PageRenderTime 106ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/libs/worker-css.js

https://github.com/creesch/reddit-moderator-toolbox
JavaScript | 8376 lines | 7922 code | 454 blank | 0 comment | 607 complexity | 170bcb7b1de6526e8487aeeb15a4766a MD5 | raw file
Possible License(s): Apache-2.0
  1. "no use strict";
  2. ;(function(window) {
  3. if (typeof window.window != "undefined" && window.document) {
  4. return;
  5. }
  6. window.console = function() {
  7. var msgs = Array.prototype.slice.call(arguments, 0);
  8. postMessage({type: "log", data: msgs});
  9. };
  10. window.console.error =
  11. window.console.warn =
  12. window.console.log =
  13. window.console.trace = window.console;
  14. window.window = window;
  15. window.ace = window;
  16. window.onerror = function(message, file, line, col, err) {
  17. console.error("Worker " + (err ? err.stack : message));
  18. };
  19. window.normalizeModule = function(parentId, moduleName) {
  20. if (moduleName.indexOf("!") !== -1) {
  21. var chunks = moduleName.split("!");
  22. return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]);
  23. }
  24. if (moduleName.charAt(0) == ".") {
  25. var base = parentId.split("/").slice(0, -1).join("/");
  26. moduleName = (base ? base + "/" : "") + moduleName;
  27. while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
  28. var previous = moduleName;
  29. moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
  30. }
  31. }
  32. return moduleName;
  33. };
  34. window.require = function(parentId, id) {
  35. if (!id) {
  36. id = parentId;
  37. parentId = null;
  38. }
  39. if (!id.charAt)
  40. throw new Error("worker.js require() accepts only (parentId, id) as arguments");
  41. id = window.normalizeModule(parentId, id);
  42. var module = window.require.modules[id];
  43. if (module) {
  44. if (!module.initialized) {
  45. module.initialized = true;
  46. module.exports = module.factory().exports;
  47. }
  48. return module.exports;
  49. }
  50. var chunks = id.split("/");
  51. if (!window.require.tlns)
  52. return console.log("unable to load " + id);
  53. chunks[0] = window.require.tlns[chunks[0]] || chunks[0];
  54. var path = chunks.join("/") + ".js";
  55. window.require.id = id;
  56. importScripts(path);
  57. return window.require(parentId, id);
  58. };
  59. window.require.modules = {};
  60. window.require.tlns = {};
  61. window.define = function(id, deps, factory) {
  62. if (arguments.length == 2) {
  63. factory = deps;
  64. if (typeof id != "string") {
  65. deps = id;
  66. id = window.require.id;
  67. }
  68. } else if (arguments.length == 1) {
  69. factory = id;
  70. deps = [];
  71. id = window.require.id;
  72. }
  73. if (!deps.length)
  74. deps = ['require', 'exports', 'module'];
  75. if (id.indexOf("text!") === 0)
  76. return;
  77. var req = function(childId) {
  78. return window.require(id, childId);
  79. };
  80. window.require.modules[id] = {
  81. exports: {},
  82. factory: function() {
  83. var module = this;
  84. var returnExports = factory.apply(this, deps.map(function(dep) {
  85. switch(dep) {
  86. case 'require': return req;
  87. case 'exports': return module.exports;
  88. case 'module': return module;
  89. default: return req(dep);
  90. }
  91. }));
  92. if (returnExports)
  93. module.exports = returnExports;
  94. return module;
  95. }
  96. };
  97. };
  98. window.define.amd = {};
  99. window.initBaseUrls = function initBaseUrls(topLevelNamespaces) {
  100. require.tlns = topLevelNamespaces;
  101. };
  102. window.initSender = function initSender() {
  103. var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter;
  104. var oop = window.require("ace/lib/oop");
  105. var Sender = function() {};
  106. (function() {
  107. oop.implement(this, EventEmitter);
  108. this.callback = function(data, callbackId) {
  109. postMessage({
  110. type: "call",
  111. id: callbackId,
  112. data: data
  113. });
  114. };
  115. this.emit = function(name, data) {
  116. postMessage({
  117. type: "event",
  118. name: name,
  119. data: data
  120. });
  121. };
  122. }).call(Sender.prototype);
  123. return new Sender();
  124. };
  125. var main = window.main = null;
  126. var sender = window.sender = null;
  127. window.onmessage = function(e) {
  128. var msg = e.data;
  129. if (msg.command) {
  130. if (main[msg.command])
  131. main[msg.command].apply(main, msg.args);
  132. else
  133. throw new Error("Unknown command:" + msg.command);
  134. }
  135. else if (msg.init) {
  136. initBaseUrls(msg.tlns);
  137. require("ace/lib/es5-shim");
  138. sender = window.sender = initSender();
  139. var clazz = require(msg.module)[msg.classname];
  140. main = window.main = new clazz(sender);
  141. }
  142. else if (msg.event && sender) {
  143. sender._signal(msg.event, msg.data);
  144. }
  145. };
  146. })(this);
  147. ace.define('ace/mode/css_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/worker/mirror', 'ace/mode/css/csslint'], function(require, exports, module) {
  148. var oop = require("../lib/oop");
  149. var lang = require("../lib/lang");
  150. var Mirror = require("../worker/mirror").Mirror;
  151. var CSSLint = require("./css/csslint").CSSLint;
  152. var Worker = exports.Worker = function(sender) {
  153. Mirror.call(this, sender);
  154. this.setTimeout(400);
  155. this.ruleset = null;
  156. this.setDisabledRules("ids");
  157. this.setInfoRules("adjoining-classes|qualified-headings|zero-units|gradients|import|outline-none");
  158. };
  159. oop.inherits(Worker, Mirror);
  160. (function() {
  161. this.setInfoRules = function(ruleNames) {
  162. if (typeof ruleNames == "string")
  163. ruleNames = ruleNames.split("|");
  164. this.infoRules = lang.arrayToMap(ruleNames);
  165. this.doc.getValue() && this.deferredUpdate.schedule(100);
  166. };
  167. this.setDisabledRules = function(ruleNames) {
  168. if (!ruleNames) {
  169. this.ruleset = null;
  170. } else {
  171. if (typeof ruleNames == "string")
  172. ruleNames = ruleNames.split("|");
  173. var all = {};
  174. CSSLint.getRules().forEach(function(x){
  175. all[x.id] = true;
  176. });
  177. ruleNames.forEach(function(x) {
  178. delete all[x];
  179. });
  180. this.ruleset = all;
  181. }
  182. this.doc.getValue() && this.deferredUpdate.schedule(100);
  183. };
  184. this.onUpdate = function() {
  185. var value = this.doc.getValue();
  186. if (!value)
  187. return this.sender.emit("csslint", []);
  188. var infoRules = this.infoRules;
  189. var result = CSSLint.verify(value, this.ruleset);
  190. this.sender.emit("csslint", result.messages.map(function(msg) {
  191. return {
  192. row: msg.line - 1,
  193. column: msg.col - 1,
  194. text: msg.message,
  195. type: infoRules[msg.rule.id] ? "info" : msg.type,
  196. rule: msg.rule.name
  197. }
  198. }));
  199. };
  200. }).call(Worker.prototype);
  201. });
  202. ace.define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) {
  203. exports.inherits = function(ctor, superCtor) {
  204. ctor.super_ = superCtor;
  205. ctor.prototype = Object.create(superCtor.prototype, {
  206. constructor: {
  207. value: ctor,
  208. enumerable: false,
  209. writable: true,
  210. configurable: true
  211. }
  212. });
  213. };
  214. exports.mixin = function(obj, mixin) {
  215. for (var key in mixin) {
  216. obj[key] = mixin[key];
  217. }
  218. return obj;
  219. };
  220. exports.implement = function(proto, mixin) {
  221. exports.mixin(proto, mixin);
  222. };
  223. });
  224. ace.define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) {
  225. exports.last = function(a) {
  226. return a[a.length - 1];
  227. };
  228. exports.stringReverse = function(string) {
  229. return string.split("").reverse().join("");
  230. };
  231. exports.stringRepeat = function (string, count) {
  232. var result = '';
  233. while (count > 0) {
  234. if (count & 1)
  235. result += string;
  236. if (count >>= 1)
  237. string += string;
  238. }
  239. return result;
  240. };
  241. var trimBeginRegexp = /^\s\s*/;
  242. var trimEndRegexp = /\s\s*$/;
  243. exports.stringTrimLeft = function (string) {
  244. return string.replace(trimBeginRegexp, '');
  245. };
  246. exports.stringTrimRight = function (string) {
  247. return string.replace(trimEndRegexp, '');
  248. };
  249. exports.copyObject = function(obj) {
  250. var copy = {};
  251. for (var key in obj) {
  252. copy[key] = obj[key];
  253. }
  254. return copy;
  255. };
  256. exports.copyArray = function(array){
  257. var copy = [];
  258. for (var i=0, l=array.length; i<l; i++) {
  259. if (array[i] && typeof array[i] == "object")
  260. copy[i] = this.copyObject( array[i] );
  261. else
  262. copy[i] = array[i];
  263. }
  264. return copy;
  265. };
  266. exports.deepCopy = function (obj) {
  267. if (typeof obj !== "object" || !obj)
  268. return obj;
  269. var cons = obj.constructor;
  270. if (cons === RegExp)
  271. return obj;
  272. var copy = cons();
  273. for (var key in obj) {
  274. if (typeof obj[key] === "object") {
  275. copy[key] = exports.deepCopy(obj[key]);
  276. } else {
  277. copy[key] = obj[key];
  278. }
  279. }
  280. return copy;
  281. };
  282. exports.arrayToMap = function(arr) {
  283. var map = {};
  284. for (var i=0; i<arr.length; i++) {
  285. map[arr[i]] = 1;
  286. }
  287. return map;
  288. };
  289. exports.createMap = function(props) {
  290. var map = Object.create(null);
  291. for (var i in props) {
  292. map[i] = props[i];
  293. }
  294. return map;
  295. };
  296. exports.arrayRemove = function(array, value) {
  297. for (var i = 0; i <= array.length; i++) {
  298. if (value === array[i]) {
  299. array.splice(i, 1);
  300. }
  301. }
  302. };
  303. exports.escapeRegExp = function(str) {
  304. return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
  305. };
  306. exports.escapeHTML = function(str) {
  307. return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");
  308. };
  309. exports.getMatchOffsets = function(string, regExp) {
  310. var matches = [];
  311. string.replace(regExp, function(str) {
  312. matches.push({
  313. offset: arguments[arguments.length-2],
  314. length: str.length
  315. });
  316. });
  317. return matches;
  318. };
  319. exports.deferredCall = function(fcn) {
  320. var timer = null;
  321. var callback = function() {
  322. timer = null;
  323. fcn();
  324. };
  325. var deferred = function(timeout) {
  326. deferred.cancel();
  327. timer = setTimeout(callback, timeout || 0);
  328. return deferred;
  329. };
  330. deferred.schedule = deferred;
  331. deferred.call = function() {
  332. this.cancel();
  333. fcn();
  334. return deferred;
  335. };
  336. deferred.cancel = function() {
  337. clearTimeout(timer);
  338. timer = null;
  339. return deferred;
  340. };
  341. deferred.isPending = function() {
  342. return timer;
  343. };
  344. return deferred;
  345. };
  346. exports.delayedCall = function(fcn, defaultTimeout) {
  347. var timer = null;
  348. var callback = function() {
  349. timer = null;
  350. fcn();
  351. };
  352. var _self = function(timeout) {
  353. if (timer == null)
  354. timer = setTimeout(callback, timeout || defaultTimeout);
  355. };
  356. _self.delay = function(timeout) {
  357. timer && clearTimeout(timer);
  358. timer = setTimeout(callback, timeout || defaultTimeout);
  359. };
  360. _self.schedule = _self;
  361. _self.call = function() {
  362. this.cancel();
  363. fcn();
  364. };
  365. _self.cancel = function() {
  366. timer && clearTimeout(timer);
  367. timer = null;
  368. };
  369. _self.isPending = function() {
  370. return timer;
  371. };
  372. return _self;
  373. };
  374. });
  375. ace.define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) {
  376. function Empty() {}
  377. if (!Function.prototype.bind) {
  378. Function.prototype.bind = function bind(that) { // .length is 1
  379. var target = this;
  380. if (typeof target != "function") {
  381. throw new TypeError("Function.prototype.bind called on incompatible " + target);
  382. }
  383. var args = slice.call(arguments, 1); // for normal call
  384. var bound = function () {
  385. if (this instanceof bound) {
  386. var result = target.apply(
  387. this,
  388. args.concat(slice.call(arguments))
  389. );
  390. if (Object(result) === result) {
  391. return result;
  392. }
  393. return this;
  394. } else {
  395. return target.apply(
  396. that,
  397. args.concat(slice.call(arguments))
  398. );
  399. }
  400. };
  401. if(target.prototype) {
  402. Empty.prototype = target.prototype;
  403. bound.prototype = new Empty();
  404. Empty.prototype = null;
  405. }
  406. return bound;
  407. };
  408. }
  409. var call = Function.prototype.call;
  410. var prototypeOfArray = Array.prototype;
  411. var prototypeOfObject = Object.prototype;
  412. var slice = prototypeOfArray.slice;
  413. var _toString = call.bind(prototypeOfObject.toString);
  414. var owns = call.bind(prototypeOfObject.hasOwnProperty);
  415. var defineGetter;
  416. var defineSetter;
  417. var lookupGetter;
  418. var lookupSetter;
  419. var supportsAccessors;
  420. if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
  421. defineGetter = call.bind(prototypeOfObject.__defineGetter__);
  422. defineSetter = call.bind(prototypeOfObject.__defineSetter__);
  423. lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
  424. lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
  425. }
  426. if ([1,2].splice(0).length != 2) {
  427. if(function() { // test IE < 9 to splice bug - see issue #138
  428. function makeArray(l) {
  429. var a = new Array(l+2);
  430. a[0] = a[1] = 0;
  431. return a;
  432. }
  433. var array = [], lengthBefore;
  434. array.splice.apply(array, makeArray(20));
  435. array.splice.apply(array, makeArray(26));
  436. lengthBefore = array.length; //46
  437. array.splice(5, 0, "XXX"); // add one element
  438. lengthBefore + 1 == array.length
  439. if (lengthBefore + 1 == array.length) {
  440. return true;// has right splice implementation without bugs
  441. }
  442. }()) {//IE 6/7
  443. var array_splice = Array.prototype.splice;
  444. Array.prototype.splice = function(start, deleteCount) {
  445. if (!arguments.length) {
  446. return [];
  447. } else {
  448. return array_splice.apply(this, [
  449. start === void 0 ? 0 : start,
  450. deleteCount === void 0 ? (this.length - start) : deleteCount
  451. ].concat(slice.call(arguments, 2)))
  452. }
  453. };
  454. } else {//IE8
  455. Array.prototype.splice = function(pos, removeCount){
  456. var length = this.length;
  457. if (pos > 0) {
  458. if (pos > length)
  459. pos = length;
  460. } else if (pos == void 0) {
  461. pos = 0;
  462. } else if (pos < 0) {
  463. pos = Math.max(length + pos, 0);
  464. }
  465. if (!(pos+removeCount < length))
  466. removeCount = length - pos;
  467. var removed = this.slice(pos, pos+removeCount);
  468. var insert = slice.call(arguments, 2);
  469. var add = insert.length;
  470. if (pos === length) {
  471. if (add) {
  472. this.push.apply(this, insert);
  473. }
  474. } else {
  475. var remove = Math.min(removeCount, length - pos);
  476. var tailOldPos = pos + remove;
  477. var tailNewPos = tailOldPos + add - remove;
  478. var tailCount = length - tailOldPos;
  479. var lengthAfterRemove = length - remove;
  480. if (tailNewPos < tailOldPos) { // case A
  481. for (var i = 0; i < tailCount; ++i) {
  482. this[tailNewPos+i] = this[tailOldPos+i];
  483. }
  484. } else if (tailNewPos > tailOldPos) { // case B
  485. for (i = tailCount; i--; ) {
  486. this[tailNewPos+i] = this[tailOldPos+i];
  487. }
  488. } // else, add == remove (nothing to do)
  489. if (add && pos === lengthAfterRemove) {
  490. this.length = lengthAfterRemove; // truncate array
  491. this.push.apply(this, insert);
  492. } else {
  493. this.length = lengthAfterRemove + add; // reserves space
  494. for (i = 0; i < add; ++i) {
  495. this[pos+i] = insert[i];
  496. }
  497. }
  498. }
  499. return removed;
  500. };
  501. }
  502. }
  503. if (!Array.isArray) {
  504. Array.isArray = function isArray(obj) {
  505. return _toString(obj) == "[object Array]";
  506. };
  507. }
  508. var boxedString = Object("a"),
  509. splitString = boxedString[0] != "a" || !(0 in boxedString);
  510. if (!Array.prototype.forEach) {
  511. Array.prototype.forEach = function forEach(fun /*, thisp*/) {
  512. var object = toObject(this),
  513. self = splitString && _toString(this) == "[object String]" ?
  514. this.split("") :
  515. object,
  516. thisp = arguments[1],
  517. i = -1,
  518. length = self.length >>> 0;
  519. if (_toString(fun) != "[object Function]") {
  520. throw new TypeError(); // TODO message
  521. }
  522. while (++i < length) {
  523. if (i in self) {
  524. fun.call(thisp, self[i], i, object);
  525. }
  526. }
  527. };
  528. }
  529. if (!Array.prototype.map) {
  530. Array.prototype.map = function map(fun /*, thisp*/) {
  531. var object = toObject(this),
  532. self = splitString && _toString(this) == "[object String]" ?
  533. this.split("") :
  534. object,
  535. length = self.length >>> 0,
  536. result = Array(length),
  537. thisp = arguments[1];
  538. if (_toString(fun) != "[object Function]") {
  539. throw new TypeError(fun + " is not a function");
  540. }
  541. for (var i = 0; i < length; i++) {
  542. if (i in self)
  543. result[i] = fun.call(thisp, self[i], i, object);
  544. }
  545. return result;
  546. };
  547. }
  548. if (!Array.prototype.filter) {
  549. Array.prototype.filter = function filter(fun /*, thisp */) {
  550. var object = toObject(this),
  551. self = splitString && _toString(this) == "[object String]" ?
  552. this.split("") :
  553. object,
  554. length = self.length >>> 0,
  555. result = [],
  556. value,
  557. thisp = arguments[1];
  558. if (_toString(fun) != "[object Function]") {
  559. throw new TypeError(fun + " is not a function");
  560. }
  561. for (var i = 0; i < length; i++) {
  562. if (i in self) {
  563. value = self[i];
  564. if (fun.call(thisp, value, i, object)) {
  565. result.push(value);
  566. }
  567. }
  568. }
  569. return result;
  570. };
  571. }
  572. if (!Array.prototype.every) {
  573. Array.prototype.every = function every(fun /*, thisp */) {
  574. var object = toObject(this),
  575. self = splitString && _toString(this) == "[object String]" ?
  576. this.split("") :
  577. object,
  578. length = self.length >>> 0,
  579. thisp = arguments[1];
  580. if (_toString(fun) != "[object Function]") {
  581. throw new TypeError(fun + " is not a function");
  582. }
  583. for (var i = 0; i < length; i++) {
  584. if (i in self && !fun.call(thisp, self[i], i, object)) {
  585. return false;
  586. }
  587. }
  588. return true;
  589. };
  590. }
  591. if (!Array.prototype.some) {
  592. Array.prototype.some = function some(fun /*, thisp */) {
  593. var object = toObject(this),
  594. self = splitString && _toString(this) == "[object String]" ?
  595. this.split("") :
  596. object,
  597. length = self.length >>> 0,
  598. thisp = arguments[1];
  599. if (_toString(fun) != "[object Function]") {
  600. throw new TypeError(fun + " is not a function");
  601. }
  602. for (var i = 0; i < length; i++) {
  603. if (i in self && fun.call(thisp, self[i], i, object)) {
  604. return true;
  605. }
  606. }
  607. return false;
  608. };
  609. }
  610. if (!Array.prototype.reduce) {
  611. Array.prototype.reduce = function reduce(fun /*, initial*/) {
  612. var object = toObject(this),
  613. self = splitString && _toString(this) == "[object String]" ?
  614. this.split("") :
  615. object,
  616. length = self.length >>> 0;
  617. if (_toString(fun) != "[object Function]") {
  618. throw new TypeError(fun + " is not a function");
  619. }
  620. if (!length && arguments.length == 1) {
  621. throw new TypeError("reduce of empty array with no initial value");
  622. }
  623. var i = 0;
  624. var result;
  625. if (arguments.length >= 2) {
  626. result = arguments[1];
  627. } else {
  628. do {
  629. if (i in self) {
  630. result = self[i++];
  631. break;
  632. }
  633. if (++i >= length) {
  634. throw new TypeError("reduce of empty array with no initial value");
  635. }
  636. } while (true);
  637. }
  638. for (; i < length; i++) {
  639. if (i in self) {
  640. result = fun.call(void 0, result, self[i], i, object);
  641. }
  642. }
  643. return result;
  644. };
  645. }
  646. if (!Array.prototype.reduceRight) {
  647. Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
  648. var object = toObject(this),
  649. self = splitString && _toString(this) == "[object String]" ?
  650. this.split("") :
  651. object,
  652. length = self.length >>> 0;
  653. if (_toString(fun) != "[object Function]") {
  654. throw new TypeError(fun + " is not a function");
  655. }
  656. if (!length && arguments.length == 1) {
  657. throw new TypeError("reduceRight of empty array with no initial value");
  658. }
  659. var result, i = length - 1;
  660. if (arguments.length >= 2) {
  661. result = arguments[1];
  662. } else {
  663. do {
  664. if (i in self) {
  665. result = self[i--];
  666. break;
  667. }
  668. if (--i < 0) {
  669. throw new TypeError("reduceRight of empty array with no initial value");
  670. }
  671. } while (true);
  672. }
  673. do {
  674. if (i in this) {
  675. result = fun.call(void 0, result, self[i], i, object);
  676. }
  677. } while (i--);
  678. return result;
  679. };
  680. }
  681. if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
  682. Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
  683. var self = splitString && _toString(this) == "[object String]" ?
  684. this.split("") :
  685. toObject(this),
  686. length = self.length >>> 0;
  687. if (!length) {
  688. return -1;
  689. }
  690. var i = 0;
  691. if (arguments.length > 1) {
  692. i = toInteger(arguments[1]);
  693. }
  694. i = i >= 0 ? i : Math.max(0, length + i);
  695. for (; i < length; i++) {
  696. if (i in self && self[i] === sought) {
  697. return i;
  698. }
  699. }
  700. return -1;
  701. };
  702. }
  703. if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
  704. Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
  705. var self = splitString && _toString(this) == "[object String]" ?
  706. this.split("") :
  707. toObject(this),
  708. length = self.length >>> 0;
  709. if (!length) {
  710. return -1;
  711. }
  712. var i = length - 1;
  713. if (arguments.length > 1) {
  714. i = Math.min(i, toInteger(arguments[1]));
  715. }
  716. i = i >= 0 ? i : length - Math.abs(i);
  717. for (; i >= 0; i--) {
  718. if (i in self && sought === self[i]) {
  719. return i;
  720. }
  721. }
  722. return -1;
  723. };
  724. }
  725. if (!Object.getPrototypeOf) {
  726. Object.getPrototypeOf = function getPrototypeOf(object) {
  727. return object.__proto__ || (
  728. object.constructor ?
  729. object.constructor.prototype :
  730. prototypeOfObject
  731. );
  732. };
  733. }
  734. if (!Object.getOwnPropertyDescriptor) {
  735. var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
  736. "non-object: ";
  737. Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
  738. if ((typeof object != "object" && typeof object != "function") || object === null)
  739. throw new TypeError(ERR_NON_OBJECT + object);
  740. if (!owns(object, property))
  741. return;
  742. var descriptor, getter, setter;
  743. descriptor = { enumerable: true, configurable: true };
  744. if (supportsAccessors) {
  745. var prototype = object.__proto__;
  746. object.__proto__ = prototypeOfObject;
  747. var getter = lookupGetter(object, property);
  748. var setter = lookupSetter(object, property);
  749. object.__proto__ = prototype;
  750. if (getter || setter) {
  751. if (getter) descriptor.get = getter;
  752. if (setter) descriptor.set = setter;
  753. return descriptor;
  754. }
  755. }
  756. descriptor.value = object[property];
  757. return descriptor;
  758. };
  759. }
  760. if (!Object.getOwnPropertyNames) {
  761. Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
  762. return Object.keys(object);
  763. };
  764. }
  765. if (!Object.create) {
  766. var createEmpty;
  767. if (Object.prototype.__proto__ === null) {
  768. createEmpty = function () {
  769. return { "__proto__": null };
  770. };
  771. } else {
  772. createEmpty = function () {
  773. var empty = {};
  774. for (var i in empty)
  775. empty[i] = null;
  776. empty.constructor =
  777. empty.hasOwnProperty =
  778. empty.propertyIsEnumerable =
  779. empty.isPrototypeOf =
  780. empty.toLocaleString =
  781. empty.toString =
  782. empty.valueOf =
  783. empty.__proto__ = null;
  784. return empty;
  785. }
  786. }
  787. Object.create = function create(prototype, properties) {
  788. var object;
  789. if (prototype === null) {
  790. object = createEmpty();
  791. } else {
  792. if (typeof prototype != "object")
  793. throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
  794. var Type = function () {};
  795. Type.prototype = prototype;
  796. object = new Type();
  797. object.__proto__ = prototype;
  798. }
  799. if (properties !== void 0)
  800. Object.defineProperties(object, properties);
  801. return object;
  802. };
  803. }
  804. function doesDefinePropertyWork(object) {
  805. try {
  806. Object.defineProperty(object, "sentinel", {});
  807. return "sentinel" in object;
  808. } catch (exception) {
  809. }
  810. }
  811. if (Object.defineProperty) {
  812. var definePropertyWorksOnObject = doesDefinePropertyWork({});
  813. var definePropertyWorksOnDom = typeof document == "undefined" ||
  814. doesDefinePropertyWork(document.createElement("div"));
  815. if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
  816. var definePropertyFallback = Object.defineProperty;
  817. }
  818. }
  819. if (!Object.defineProperty || definePropertyFallback) {
  820. var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
  821. var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
  822. var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
  823. "on this javascript engine";
  824. Object.defineProperty = function defineProperty(object, property, descriptor) {
  825. if ((typeof object != "object" && typeof object != "function") || object === null)
  826. throw new TypeError(ERR_NON_OBJECT_TARGET + object);
  827. if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
  828. throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
  829. if (definePropertyFallback) {
  830. try {
  831. return definePropertyFallback.call(Object, object, property, descriptor);
  832. } catch (exception) {
  833. }
  834. }
  835. if (owns(descriptor, "value")) {
  836. if (supportsAccessors && (lookupGetter(object, property) ||
  837. lookupSetter(object, property)))
  838. {
  839. var prototype = object.__proto__;
  840. object.__proto__ = prototypeOfObject;
  841. delete object[property];
  842. object[property] = descriptor.value;
  843. object.__proto__ = prototype;
  844. } else {
  845. object[property] = descriptor.value;
  846. }
  847. } else {
  848. if (!supportsAccessors)
  849. throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
  850. if (owns(descriptor, "get"))
  851. defineGetter(object, property, descriptor.get);
  852. if (owns(descriptor, "set"))
  853. defineSetter(object, property, descriptor.set);
  854. }
  855. return object;
  856. };
  857. }
  858. if (!Object.defineProperties) {
  859. Object.defineProperties = function defineProperties(object, properties) {
  860. for (var property in properties) {
  861. if (owns(properties, property))
  862. Object.defineProperty(object, property, properties[property]);
  863. }
  864. return object;
  865. };
  866. }
  867. if (!Object.seal) {
  868. Object.seal = function seal(object) {
  869. return object;
  870. };
  871. }
  872. if (!Object.freeze) {
  873. Object.freeze = function freeze(object) {
  874. return object;
  875. };
  876. }
  877. try {
  878. Object.freeze(function () {});
  879. } catch (exception) {
  880. Object.freeze = (function freeze(freezeObject) {
  881. return function freeze(object) {
  882. if (typeof object == "function") {
  883. return object;
  884. } else {
  885. return freezeObject(object);
  886. }
  887. };
  888. })(Object.freeze);
  889. }
  890. if (!Object.preventExtensions) {
  891. Object.preventExtensions = function preventExtensions(object) {
  892. return object;
  893. };
  894. }
  895. if (!Object.isSealed) {
  896. Object.isSealed = function isSealed(object) {
  897. return false;
  898. };
  899. }
  900. if (!Object.isFrozen) {
  901. Object.isFrozen = function isFrozen(object) {
  902. return false;
  903. };
  904. }
  905. if (!Object.isExtensible) {
  906. Object.isExtensible = function isExtensible(object) {
  907. if (Object(object) === object) {
  908. throw new TypeError(); // TODO message
  909. }
  910. var name = '';
  911. while (owns(object, name)) {
  912. name += '?';
  913. }
  914. object[name] = true;
  915. var returnValue = owns(object, name);
  916. delete object[name];
  917. return returnValue;
  918. };
  919. }
  920. if (!Object.keys) {
  921. var hasDontEnumBug = true,
  922. dontEnums = [
  923. "toString",
  924. "toLocaleString",
  925. "valueOf",
  926. "hasOwnProperty",
  927. "isPrototypeOf",
  928. "propertyIsEnumerable",
  929. "constructor"
  930. ],
  931. dontEnumsLength = dontEnums.length;
  932. for (var key in {"toString": null}) {
  933. hasDontEnumBug = false;
  934. }
  935. Object.keys = function keys(object) {
  936. if (
  937. (typeof object != "object" && typeof object != "function") ||
  938. object === null
  939. ) {
  940. throw new TypeError("Object.keys called on a non-object");
  941. }
  942. var keys = [];
  943. for (var name in object) {
  944. if (owns(object, name)) {
  945. keys.push(name);
  946. }
  947. }
  948. if (hasDontEnumBug) {
  949. for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
  950. var dontEnum = dontEnums[i];
  951. if (owns(object, dontEnum)) {
  952. keys.push(dontEnum);
  953. }
  954. }
  955. }
  956. return keys;
  957. };
  958. }
  959. if (!Date.now) {
  960. Date.now = function now() {
  961. return new Date().getTime();
  962. };
  963. }
  964. var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
  965. "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
  966. "\u2029\uFEFF";
  967. if (!String.prototype.trim || ws.trim()) {
  968. ws = "[" + ws + "]";
  969. var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
  970. trimEndRegexp = new RegExp(ws + ws + "*$");
  971. String.prototype.trim = function trim() {
  972. return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
  973. };
  974. }
  975. function toInteger(n) {
  976. n = +n;
  977. if (n !== n) { // isNaN
  978. n = 0;
  979. } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
  980. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  981. }
  982. return n;
  983. }
  984. function isPrimitive(input) {
  985. var type = typeof input;
  986. return (
  987. input === null ||
  988. type === "undefined" ||
  989. type === "boolean" ||
  990. type === "number" ||
  991. type === "string"
  992. );
  993. }
  994. function toPrimitive(input) {
  995. var val, valueOf, toString;
  996. if (isPrimitive(input)) {
  997. return input;
  998. }
  999. valueOf = input.valueOf;
  1000. if (typeof valueOf === "function") {
  1001. val = valueOf.call(input);
  1002. if (isPrimitive(val)) {
  1003. return val;
  1004. }
  1005. }
  1006. toString = input.toString;
  1007. if (typeof toString === "function") {
  1008. val = toString.call(input);
  1009. if (isPrimitive(val)) {
  1010. return val;
  1011. }
  1012. }
  1013. throw new TypeError();
  1014. }
  1015. var toObject = function (o) {
  1016. if (o == null) { // this matches both null and undefined
  1017. throw new TypeError("can't convert "+o+" to object");
  1018. }
  1019. return Object(o);
  1020. };
  1021. });
  1022. ace.define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) {
  1023. var oop = require("./lib/oop");
  1024. var EventEmitter = require("./lib/event_emitter").EventEmitter;
  1025. var Range = require("./range").Range;
  1026. var Anchor = require("./anchor").Anchor;
  1027. var Document = function(text) {
  1028. this.$lines = [];
  1029. if (text.length === 0) {
  1030. this.$lines = [""];
  1031. } else if (Array.isArray(text)) {
  1032. this._insertLines(0, text);
  1033. } else {
  1034. this.insert({row: 0, column:0}, text);
  1035. }
  1036. };
  1037. (function() {
  1038. oop.implement(this, EventEmitter);
  1039. this.setValue = function(text) {
  1040. var len = this.getLength();
  1041. this.remove(new Range(0, 0, len, this.getLine(len-1).length));
  1042. this.insert({row: 0, column:0}, text);
  1043. };
  1044. this.getValue = function() {
  1045. return this.getAllLines().join(this.getNewLineCharacter());
  1046. };
  1047. this.createAnchor = function(row, column) {
  1048. return new Anchor(this, row, column);
  1049. };
  1050. if ("aaa".split(/a/).length === 0)
  1051. this.$split = function(text) {
  1052. return text.replace(/\r\n|\r/g, "\n").split("\n");
  1053. };
  1054. else
  1055. this.$split = function(text) {
  1056. return text.split(/\r\n|\r|\n/);
  1057. };
  1058. this.$detectNewLine = function(text) {
  1059. var match = text.match(/^.*?(\r\n|\r|\n)/m);
  1060. this.$autoNewLine = match ? match[1] : "\n";
  1061. this._signal("changeNewLineMode");
  1062. };
  1063. this.getNewLineCharacter = function() {
  1064. switch (this.$newLineMode) {
  1065. case "windows":
  1066. return "\r\n";
  1067. case "unix":
  1068. return "\n";
  1069. default:
  1070. return this.$autoNewLine || "\n";
  1071. }
  1072. };
  1073. this.$autoNewLine = "";
  1074. this.$newLineMode = "auto";
  1075. this.setNewLineMode = function(newLineMode) {
  1076. if (this.$newLineMode === newLineMode)
  1077. return;
  1078. this.$newLineMode = newLineMode;
  1079. this._signal("changeNewLineMode");
  1080. };
  1081. this.getNewLineMode = function() {
  1082. return this.$newLineMode;
  1083. };
  1084. this.isNewLine = function(text) {
  1085. return (text == "\r\n" || text == "\r" || text == "\n");
  1086. };
  1087. this.getLine = function(row) {
  1088. return this.$lines[row] || "";
  1089. };
  1090. this.getLines = function(firstRow, lastRow) {
  1091. return this.$lines.slice(firstRow, lastRow + 1);
  1092. };
  1093. this.getAllLines = function() {
  1094. return this.getLines(0, this.getLength());
  1095. };
  1096. this.getLength = function() {
  1097. return this.$lines.length;
  1098. };
  1099. this.getTextRange = function(range) {
  1100. if (range.start.row == range.end.row) {
  1101. return this.getLine(range.start.row)
  1102. .substring(range.start.column, range.end.column);
  1103. }
  1104. var lines = this.getLines(range.start.row, range.end.row);
  1105. lines[0] = (lines[0] || "").substring(range.start.column);
  1106. var l = lines.length - 1;
  1107. if (range.end.row - range.start.row == l)
  1108. lines[l] = lines[l].substring(0, range.end.column);
  1109. return lines.join(this.getNewLineCharacter());
  1110. };
  1111. this.$clipPosition = function(position) {
  1112. var length = this.getLength();
  1113. if (position.row >= length) {
  1114. position.row = Math.max(0, length - 1);
  1115. position.column = this.getLine(length-1).length;
  1116. } else if (position.row < 0)
  1117. position.row = 0;
  1118. return position;
  1119. };
  1120. this.insert = function(position, text) {
  1121. if (!text || text.length === 0)
  1122. return position;
  1123. position = this.$clipPosition(position);
  1124. if (this.getLength() <= 1)
  1125. this.$detectNewLine(text);
  1126. var lines = this.$split(text);
  1127. var firstLine = lines.splice(0, 1)[0];
  1128. var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
  1129. position = this.insertInLine(position, firstLine);
  1130. if (lastLine !== null) {
  1131. position = this.insertNewLine(position); // terminate first line
  1132. position = this._insertLines(position.row, lines);
  1133. position = this.insertInLine(position, lastLine || "");
  1134. }
  1135. return position;
  1136. };
  1137. this.insertLines = function(row, lines) {
  1138. if (row >= this.getLength())
  1139. return this.insert({row: row, column: 0}, "\n" + lines.join("\n"));
  1140. return this._insertLines(Math.max(row, 0), lines);
  1141. };
  1142. this._insertLines = function(row, lines) {
  1143. if (lines.length == 0)
  1144. return {row: row, column: 0};
  1145. while (lines.length > 0xF000) {
  1146. var end = this._insertLines(row, lines.slice(0, 0xF000));
  1147. lines = lines.slice(0xF000);
  1148. row = end.row;
  1149. }
  1150. var args = [row, 0];
  1151. args.push.apply(args, lines);
  1152. this.$lines.splice.apply(this.$lines, args);
  1153. var range = new Range(row, 0, row + lines.length, 0);
  1154. var delta = {
  1155. action: "insertLines",
  1156. range: range,
  1157. lines: lines
  1158. };
  1159. this._signal("change", { data: delta });
  1160. return range.end;
  1161. };
  1162. this.insertNewLine = function(position) {
  1163. position = this.$clipPosition(position);
  1164. var line = this.$lines[position.row] || "";
  1165. this.$lines[position.row] = line.substring(0, position.column);
  1166. this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
  1167. var end = {
  1168. row : position.row + 1,
  1169. column : 0
  1170. };
  1171. var delta = {
  1172. action: "insertText",
  1173. range: Range.fromPoints(position, end),
  1174. text: this.getNewLineCharacter()
  1175. };
  1176. this._signal("change", { data: delta });
  1177. return end;
  1178. };
  1179. this.insertInLine = function(position, text) {
  1180. if (text.length == 0)
  1181. return position;
  1182. var line = this.$lines[position.row] || "";
  1183. this.$lines[position.row] = line.substring(0, position.column) + text
  1184. + line.substring(position.column);
  1185. var end = {
  1186. row : position.row,
  1187. column : position.column + text.length
  1188. };
  1189. var delta = {
  1190. action: "insertText",
  1191. range: Range.fromPoints(position, end),
  1192. text: text
  1193. };
  1194. this._signal("change", { data: delta });
  1195. return end;
  1196. };
  1197. this.remove = function(range) {
  1198. if (!(range instanceof Range))
  1199. range = Range.fromPoints(range.start, range.end);
  1200. range.start = this.$clipPosition(range.start);
  1201. range.end = this.$clipPosition(range.end);
  1202. if (range.isEmpty())
  1203. return range.start;
  1204. var firstRow = range.start.row;
  1205. var lastRow = range.end.row;
  1206. if (range.isMultiLine()) {
  1207. var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
  1208. var lastFullRow = lastRow - 1;
  1209. if (range.end.column > 0)
  1210. this.removeInLine(lastRow, 0, range.end.column);
  1211. if (lastFullRow >= firstFullRow)
  1212. this._removeLines(firstFullRow, lastFullRow);
  1213. if (firstFullRow != firstRow) {
  1214. this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
  1215. this.removeNewLine(range.start.row);
  1216. }
  1217. }
  1218. else {
  1219. this.removeInLine(firstRow, range.start.column, range.end.column);
  1220. }
  1221. return range.start;
  1222. };
  1223. this.removeInLine = function(row, startColumn, endColumn) {
  1224. if (startColumn == endColumn)
  1225. return;
  1226. var range = new Range(row, startColumn, row, endColumn);
  1227. var line = this.getLine(row);
  1228. var removed = line.substring(startColumn, endColumn);
  1229. var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
  1230. this.$lines.splice(row, 1, newLine);
  1231. var delta = {
  1232. action: "removeText",
  1233. range: range,
  1234. text: removed
  1235. };
  1236. this._signal("change", { data: delta });
  1237. return range.start;
  1238. };
  1239. this.removeLines = function(firstRow, lastRow) {
  1240. if (firstRow < 0 || lastRow >= this.getLength())
  1241. return this.remove(new Range(firstRow, 0, lastRow + 1, 0));
  1242. return this._removeLines(firstRow, lastRow);
  1243. };
  1244. this._removeLines = function(firstRow, lastRow) {
  1245. var range = new Range(firstRow, 0, lastRow + 1, 0);
  1246. var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
  1247. var delta = {
  1248. action: "removeLines",
  1249. range: range,
  1250. nl: this.getNewLineCharacter(),
  1251. lines: removed
  1252. };
  1253. this._signal("change", { data: delta });
  1254. return removed;
  1255. };
  1256. this.removeNewLine = function(row) {
  1257. var firstLine = this.getLine(row);
  1258. var secondLine = this.getLine(row+1);
  1259. var range = new Range(row, firstLine.length, row+1, 0);
  1260. var line = firstLine + secondLine;
  1261. this.$lines.splice(row, 2, line);
  1262. var delta = {
  1263. action: "removeText",
  1264. range: range,
  1265. text: this.getNewLineCharacter()
  1266. };
  1267. this._signal("change", { data: delta });
  1268. };
  1269. this.replace = function(range, text) {
  1270. if (!(range instanceof Range))
  1271. range = Range.fromPoints(range.start, range.end);
  1272. if (text.length == 0 && range.isEmpty())
  1273. return range.start;
  1274. if (text == this.getTextRange(range))
  1275. return range.end;
  1276. this.remove(range);
  1277. if (text) {
  1278. var end = this.insert(range.start, text);
  1279. }
  1280. else {
  1281. end = range.start;
  1282. }
  1283. return end;
  1284. };
  1285. this.applyDeltas = function(deltas) {
  1286. for (var i=0; i<deltas.length; i++) {
  1287. var delta = deltas[i];
  1288. var range = Range.fromPoints(delta.range.start, delta.range.end);
  1289. if (delta.action == "insertLines")
  1290. this.insertLines(range.start.row, delta.lines);
  1291. else if (delta.action == "insertText")
  1292. this.insert(range.start, delta.text);
  1293. else if (delta.action == "removeLines")
  1294. this._removeLines(range.start.row, range.end.row - 1);
  1295. else if (delta.action == "removeText")
  1296. this.remove(range);
  1297. }
  1298. };
  1299. this.revertDeltas = function(deltas) {
  1300. for (var i=deltas.length-1; i>=0; i--) {
  1301. var delta = deltas[i];
  1302. var range = Range.fromPoints(delta.range.start, delta.range.end);
  1303. if (delta.action == "insertLines")
  1304. this._removeLines(range.start.row, range.end.row - 1);
  1305. else if (delta.action == "insertText")
  1306. this.remove(range);
  1307. else if (delta.action == "removeLines")
  1308. this._insertLines(range.start.row, delta.lines);
  1309. else if (delta.action == "removeText")
  1310. this.insert(range.start, delta.text);
  1311. }
  1312. };
  1313. this.indexToPosition = function(index, startRow) {
  1314. var lines = this.$lines || this.getAllLines();
  1315. var newlineLength = this.getNewLineCharacter().length;
  1316. for (var i = startRow || 0, l = lines.length; i < l; i++) {
  1317. index -= lines[i].length + newlineLength;
  1318. if (index < 0)
  1319. return {row: i, column: index + lines[i].length + newlineLength};
  1320. }
  1321. return {row: l-1, column: lines[l-1].length};
  1322. };
  1323. this.positionToIndex = function(pos, startRow) {
  1324. var lines = this.$lines || this.getAllLines();
  1325. var newlineLength = this.getNewLineCharacter().length;
  1326. var index = 0;
  1327. var row = Math.min(pos.row, lines.length);
  1328. for (var i = startRow || 0; i < row; ++i)
  1329. index += lines[i].length + newlineLength;
  1330. return index + pos.column;
  1331. };
  1332. }).call(Document.prototype);
  1333. exports.Document = Document;
  1334. });
  1335. ace.define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) {
  1336. var EventEmitter = {};
  1337. var stopPropagation = function() { this.propagationStopped = true; };
  1338. var preventDefault = function() { this.defaultPrevented = true; };
  1339. EventEmitter._emit =
  1340. EventEmitter._dispatchEvent = function(eventName, e) {
  1341. this._eventRegistry || (this._eventRegistry = {});
  1342. this._defaultHandlers || (this._defaultHandlers = {});
  1343. var listeners = this._eventRegistry[eventName] || [];
  1344. var defaultHandler = this._defaultHandlers[eventName];
  1345. if (!listeners.length && !defaultHandler)
  1346. return;
  1347. if (typeof e != "object" || !e)
  1348. e = {};
  1349. if (!e.type)
  1350. e.type = eventName;
  1351. if (!e.stopPropagation)
  1352. e.stopPropagation = stopPropagation;
  1353. if (!e.preventDefault)
  1354. e.preventDefault = preventDefault;
  1355. listeners = listeners.slice();
  1356. for (var i=0; i<listeners.length; i++) {
  1357. listeners[i](e, this);
  1358. if (e.propagationStopped)
  1359. break;
  1360. }
  1361. if (defaultHandler && !e.defaultPrevented)
  1362. return defaultHandler(e, this);
  1363. };
  1364. EventEmitter._signal = function(eventName, e) {
  1365. var listeners = (this._eventRegistry || {})[eventName];
  1366. if (!listeners)
  1367. return;
  1368. listeners = listeners.slice();
  1369. for (var i=0; i<listeners.length; i++)
  1370. listeners[i](e, this);
  1371. };
  1372. EventEmitter.once = function(eventName, callback) {
  1373. var _self = this;
  1374. callback && this.addEventListener(eventName, function newCallback() {
  1375. _self.removeEventListener(eventName, newCallback);
  1376. callback.apply(null, arguments);
  1377. });
  1378. };
  1379. EventEmitter.setDefaultHandler = function(eventName, callback) {
  1380. var handlers = this._defaultHandlers
  1381. if (!handlers)
  1382. handlers = this._defaultHandlers = {_disabled_: {}};
  1383. if (handlers[eventName]) {
  1384. var old = handlers[eventName];
  1385. var disabled = handlers._disabled_[eventName];
  1386. if (!disabled)
  1387. handlers._disabled_[eventName] = disabled = [];
  1388. disabled.push(old);
  1389. var i = disabled.indexOf(callback);
  1390. if (i != -1)
  1391. disabled.splice(i, 1);
  1392. }
  1393. handlers[eventName] = callback;
  1394. };
  1395. EventEmitter.removeDefaultHandler = function(eventName, callback) {
  1396. var handlers = this._defaultHandlers
  1397. if (!handlers)
  1398. return;
  1399. var disabled = handlers._disabled_[eventName];
  1400. if (handlers[eventName] == callback) {
  1401. var old = handlers[eventName];
  1402. if (disabled)
  1403. this.setDefaultHandler(eventName, disabled.pop());
  1404. } else if (disabled) {
  1405. var i = disabled.indexOf(callback);
  1406. if (i != -1)
  1407. disabled.splice(i, 1);
  1408. }
  1409. };
  1410. EventEmitter.on =
  1411. EventEmitter.addEventListener = function(eventName, callback, capturing) {
  1412. this._eventRegistry = this._eventRegistry || {};
  1413. var listeners = this._eventRegistry[eventName];
  1414. if (!listeners)
  1415. listeners = this._eventRegistry[eventName] = [];
  1416. if (listeners.indexOf(callback) == -1)
  1417. listeners[capturing ? "unshift" : "push"](callback);
  1418. return callback;
  1419. };
  1420. EventEmitter.off =
  1421. EventEmitter.removeListener =
  1422. EventEmitter.removeEventListener = function(eventName, callback) {
  1423. this._eventRegistry = this._eventRegistry || {};
  1424. var listeners = this._eventRegistry[eventName];
  1425. if (!listeners)
  1426. return;
  1427. var index = listeners.indexOf(callback);
  1428. if (index !== -1)
  1429. listeners.splice(index, 1);
  1430. };
  1431. EventEmitter.removeAllListeners = function(eventName) {
  1432. if (this._eventRegistry) this._eventRegistry[eventName] = [];
  1433. };
  1434. exports.EventEmitter = EventEmitter;
  1435. });
  1436. ace.define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) {
  1437. var comparePoints = function(p1, p2) {
  1438. return p1.row - p2.row || p1.column - p2.column;
  1439. };
  1440. var Range = function(startRow, startColumn, endRow, endColumn) {
  1441. this.start = {
  1442. row: startRow,
  1443. column: startColumn
  1444. };
  1445. this.end = {
  1446. row: endRow,
  1447. column: endColumn
  1448. };
  1449. };
  1450. (function() {
  1451. this.isEqual = function(range) {
  1452. return this.start.row === range.start.row &&
  1453. this.end.row === range.end.row &&
  1454. this.start.column === range.start.column &&
  1455. this.end.column === range.end.column;
  1456. };
  1457. this.toString = function() {
  1458. return ("Range: [" + this.start.row + "/" + this.start.column +
  1459. "] -> [" + this.end.row + "/" + this.end.column + "]");
  1460. };
  1461. this.contains = function(row, column) {
  1462. return this.compare(row, column) == 0;
  1463. };
  1464. this.compareRange = function(range) {
  1465. var cmp,
  1466. end = range.end,
  1467. start = range.start;
  1468. cmp = this.compare(end.row, end.column);
  1469. if (cmp == 1) {
  1470. cmp = this.compare(start.row, start.column);
  1471. if (cmp == 1) {
  1472. return 2;
  1473. } else if (cmp == 0) {
  1474. return 1;
  1475. } else {
  1476. return 0;
  1477. }
  1478. } else if (cmp == -1) {
  1479. return -2;
  1480. } else {
  1481. cmp = this.compare(start.row, start.column);
  1482. if (cmp == -1) {
  1483. return -1;
  1484. } else if (cmp == 1) {
  1485. return 42;
  1486. } else {
  1487. return 0;
  1488. }
  1489. }
  1490. };
  1491. this.comparePoint = function(p) {
  1492. return this.compare(p.row, p.column);
  1493. };
  1494. this.containsRange = function(range) {
  1495. return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
  1496. };
  1497. this.intersects = function(range) {
  1498. var cmp = this.compareRange(range);
  1499. return (cmp == -1 || cmp == 0 || cmp == 1);
  1500. };
  1501. this.isEnd = function(row, column) {
  1502. return this.end.row == row && this.end.column == column;
  1503. };
  1504. this.isStart = function(row, column) {
  1505. return this.start.row == row && this.start.column == column;
  1506. };
  1507. this.setStart = function(row, column) {
  1508. if (typeof row == "object") {
  1509. this.start.column = row.column;
  1510. this.start.row = row.row;
  1511. } else {
  1512. this.start.row = row;
  1513. this.start.column = column;
  1514. }
  1515. };
  1516. this.setEnd = function(row, column) {
  1517. if (typeof row == "object") {
  1518. this.end.column = row.column;
  1519. this.end.row = row.row;
  1520. } else {
  1521. this.end.row = row;
  1522. this.end.column = column;
  1523. }
  1524. };
  1525. this.inside = function(row, column) {
  1526. if (this.compare(row, column) == 0) {
  1527. if (this.isEnd(row, column) || this.isStart(row, column)) {
  1528. return false;
  1529. } else {
  1530. return true;
  1531. }
  1532. }
  1533. return false;
  1534. };
  1535. this.insideStart = function(row, column) {
  1536. if (this.compare(row, column) == 0) {
  1537. if (this.isEnd(row, column)) {
  1538. return false;
  1539. } else {
  1540. return true;
  1541. }
  1542. }
  1543. return false;
  1544. };
  1545. this.insideEnd = function(row, column) {
  1546. if (this.compare(row, column) == 0) {
  1547. if (this.isStart(row, column)) {
  1548. return false;
  1549. } else {
  1550. return true;
  1551. }
  1552. }
  1553. return false;
  1554. };
  1555. this.compare = function(row, column) {
  1556. if (!this.isMultiLine()) {
  1557. if (row === this.start.row) {
  1558. return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
  1559. };
  1560. }
  1561. if (row < this.start.row)
  1562. return -1;
  1563. if (row > this.end.row)
  1564. return 1;
  1565. if (this.start.row === row)
  1566. return column >= this.start.column ? 0 : -1;
  1567. if (this.end.row === row)
  1568. return column <= this.end.column ? 0 : 1;
  1569. return 0;
  1570. };
  1571. this.compareStart = function(row, column) {
  1572. if (this.start.row == row && this.start.column == column) {
  1573. return -1;
  1574. } else {
  1575. return this.compare(row, column);
  1576. }
  1577. };
  1578. this.compareEnd = function(row, column) {
  1579. if (this.end.row == row && this.end.column == column) {
  1580. return 1;
  1581. } else {
  1582. return this.compare(row, column);
  1583. }
  1584. };
  1585. this.compareInside = function(row, column) {
  1586. if (this.end.row == row && this.end.column == column) {
  1587. return 1;
  1588. } else if (this.start.row == row && this.start.column == column) {
  1589. return -1;
  1590. } else {
  1591. return this.compare(row, column);
  1592. }
  1593. };
  1594. this.clipRows = function(firstRow, lastRow) {
  1595. if (this.end.row > lastRow)
  1596. var end = {row: lastRow + 1, column: 0};
  1597. else if (this.end.row < firstRow)
  1598. var end = {row: firstRow, column: 0};
  1599. if (this.start.row > lastRow)
  1600. var start = {row: lastRow + 1, column: 0};
  1601. else if (this.start.row < firstRow)
  1602. var start = {row: firstRow, column: 0};
  1603. return Range.fromPoints(start || this.start, end || this.end);
  1604. };
  1605. this.extend = function(row, column) {
  1606. var cmp = this.compare(row, column);
  1607. if (cmp == 0)
  1608. return this;
  1609. else if (cmp == -1)
  1610. var start = {row: row, column: column};
  1611. else
  1612. var end = {row: row, column: column};
  1613. return Range.fromPoints(start || this.start, end || this.end);
  1614. };
  1615. this.isEmpty = function() {
  1616. return (this.start.row === this.end.row && this.start.column === this.end.column);
  1617. };
  1618. this.isMultiLine = function() {
  1619. return (this.start.row !== this.end.row);
  1620. };
  1621. this.clone = function() {
  1622. return Range.fromPoints(this.start, this.end);
  1623. };
  1624. this.collapseRows = function() {
  1625. if (this.end.column == 0)
  1626. return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
  1627. else
  1628. return new Range(this.start.row, 0, this.end.row, 0)
  1629. };
  1630. this.toScreenRange = function(session) {
  1631. var screenPosStart = session.documentToScreenPosition(this.start);
  1632. var screenPosEnd = session.documentToScreenPosition(this.end);
  1633. return new Range(
  1634. screenPosStart.row, screenPosStart.column,
  1635. screenPosEnd.row, screenPosEnd.column
  1636. );
  1637. };
  1638. this.moveBy = function(row, column) {
  1639. this.start.row += row;
  1640. this.start.column += column;
  1641. this.end.row += row;
  1642. this.end.column += column;
  1643. };
  1644. }).call(Range.prototype);
  1645. Range.fromPoints = function(start, end) {
  1646. return new Range(start.row, start.column, end.row, end.column);
  1647. };
  1648. Range.comparePoints = comparePoints;
  1649. Range.comparePoints = function(p1, p2) {
  1650. return p1.row - p2.row || p1.column - p2.column;
  1651. };
  1652. exports.Range = Range;
  1653. });
  1654. ace.define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) {
  1655. var oop = require("./lib/oop");
  1656. var EventEmitter = require("./lib/event_emitter").EventEmitter;
  1657. var Anchor = exports.Anchor = function(doc, row, column) {
  1658. this.$onChange = this.onChange.bind(this);
  1659. this.attach(doc);
  1660. if (typeof column == "undefined")
  1661. this.setPosition(row.row, row.column);
  1662. else
  1663. this.setPosition(row, column);
  1664. };
  1665. (function() {
  1666. oop.implement(this, EventEmitter);
  1667. this.getPosition = function() {
  1668. return this.$clipPositionToDocument(this.row, this.column);
  1669. };
  1670. this.getDocument = function() {
  1671. return this.document;
  1672. };
  1673. this.$insertRight = false;
  1674. this.onChange = function(e) {
  1675. var delta = e.data;
  1676. var range = delta.range;
  1677. if (range.start.row == range.end.row && range.start.row != this.row)
  1678. return;
  1679. if (range.start.row > this.row)
  1680. return;
  1681. if (range.start.row == this.row && range.start.column > this.column)
  1682. return;
  1683. var row = this.row;
  1684. var column = this.column;
  1685. var start = range.start;
  1686. var end = range.end;
  1687. if (delta.action === "insertText") {
  1688. if (start.row === row && start.column <= column) {
  1689. if (start.column === column && this.$insertRight) {
  1690. } else if (start.row === end.row) {
  1691. column += end.column - start.column;
  1692. } else {
  1693. column -= start.column;
  1694. row += end.row - start.row;
  1695. }
  1696. } else if (start.row !== end.row && start.row < row) {
  1697. row += end.row - start.row;
  1698. }
  1699. } else if (delta.action === "insertLines") {
  1700. if (start.row === row && column === 0 && this.$insertRight) {
  1701. }
  1702. else if (start.row <= row) {
  1703. row += end.row - start.row;
  1704. }
  1705. } else if (delta.action === "removeText") {
  1706. if (start.row === row && start.column < column) {
  1707. if (end.column >= column)
  1708. column = start.column;
  1709. else
  1710. column = Math.max(0, column - (end.column - start.column));
  1711. } else if (start.row !== end.row && start.row < row) {
  1712. if (end.row === row)
  1713. column = Math.max(0, column - end.column) + start.column;
  1714. row -= (end.row - start.row);
  1715. } else if (end.row === row) {
  1716. row -= end.row - start.row;
  1717. column = Math.max(0, column - end.column) + start.column;
  1718. }
  1719. } else if (delta.action == "removeLines") {
  1720. if (start.row <= row) {
  1721. if (end.row <= row)
  1722. row -= end.row - start.row;
  1723. else {
  1724. row = start.row;
  1725. column = 0;
  1726. }
  1727. }
  1728. }
  1729. this.setPosition(row, column, true);
  1730. };
  1731. this.setPosition = function(row, column, noClip) {
  1732. var pos;
  1733. if (noClip) {
  1734. pos = {
  1735. row: row,
  1736. column: column
  1737. };
  1738. } else {
  1739. pos = this.$clipPositionToDocument(row, column);
  1740. }
  1741. if (this.row == pos.row && this.column == pos.column)
  1742. return;
  1743. var old = {
  1744. row: this.row,
  1745. column: this.column
  1746. };
  1747. this.row = pos.row;
  1748. this.column = pos.column;
  1749. this._signal("change", {
  1750. old: old,
  1751. value: pos
  1752. });
  1753. };
  1754. this.detach = function() {
  1755. this.document.removeEventListener("change", this.$onChange);
  1756. };
  1757. this.attach = function(doc) {
  1758. this.document = doc || this.document;
  1759. this.document.on("change", this.$onChange);
  1760. };
  1761. this.$clipPositionToDocument = function(row, column) {
  1762. var pos = {};
  1763. if (row >= this.document.getLength()) {
  1764. pos.row = Math.max(0, this.document.getLength() - 1);
  1765. pos.column = this.document.getLine(pos.row).length;
  1766. }
  1767. else if (row < 0) {
  1768. pos.row = 0;
  1769. pos.column = 0;
  1770. }
  1771. else {
  1772. pos.row = row;
  1773. pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
  1774. }
  1775. if (column < 0)
  1776. pos.column = 0;
  1777. return pos;
  1778. };
  1779. }).call(Anchor.prototype);
  1780. });
  1781. ace.define('ace/mode/css/csslint', ['require', 'exports', 'module' ], function(require, exports, module) {
  1782. var parserlib = {};
  1783. (function(){
  1784. function EventTarget(){
  1785. this._listeners = {};
  1786. }
  1787. EventTarget.prototype = {
  1788. constructor: EventTarget,
  1789. addListener: function(type, listener){
  1790. if (!this._listeners[type]){
  1791. this._listeners[type] = [];
  1792. }
  1793. this._listeners[type].push(listener);
  1794. },
  1795. fire: function(event){
  1796. if (typeof event == "string"){
  1797. event = { type: event };
  1798. }
  1799. if (typeof event.target != "undefined"){
  1800. event.target = this;
  1801. }
  1802. if (typeof event.type == "undefined"){
  1803. throw new Error("Event object missing 'type' property.");
  1804. }
  1805. if (this._listeners[event.type]){
  1806. var listeners = this._listeners[event.type].concat();
  1807. for (var i=0, len=listeners.length; i < len; i++){
  1808. listeners[i].call(this, event);
  1809. }
  1810. }
  1811. },
  1812. removeListener: function(type, listener){
  1813. if (this._listeners[type]){
  1814. var listeners = this._listeners[type];
  1815. for (var i=0, len=listeners.length; i < len; i++){
  1816. if (listeners[i] === listener){
  1817. listeners.splice(i, 1);
  1818. break;
  1819. }
  1820. }
  1821. }
  1822. }
  1823. };
  1824. function StringReader(text){
  1825. this._input = text.replace(/\n\r?/g, "\n");
  1826. this._line = 1;
  1827. this._col = 1;
  1828. this._cursor = 0;
  1829. }
  1830. StringReader.prototype = {
  1831. constructor: StringReader,
  1832. getCol: function(){
  1833. return this._col;
  1834. },
  1835. getLine: function(){
  1836. return this._line ;
  1837. },
  1838. eof: function(){
  1839. return (this._cursor == this._input.length);
  1840. },
  1841. peek: function(count){
  1842. var c = null;
  1843. count = (typeof count == "undefined" ? 1 : count);
  1844. if (this._cursor < this._input.length){
  1845. c = this._input.charAt(this._cursor + count - 1);
  1846. }
  1847. return c;
  1848. },
  1849. read: function(){
  1850. var c = null;
  1851. if (this._cursor < this._input.length){
  1852. if (this._input.charAt(this._cursor) == "\n"){
  1853. this._line++;
  1854. this._col=1;
  1855. } else {
  1856. this._col++;
  1857. }
  1858. c = this._input.charAt(this._cursor++);
  1859. }
  1860. return c;
  1861. },
  1862. mark: function(){
  1863. this._bookmark = {
  1864. cursor: this._cursor,
  1865. line: this._line,
  1866. col: this._col
  1867. };
  1868. },
  1869. reset: function(){
  1870. if (this._bookmark){
  1871. this._cursor = this._bookmark.cursor;
  1872. this._line = this._bookmark.line;
  1873. this._col = this._bookmark.col;
  1874. delete this._bookmark;
  1875. }
  1876. },
  1877. readTo: function(pattern){
  1878. var buffer = "",
  1879. c;
  1880. while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){
  1881. c = this.read();
  1882. if (c){
  1883. buffer += c;
  1884. } else {
  1885. throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + ".");
  1886. }
  1887. }
  1888. return buffer;
  1889. },
  1890. readWhile: function(filter){
  1891. var buffer = "",
  1892. c = this.read();
  1893. while(c !== null && filter(c)){
  1894. buffer += c;
  1895. c = this.read();
  1896. }
  1897. return buffer;
  1898. },
  1899. readMatch: function(matcher){
  1900. var source = this._input.substring(this._cursor),
  1901. value = null;
  1902. if (typeof matcher == "string"){
  1903. if (source.indexOf(matcher) === 0){
  1904. value = this.readCount(matcher.length);
  1905. }
  1906. } else if (matcher instanceof RegExp){
  1907. if (matcher.test(source)){
  1908. value = this.readCount(RegExp.lastMatch.length);
  1909. }
  1910. }
  1911. return value;
  1912. },
  1913. readCount: function(count){
  1914. var buffer = "";
  1915. while(count--){
  1916. buffer += this.read();
  1917. }
  1918. return buffer;
  1919. }
  1920. };
  1921. function SyntaxError(message, line, col){
  1922. this.col = col;
  1923. this.line = line;
  1924. this.message = message;
  1925. }
  1926. SyntaxError.prototype = new Error();
  1927. function SyntaxUnit(text, line, col, type){
  1928. this.col = col;
  1929. this.line = line;
  1930. this.text = text;
  1931. this.type = type;
  1932. }
  1933. SyntaxUnit.fromToken = function(token){
  1934. return new SyntaxUnit(token.value, token.startLine, token.startCol);
  1935. };
  1936. SyntaxUnit.prototype = {
  1937. constructor: SyntaxUnit,
  1938. valueOf: function(){
  1939. return this.toString();
  1940. },
  1941. toString: function(){
  1942. return this.text;
  1943. }
  1944. };
  1945. function TokenStreamBase(input, tokenData){
  1946. this._reader = input ? new StringReader(input.toString()) : null;
  1947. this._token = null;
  1948. this._tokenData = tokenData;
  1949. this._lt = [];
  1950. this._ltIndex = 0;
  1951. this._ltIndexCache = [];
  1952. }
  1953. TokenStreamBase.createTokenData = function(tokens){
  1954. var nameMap = [],
  1955. typeMap = {},
  1956. tokenData = tokens.concat([]),
  1957. i = 0,
  1958. len = tokenData.length+1;
  1959. tokenData.UNKNOWN = -1;
  1960. tokenData.unshift({name:"EOF"});
  1961. for (; i < len; i++){
  1962. nameMap.push(tokenData[i].name);
  1963. tokenData[tokenData[i].name] = i;
  1964. if (tokenData[i].text){
  1965. typeMap[tokenData[i].text] = i;
  1966. }
  1967. }
  1968. tokenData.name = function(tt){
  1969. return nameMap[tt];
  1970. };
  1971. tokenData.type = function(c){
  1972. return typeMap[c];
  1973. };
  1974. return tokenData;
  1975. };
  1976. TokenStreamBase.prototype = {
  1977. constructor: TokenStreamBase,
  1978. match: function(tokenTypes, channel){
  1979. if (!(tokenTypes instanceof Array)){
  1980. tokenTypes = [tokenTypes];
  1981. }
  1982. var tt = this.get(channel),
  1983. i = 0,
  1984. len = tokenTypes.length;
  1985. while(i < len){
  1986. if (tt == tokenTypes[i++]){
  1987. return true;
  1988. }
  1989. }
  1990. this.unget();
  1991. return false;
  1992. },
  1993. mustMatch: function(tokenTypes, channel){
  1994. var token;
  1995. if (!(tokenTypes instanceof Array)){
  1996. tokenTypes = [tokenTypes];
  1997. }
  1998. if (!this.match.apply(this, arguments)){
  1999. token = this.LT(1);
  2000. throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
  2001. " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  2002. }
  2003. },
  2004. advance: function(tokenTypes, channel){
  2005. while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
  2006. this.get();
  2007. }
  2008. return this.LA(0);
  2009. },
  2010. get: function(channel){
  2011. var tokenInfo = this._tokenData,
  2012. reader = this._reader,
  2013. value,
  2014. i =0,
  2015. len = tokenInfo.length,
  2016. found = false,
  2017. token,
  2018. info;
  2019. if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){
  2020. i++;
  2021. this._token = this._lt[this._ltIndex++];
  2022. info = tokenInfo[this._token.type];
  2023. while((info.channel !== undefined && channel !== info.channel) &&
  2024. this._ltIndex < this._lt.length){
  2025. this._token = this._lt[this._ltIndex++];
  2026. info = tokenInfo[this._token.type];
  2027. i++;
  2028. }
  2029. if ((info.channel === undefined || channel === info.channel) &&
  2030. this._ltIndex <= this._lt.length){
  2031. this._ltIndexCache.push(i);
  2032. return this._token.type;
  2033. }
  2034. }
  2035. token = this._getToken();
  2036. if (token.type > -1 && !tokenInfo[token.type].hide){
  2037. token.channel = tokenInfo[token.type].channel;
  2038. this._token = token;
  2039. this._lt.push(token);
  2040. this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
  2041. if (this._lt.length > 5){
  2042. this._lt.shift();
  2043. }
  2044. if (this._ltIndexCache.length > 5){
  2045. this._ltIndexCache.shift();
  2046. }
  2047. this._ltIndex = this._lt.length;
  2048. }
  2049. info = tokenInfo[token.type];
  2050. if (info &&
  2051. (info.hide ||
  2052. (info.channel !== undefined && channel !== info.channel))){
  2053. return this.get(channel);
  2054. } else {
  2055. return token.type;
  2056. }
  2057. },
  2058. LA: function(index){
  2059. var total = index,
  2060. tt;
  2061. if (index > 0){
  2062. if (index > 5){
  2063. throw new Error("Too much lookahead.");
  2064. }
  2065. while(total){
  2066. tt = this.get();
  2067. total--;
  2068. }
  2069. while(total < index){
  2070. this.unget();
  2071. total++;
  2072. }
  2073. } else if (index < 0){
  2074. if(this._lt[this._ltIndex+index]){
  2075. tt = this._lt[this._ltIndex+index].type;
  2076. } else {
  2077. throw new Error("Too much lookbehind.");
  2078. }
  2079. } else {
  2080. tt = this._token.type;
  2081. }
  2082. return tt;
  2083. },
  2084. LT: function(index){
  2085. this.LA(index);
  2086. return this._lt[this._ltIndex+index-1];
  2087. },
  2088. peek: function(){
  2089. return this.LA(1);
  2090. },
  2091. token: function(){
  2092. return this._token;
  2093. },
  2094. tokenName: function(tokenType){
  2095. if (tokenType < 0 || tokenType > this._tokenData.length){
  2096. return "UNKNOWN_TOKEN";
  2097. } else {
  2098. return this._tokenData[tokenType].name;
  2099. }
  2100. },
  2101. tokenType: function(tokenName){
  2102. return this._tokenData[tokenName] || -1;
  2103. },
  2104. unget: function(){
  2105. if (this._ltIndexCache.length){
  2106. this._ltIndex -= this._ltIndexCache.pop();//--;
  2107. this._token = this._lt[this._ltIndex - 1];
  2108. } else {
  2109. throw new Error("Too much lookahead.");
  2110. }
  2111. }
  2112. };
  2113. parserlib.util = {
  2114. StringReader: StringReader,
  2115. SyntaxError : SyntaxError,
  2116. SyntaxUnit : SyntaxUnit,
  2117. EventTarget : EventTarget,
  2118. TokenStreamBase : TokenStreamBase
  2119. };
  2120. })();
  2121. (function(){
  2122. var EventTarget = parserlib.util.EventTarget,
  2123. TokenStreamBase = parserlib.util.TokenStreamBase,
  2124. StringReader = parserlib.util.StringReader,
  2125. SyntaxError = parserlib.util.SyntaxError,
  2126. SyntaxUnit = parserlib.util.SyntaxUnit;
  2127. var Colors = {
  2128. aliceblue :"#f0f8ff",
  2129. antiquewhite :"#faebd7",
  2130. aqua :"#00ffff",
  2131. aquamarine :"#7fffd4",
  2132. azure :"#f0ffff",
  2133. beige :"#f5f5dc",
  2134. bisque :"#ffe4c4",
  2135. black :"#000000",
  2136. blanchedalmond :"#ffebcd",
  2137. blue :"#0000ff",
  2138. blueviolet :"#8a2be2",
  2139. brown :"#a52a2a",
  2140. burlywood :"#deb887",
  2141. cadetblue :"#5f9ea0",
  2142. chartreuse :"#7fff00",
  2143. chocolate :"#d2691e",
  2144. coral :"#ff7f50",
  2145. cornflowerblue :"#6495ed",
  2146. cornsilk :"#fff8dc",
  2147. crimson :"#dc143c",
  2148. cyan :"#00ffff",
  2149. darkblue :"#00008b",
  2150. darkcyan :"#008b8b",
  2151. darkgoldenrod :"#b8860b",
  2152. darkgray :"#a9a9a9",
  2153. darkgrey :"#a9a9a9",
  2154. darkgreen :"#006400",
  2155. darkkhaki :"#bdb76b",
  2156. darkmagenta :"#8b008b",
  2157. darkolivegreen :"#556b2f",
  2158. darkorange :"#ff8c00",
  2159. darkorchid :"#9932cc",
  2160. darkred :"#8b0000",
  2161. darksalmon :"#e9967a",
  2162. darkseagreen :"#8fbc8f",
  2163. darkslateblue :"#483d8b",
  2164. darkslategray :"#2f4f4f",
  2165. darkslategrey :"#2f4f4f",
  2166. darkturquoise :"#00ced1",
  2167. darkviolet :"#9400d3",
  2168. deeppink :"#ff1493",
  2169. deepskyblue :"#00bfff",
  2170. dimgray :"#696969",
  2171. dimgrey :"#696969",
  2172. dodgerblue :"#1e90ff",
  2173. firebrick :"#b22222",
  2174. floralwhite :"#fffaf0",
  2175. forestgreen :"#228b22",
  2176. fuchsia :"#ff00ff",
  2177. gainsboro :"#dcdcdc",
  2178. ghostwhite :"#f8f8ff",
  2179. gold :"#ffd700",
  2180. goldenrod :"#daa520",
  2181. gray :"#808080",
  2182. grey :"#808080",
  2183. green :"#008000",
  2184. greenyellow :"#adff2f",
  2185. honeydew :"#f0fff0",
  2186. hotpink :"#ff69b4",
  2187. indianred :"#cd5c5c",
  2188. indigo :"#4b0082",
  2189. ivory :"#fffff0",
  2190. khaki :"#f0e68c",
  2191. lavender :"#e6e6fa",
  2192. lavenderblush :"#fff0f5",
  2193. lawngreen :"#7cfc00",
  2194. lemonchiffon :"#fffacd",
  2195. lightblue :"#add8e6",
  2196. lightcoral :"#f08080",
  2197. lightcyan :"#e0ffff",
  2198. lightgoldenrodyellow :"#fafad2",
  2199. lightgray :"#d3d3d3",
  2200. lightgrey :"#d3d3d3",
  2201. lightgreen :"#90ee90",
  2202. lightpink :"#ffb6c1",
  2203. lightsalmon :"#ffa07a",
  2204. lightseagreen :"#20b2aa",
  2205. lightskyblue :"#87cefa",
  2206. lightslategray :"#778899",
  2207. lightslategrey :"#778899",
  2208. lightsteelblue :"#b0c4de",
  2209. lightyellow :"#ffffe0",
  2210. lime :"#00ff00",
  2211. limegreen :"#32cd32",
  2212. linen :"#faf0e6",
  2213. magenta :"#ff00ff",
  2214. maroon :"#800000",
  2215. mediumaquamarine:"#66cdaa",
  2216. mediumblue :"#0000cd",
  2217. mediumorchid :"#ba55d3",
  2218. mediumpurple :"#9370d8",
  2219. mediumseagreen :"#3cb371",
  2220. mediumslateblue :"#7b68ee",
  2221. mediumspringgreen :"#00fa9a",
  2222. mediumturquoise :"#48d1cc",
  2223. mediumvioletred :"#c71585",
  2224. midnightblue :"#191970",
  2225. mintcream :"#f5fffa",
  2226. mistyrose :"#ffe4e1",
  2227. moccasin :"#ffe4b5",
  2228. navajowhite :"#ffdead",
  2229. navy :"#000080",
  2230. oldlace :"#fdf5e6",
  2231. olive :"#808000",
  2232. olivedrab :"#6b8e23",
  2233. orange :"#ffa500",
  2234. orangered :"#ff4500",
  2235. orchid :"#da70d6",
  2236. palegoldenrod :"#eee8aa",
  2237. palegreen :"#98fb98",
  2238. paleturquoise :"#afeeee",
  2239. palevioletred :"#d87093",
  2240. papayawhip :"#ffefd5",
  2241. peachpuff :"#ffdab9",
  2242. peru :"#cd853f",
  2243. pink :"#ffc0cb",
  2244. plum :"#dda0dd",
  2245. powderblue :"#b0e0e6",
  2246. purple :"#800080",
  2247. red :"#ff0000",
  2248. rosybrown :"#bc8f8f",
  2249. royalblue :"#4169e1",
  2250. saddlebrown :"#8b4513",
  2251. salmon :"#fa8072",
  2252. sandybrown :"#f4a460",
  2253. seagreen :"#2e8b57",
  2254. seashell :"#fff5ee",
  2255. sienna :"#a0522d",
  2256. silver :"#c0c0c0",
  2257. skyblue :"#87ceeb",
  2258. slateblue :"#6a5acd",
  2259. slategray :"#708090",
  2260. slategrey :"#708090",
  2261. snow :"#fffafa",
  2262. springgreen :"#00ff7f",
  2263. steelblue :"#4682b4",
  2264. tan :"#d2b48c",
  2265. teal :"#008080",
  2266. thistle :"#d8bfd8",
  2267. tomato :"#ff6347",
  2268. turquoise :"#40e0d0",
  2269. violet :"#ee82ee",
  2270. wheat :"#f5deb3",
  2271. white :"#ffffff",
  2272. whitesmoke :"#f5f5f5",
  2273. yellow :"#ffff00",
  2274. yellowgreen :"#9acd32",
  2275. activeBorder :"Active window border.",
  2276. activecaption :"Active window caption.",
  2277. appworkspace :"Background color of multiple document interface.",
  2278. background :"Desktop background.",
  2279. buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",
  2280. buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
  2281. buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
  2282. buttontext :"Text on push buttons.",
  2283. captiontext :"Text in caption, size box, and scrollbar arrow box.",
  2284. graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
  2285. greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",
  2286. highlight :"Item(s) selected in a control.",
  2287. highlighttext :"Text of item(s) selected in a control.",
  2288. inactiveborder :"Inactive window border.",
  2289. inactivecaption :"Inactive window caption.",
  2290. inactivecaptiontext :"Color of text in an inactive caption.",
  2291. infobackground :"Background color for tooltip controls.",
  2292. infotext :"Text color for tooltip controls.",
  2293. menu :"Menu background.",
  2294. menutext :"Text in menus.",
  2295. scrollbar :"Scroll bar gray area.",
  2296. threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  2297. threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  2298. threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  2299. threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  2300. threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  2301. window :"Window background.",
  2302. windowframe :"Window frame.",
  2303. windowtext :"Text in windows."
  2304. };
  2305. function Combinator(text, line, col){
  2306. SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
  2307. this.type = "unknown";
  2308. if (/^\s+$/.test(text)){
  2309. this.type = "descendant";
  2310. } else if (text == ">"){
  2311. this.type = "child";
  2312. } else if (text == "+"){
  2313. this.type = "adjacent-sibling";
  2314. } else if (text == "~"){
  2315. this.type = "sibling";
  2316. }
  2317. }
  2318. Combinator.prototype = new SyntaxUnit();
  2319. Combinator.prototype.constructor = Combinator;
  2320. function MediaFeature(name, value){
  2321. SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
  2322. this.name = name;
  2323. this.value = value;
  2324. }
  2325. MediaFeature.prototype = new SyntaxUnit();
  2326. MediaFeature.prototype.constructor = MediaFeature;
  2327. function MediaQuery(modifier, mediaType, features, line, col){
  2328. SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
  2329. this.modifier = modifier;
  2330. this.mediaType = mediaType;
  2331. this.features = features;
  2332. }
  2333. MediaQuery.prototype = new SyntaxUnit();
  2334. MediaQuery.prototype.constructor = MediaQuery;
  2335. function Parser(options){
  2336. EventTarget.call(this);
  2337. this.options = options || {};
  2338. this._tokenStream = null;
  2339. }
  2340. Parser.DEFAULT_TYPE = 0;
  2341. Parser.COMBINATOR_TYPE = 1;
  2342. Parser.MEDIA_FEATURE_TYPE = 2;
  2343. Parser.MEDIA_QUERY_TYPE = 3;
  2344. Parser.PROPERTY_NAME_TYPE = 4;
  2345. Parser.PROPERTY_VALUE_TYPE = 5;
  2346. Parser.PROPERTY_VALUE_PART_TYPE = 6;
  2347. Parser.SELECTOR_TYPE = 7;
  2348. Parser.SELECTOR_PART_TYPE = 8;
  2349. Parser.SELECTOR_SUB_PART_TYPE = 9;
  2350. Parser.prototype = function(){
  2351. var proto = new EventTarget(), //new prototype
  2352. prop,
  2353. additions = {
  2354. constructor: Parser,
  2355. DEFAULT_TYPE : 0,
  2356. COMBINATOR_TYPE : 1,
  2357. MEDIA_FEATURE_TYPE : 2,
  2358. MEDIA_QUERY_TYPE : 3,
  2359. PROPERTY_NAME_TYPE : 4,
  2360. PROPERTY_VALUE_TYPE : 5,
  2361. PROPERTY_VALUE_PART_TYPE : 6,
  2362. SELECTOR_TYPE : 7,
  2363. SELECTOR_PART_TYPE : 8,
  2364. SELECTOR_SUB_PART_TYPE : 9,
  2365. _stylesheet: function(){
  2366. var tokenStream = this._tokenStream,
  2367. charset = null,
  2368. count,
  2369. token,
  2370. tt;
  2371. this.fire("startstylesheet");
  2372. this._charset();
  2373. this._skipCruft();
  2374. while (tokenStream.peek() == Tokens.IMPORT_SYM){
  2375. this._import();
  2376. this._skipCruft();
  2377. }
  2378. while (tokenStream.peek() == Tokens.NAMESPACE_SYM){
  2379. this._namespace();
  2380. this._skipCruft();
  2381. }
  2382. tt = tokenStream.peek();
  2383. while(tt > Tokens.EOF){
  2384. try {
  2385. switch(tt){
  2386. case Tokens.MEDIA_SYM:
  2387. this._media();
  2388. this._skipCruft();
  2389. break;
  2390. case Tokens.PAGE_SYM:
  2391. this._page();
  2392. this._skipCruft();
  2393. break;
  2394. case Tokens.FONT_FACE_SYM:
  2395. this._font_face();
  2396. this._skipCruft();
  2397. break;
  2398. case Tokens.KEYFRAMES_SYM:
  2399. this._keyframes();
  2400. this._skipCruft();
  2401. break;
  2402. case Tokens.VIEWPORT_SYM:
  2403. this._viewport();
  2404. this._skipCruft();
  2405. break;
  2406. case Tokens.UNKNOWN_SYM: //unknown @ rule
  2407. tokenStream.get();
  2408. if (!this.options.strict){
  2409. this.fire({
  2410. type: "error",
  2411. error: null,
  2412. message: "Unknown @ rule: " + tokenStream.LT(0).value + ".",
  2413. line: tokenStream.LT(0).startLine,
  2414. col: tokenStream.LT(0).startCol
  2415. });
  2416. count=0;
  2417. while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
  2418. count++; //keep track of nesting depth
  2419. }
  2420. while(count){
  2421. tokenStream.advance([Tokens.RBRACE]);
  2422. count--;
  2423. }
  2424. } else {
  2425. throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
  2426. }
  2427. break;
  2428. case Tokens.S:
  2429. this._readWhitespace();
  2430. break;
  2431. default:
  2432. if(!this._ruleset()){
  2433. switch(tt){
  2434. case Tokens.CHARSET_SYM:
  2435. token = tokenStream.LT(1);
  2436. this._charset(false);
  2437. throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
  2438. case Tokens.IMPORT_SYM:
  2439. token = tokenStream.LT(1);
  2440. this._import(false);
  2441. throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
  2442. case Tokens.NAMESPACE_SYM:
  2443. token = tokenStream.LT(1);
  2444. this._namespace(false);
  2445. throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
  2446. default:
  2447. tokenStream.get(); //get the last token
  2448. this._unexpectedToken(tokenStream.token());
  2449. }
  2450. }
  2451. }
  2452. } catch(ex) {
  2453. if (ex instanceof SyntaxError && !this.options.strict){
  2454. this.fire({
  2455. type: "error",
  2456. error: ex,
  2457. message: ex.message,
  2458. line: ex.line,
  2459. col: ex.col
  2460. });
  2461. } else {
  2462. throw ex;
  2463. }
  2464. }
  2465. tt = tokenStream.peek();
  2466. }
  2467. if (tt != Tokens.EOF){
  2468. this._unexpectedToken(tokenStream.token());
  2469. }
  2470. this.fire("endstylesheet");
  2471. },
  2472. _charset: function(emit){
  2473. var tokenStream = this._tokenStream,
  2474. charset,
  2475. token,
  2476. line,
  2477. col;
  2478. if (tokenStream.match(Tokens.CHARSET_SYM)){
  2479. line = tokenStream.token().startLine;
  2480. col = tokenStream.token().startCol;
  2481. this._readWhitespace();
  2482. tokenStream.mustMatch(Tokens.STRING);
  2483. token = tokenStream.token();
  2484. charset = token.value;
  2485. this._readWhitespace();
  2486. tokenStream.mustMatch(Tokens.SEMICOLON);
  2487. if (emit !== false){
  2488. this.fire({
  2489. type: "charset",
  2490. charset:charset,
  2491. line: line,
  2492. col: col
  2493. });
  2494. }
  2495. }
  2496. },
  2497. _import: function(emit){
  2498. var tokenStream = this._tokenStream,
  2499. tt,
  2500. uri,
  2501. importToken,
  2502. mediaList = [];
  2503. tokenStream.mustMatch(Tokens.IMPORT_SYM);
  2504. importToken = tokenStream.token();
  2505. this._readWhitespace();
  2506. tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
  2507. uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
  2508. this._readWhitespace();
  2509. mediaList = this._media_query_list();
  2510. tokenStream.mustMatch(Tokens.SEMICOLON);
  2511. this._readWhitespace();
  2512. if (emit !== false){
  2513. this.fire({
  2514. type: "import",
  2515. uri: uri,
  2516. media: mediaList,
  2517. line: importToken.startLine,
  2518. col: importToken.startCol
  2519. });
  2520. }
  2521. },
  2522. _namespace: function(emit){
  2523. var tokenStream = this._tokenStream,
  2524. line,
  2525. col,
  2526. prefix,
  2527. uri;
  2528. tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
  2529. line = tokenStream.token().startLine;
  2530. col = tokenStream.token().startCol;
  2531. this._readWhitespace();
  2532. if (tokenStream.match(Tokens.IDENT)){
  2533. prefix = tokenStream.token().value;
  2534. this._readWhitespace();
  2535. }
  2536. tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
  2537. uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
  2538. this._readWhitespace();
  2539. tokenStream.mustMatch(Tokens.SEMICOLON);
  2540. this._readWhitespace();
  2541. if (emit !== false){
  2542. this.fire({
  2543. type: "namespace",
  2544. prefix: prefix,
  2545. uri: uri,
  2546. line: line,
  2547. col: col
  2548. });
  2549. }
  2550. },
  2551. _media: function(){
  2552. var tokenStream = this._tokenStream,
  2553. line,
  2554. col,
  2555. mediaList;// = [];
  2556. tokenStream.mustMatch(Tokens.MEDIA_SYM);
  2557. line = tokenStream.token().startLine;
  2558. col = tokenStream.token().startCol;
  2559. this._readWhitespace();
  2560. mediaList = this._media_query_list();
  2561. tokenStream.mustMatch(Tokens.LBRACE);
  2562. this._readWhitespace();
  2563. this.fire({
  2564. type: "startmedia",
  2565. media: mediaList,
  2566. line: line,
  2567. col: col
  2568. });
  2569. while(true) {
  2570. if (tokenStream.peek() == Tokens.PAGE_SYM){
  2571. this._page();
  2572. } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){
  2573. this._font_face();
  2574. } else if (!this._ruleset()){
  2575. break;
  2576. }
  2577. }
  2578. tokenStream.mustMatch(Tokens.RBRACE);
  2579. this._readWhitespace();
  2580. this.fire({
  2581. type: "endmedia",
  2582. media: mediaList,
  2583. line: line,
  2584. col: col
  2585. });
  2586. },
  2587. _media_query_list: function(){
  2588. var tokenStream = this._tokenStream,
  2589. mediaList = [];
  2590. this._readWhitespace();
  2591. if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){
  2592. mediaList.push(this._media_query());
  2593. }
  2594. while(tokenStream.match(Tokens.COMMA)){
  2595. this._readWhitespace();
  2596. mediaList.push(this._media_query());
  2597. }
  2598. return mediaList;
  2599. },
  2600. _media_query: function(){
  2601. var tokenStream = this._tokenStream,
  2602. type = null,
  2603. ident = null,
  2604. token = null,
  2605. expressions = [];
  2606. if (tokenStream.match(Tokens.IDENT)){
  2607. ident = tokenStream.token().value.toLowerCase();
  2608. if (ident != "only" && ident != "not"){
  2609. tokenStream.unget();
  2610. ident = null;
  2611. } else {
  2612. token = tokenStream.token();
  2613. }
  2614. }
  2615. this._readWhitespace();
  2616. if (tokenStream.peek() == Tokens.IDENT){
  2617. type = this._media_type();
  2618. if (token === null){
  2619. token = tokenStream.token();
  2620. }
  2621. } else if (tokenStream.peek() == Tokens.LPAREN){
  2622. if (token === null){
  2623. token = tokenStream.LT(1);
  2624. }
  2625. expressions.push(this._media_expression());
  2626. }
  2627. if (type === null && expressions.length === 0){
  2628. return null;
  2629. } else {
  2630. this._readWhitespace();
  2631. while (tokenStream.match(Tokens.IDENT)){
  2632. if (tokenStream.token().value.toLowerCase() != "and"){
  2633. this._unexpectedToken(tokenStream.token());
  2634. }
  2635. this._readWhitespace();
  2636. expressions.push(this._media_expression());
  2637. }
  2638. }
  2639. return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
  2640. },
  2641. _media_type: function(){
  2642. return this._media_feature();
  2643. },
  2644. _media_expression: function(){
  2645. var tokenStream = this._tokenStream,
  2646. feature = null,
  2647. token,
  2648. expression = null;
  2649. tokenStream.mustMatch(Tokens.LPAREN);
  2650. feature = this._media_feature();
  2651. this._readWhitespace();
  2652. if (tokenStream.match(Tokens.COLON)){
  2653. this._readWhitespace();
  2654. token = tokenStream.LT(1);
  2655. expression = this._expression();
  2656. }
  2657. tokenStream.mustMatch(Tokens.RPAREN);
  2658. this._readWhitespace();
  2659. return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));
  2660. },
  2661. _media_feature: function(){
  2662. var tokenStream = this._tokenStream;
  2663. tokenStream.mustMatch(Tokens.IDENT);
  2664. return SyntaxUnit.fromToken(tokenStream.token());
  2665. },
  2666. _page: function(){
  2667. var tokenStream = this._tokenStream,
  2668. line,
  2669. col,
  2670. identifier = null,
  2671. pseudoPage = null;
  2672. tokenStream.mustMatch(Tokens.PAGE_SYM);
  2673. line = tokenStream.token().startLine;
  2674. col = tokenStream.token().startCol;
  2675. this._readWhitespace();
  2676. if (tokenStream.match(Tokens.IDENT)){
  2677. identifier = tokenStream.token().value;
  2678. if (identifier.toLowerCase() === "auto"){
  2679. this._unexpectedToken(tokenStream.token());
  2680. }
  2681. }
  2682. if (tokenStream.peek() == Tokens.COLON){
  2683. pseudoPage = this._pseudo_page();
  2684. }
  2685. this._readWhitespace();
  2686. this.fire({
  2687. type: "startpage",
  2688. id: identifier,
  2689. pseudo: pseudoPage,
  2690. line: line,
  2691. col: col
  2692. });
  2693. this._readDeclarations(true, true);
  2694. this.fire({
  2695. type: "endpage",
  2696. id: identifier,
  2697. pseudo: pseudoPage,
  2698. line: line,
  2699. col: col
  2700. });
  2701. },
  2702. _margin: function(){
  2703. var tokenStream = this._tokenStream,
  2704. line,
  2705. col,
  2706. marginSym = this._margin_sym();
  2707. if (marginSym){
  2708. line = tokenStream.token().startLine;
  2709. col = tokenStream.token().startCol;
  2710. this.fire({
  2711. type: "startpagemargin",
  2712. margin: marginSym,
  2713. line: line,
  2714. col: col
  2715. });
  2716. this._readDeclarations(true);
  2717. this.fire({
  2718. type: "endpagemargin",
  2719. margin: marginSym,
  2720. line: line,
  2721. col: col
  2722. });
  2723. return true;
  2724. } else {
  2725. return false;
  2726. }
  2727. },
  2728. _margin_sym: function(){
  2729. var tokenStream = this._tokenStream;
  2730. if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
  2731. Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
  2732. Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
  2733. Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
  2734. Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
  2735. Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
  2736. Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))
  2737. {
  2738. return SyntaxUnit.fromToken(tokenStream.token());
  2739. } else {
  2740. return null;
  2741. }
  2742. },
  2743. _pseudo_page: function(){
  2744. var tokenStream = this._tokenStream;
  2745. tokenStream.mustMatch(Tokens.COLON);
  2746. tokenStream.mustMatch(Tokens.IDENT);
  2747. return tokenStream.token().value;
  2748. },
  2749. _font_face: function(){
  2750. var tokenStream = this._tokenStream,
  2751. line,
  2752. col;
  2753. tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
  2754. line = tokenStream.token().startLine;
  2755. col = tokenStream.token().startCol;
  2756. this._readWhitespace();
  2757. this.fire({
  2758. type: "startfontface",
  2759. line: line,
  2760. col: col
  2761. });
  2762. this._readDeclarations(true);
  2763. this.fire({
  2764. type: "endfontface",
  2765. line: line,
  2766. col: col
  2767. });
  2768. },
  2769. _viewport: function(){
  2770. var tokenStream = this._tokenStream,
  2771. line,
  2772. col;
  2773. tokenStream.mustMatch(Tokens.VIEWPORT_SYM);
  2774. line = tokenStream.token().startLine;
  2775. col = tokenStream.token().startCol;
  2776. this._readWhitespace();
  2777. this.fire({
  2778. type: "startviewport",
  2779. line: line,
  2780. col: col
  2781. });
  2782. this._readDeclarations(true);
  2783. this.fire({
  2784. type: "endviewport",
  2785. line: line,
  2786. col: col
  2787. });
  2788. },
  2789. _operator: function(inFunction){
  2790. var tokenStream = this._tokenStream,
  2791. token = null;
  2792. if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||
  2793. (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){
  2794. token = tokenStream.token();
  2795. this._readWhitespace();
  2796. }
  2797. return token ? PropertyValuePart.fromToken(token) : null;
  2798. },
  2799. _combinator: function(){
  2800. var tokenStream = this._tokenStream,
  2801. value = null,
  2802. token;
  2803. if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){
  2804. token = tokenStream.token();
  2805. value = new Combinator(token.value, token.startLine, token.startCol);
  2806. this._readWhitespace();
  2807. }
  2808. return value;
  2809. },
  2810. _unary_operator: function(){
  2811. var tokenStream = this._tokenStream;
  2812. if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){
  2813. return tokenStream.token().value;
  2814. } else {
  2815. return null;
  2816. }
  2817. },
  2818. _property: function(){
  2819. var tokenStream = this._tokenStream,
  2820. value = null,
  2821. hack = null,
  2822. tokenValue,
  2823. token,
  2824. line,
  2825. col;
  2826. if (tokenStream.peek() == Tokens.STAR && this.options.starHack){
  2827. tokenStream.get();
  2828. token = tokenStream.token();
  2829. hack = token.value;
  2830. line = token.startLine;
  2831. col = token.startCol;
  2832. }
  2833. if(tokenStream.match(Tokens.IDENT)){
  2834. token = tokenStream.token();
  2835. tokenValue = token.value;
  2836. if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){
  2837. hack = "_";
  2838. tokenValue = tokenValue.substring(1);
  2839. }
  2840. value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
  2841. this._readWhitespace();
  2842. }
  2843. return value;
  2844. },
  2845. _ruleset: function(){
  2846. var tokenStream = this._tokenStream,
  2847. tt,
  2848. selectors;
  2849. try {
  2850. selectors = this._selectors_group();
  2851. } catch (ex){
  2852. if (ex instanceof SyntaxError && !this.options.strict){
  2853. this.fire({
  2854. type: "error",
  2855. error: ex,
  2856. message: ex.message,
  2857. line: ex.line,
  2858. col: ex.col
  2859. });
  2860. tt = tokenStream.advance([Tokens.RBRACE]);
  2861. if (tt == Tokens.RBRACE){
  2862. } else {
  2863. throw ex;
  2864. }
  2865. } else {
  2866. throw ex;
  2867. }
  2868. return true;
  2869. }
  2870. if (selectors){
  2871. this.fire({
  2872. type: "startrule",
  2873. selectors: selectors,
  2874. line: selectors[0].line,
  2875. col: selectors[0].col
  2876. });
  2877. this._readDeclarations(true);
  2878. this.fire({
  2879. type: "endrule",
  2880. selectors: selectors,
  2881. line: selectors[0].line,
  2882. col: selectors[0].col
  2883. });
  2884. }
  2885. return selectors;
  2886. },
  2887. _selectors_group: function(){
  2888. var tokenStream = this._tokenStream,
  2889. selectors = [],
  2890. selector;
  2891. selector = this._selector();
  2892. if (selector !== null){
  2893. selectors.push(selector);
  2894. while(tokenStream.match(Tokens.COMMA)){
  2895. this._readWhitespace();
  2896. selector = this._selector();
  2897. if (selector !== null){
  2898. selectors.push(selector);
  2899. } else {
  2900. this._unexpectedToken(tokenStream.LT(1));
  2901. }
  2902. }
  2903. }
  2904. return selectors.length ? selectors : null;
  2905. },
  2906. _selector: function(){
  2907. var tokenStream = this._tokenStream,
  2908. selector = [],
  2909. nextSelector = null,
  2910. combinator = null,
  2911. ws = null;
  2912. nextSelector = this._simple_selector_sequence();
  2913. if (nextSelector === null){
  2914. return null;
  2915. }
  2916. selector.push(nextSelector);
  2917. do {
  2918. combinator = this._combinator();
  2919. if (combinator !== null){
  2920. selector.push(combinator);
  2921. nextSelector = this._simple_selector_sequence();
  2922. if (nextSelector === null){
  2923. this._unexpectedToken(tokenStream.LT(1));
  2924. } else {
  2925. selector.push(nextSelector);
  2926. }
  2927. } else {
  2928. if (this._readWhitespace()){
  2929. ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
  2930. combinator = this._combinator();
  2931. nextSelector = this._simple_selector_sequence();
  2932. if (nextSelector === null){
  2933. if (combinator !== null){
  2934. this._unexpectedToken(tokenStream.LT(1));
  2935. }
  2936. } else {
  2937. if (combinator !== null){
  2938. selector.push(combinator);
  2939. } else {
  2940. selector.push(ws);
  2941. }
  2942. selector.push(nextSelector);
  2943. }
  2944. } else {
  2945. break;
  2946. }
  2947. }
  2948. } while(true);
  2949. return new Selector(selector, selector[0].line, selector[0].col);
  2950. },
  2951. _simple_selector_sequence: function(){
  2952. var tokenStream = this._tokenStream,
  2953. elementName = null,
  2954. modifiers = [],
  2955. selectorText= "",
  2956. components = [
  2957. function(){
  2958. return tokenStream.match(Tokens.HASH) ?
  2959. new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
  2960. null;
  2961. },
  2962. this._class,
  2963. this._attrib,
  2964. this._pseudo,
  2965. this._negation
  2966. ],
  2967. i = 0,
  2968. len = components.length,
  2969. component = null,
  2970. found = false,
  2971. line,
  2972. col;
  2973. line = tokenStream.LT(1).startLine;
  2974. col = tokenStream.LT(1).startCol;
  2975. elementName = this._type_selector();
  2976. if (!elementName){
  2977. elementName = this._universal();
  2978. }
  2979. if (elementName !== null){
  2980. selectorText += elementName;
  2981. }
  2982. while(true){
  2983. if (tokenStream.peek() === Tokens.S){
  2984. break;
  2985. }
  2986. while(i < len && component === null){
  2987. component = components[i++].call(this);
  2988. }
  2989. if (component === null){
  2990. if (selectorText === ""){
  2991. return null;
  2992. } else {
  2993. break;
  2994. }
  2995. } else {
  2996. i = 0;
  2997. modifiers.push(component);
  2998. selectorText += component.toString();
  2999. component = null;
  3000. }
  3001. }
  3002. return selectorText !== "" ?
  3003. new SelectorPart(elementName, modifiers, selectorText, line, col) :
  3004. null;
  3005. },
  3006. _type_selector: function(){
  3007. var tokenStream = this._tokenStream,
  3008. ns = this._namespace_prefix(),
  3009. elementName = this._element_name();
  3010. if (!elementName){
  3011. if (ns){
  3012. tokenStream.unget();
  3013. if (ns.length > 1){
  3014. tokenStream.unget();
  3015. }
  3016. }
  3017. return null;
  3018. } else {
  3019. if (ns){
  3020. elementName.text = ns + elementName.text;
  3021. elementName.col -= ns.length;
  3022. }
  3023. return elementName;
  3024. }
  3025. },
  3026. _class: function(){
  3027. var tokenStream = this._tokenStream,
  3028. token;
  3029. if (tokenStream.match(Tokens.DOT)){
  3030. tokenStream.mustMatch(Tokens.IDENT);
  3031. token = tokenStream.token();
  3032. return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
  3033. } else {
  3034. return null;
  3035. }
  3036. },
  3037. _element_name: function(){
  3038. var tokenStream = this._tokenStream,
  3039. token;
  3040. if (tokenStream.match(Tokens.IDENT)){
  3041. token = tokenStream.token();
  3042. return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);
  3043. } else {
  3044. return null;
  3045. }
  3046. },
  3047. _namespace_prefix: function(){
  3048. var tokenStream = this._tokenStream,
  3049. value = "";
  3050. if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){
  3051. if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){
  3052. value += tokenStream.token().value;
  3053. }
  3054. tokenStream.mustMatch(Tokens.PIPE);
  3055. value += "|";
  3056. }
  3057. return value.length ? value : null;
  3058. },
  3059. _universal: function(){
  3060. var tokenStream = this._tokenStream,
  3061. value = "",
  3062. ns;
  3063. ns = this._namespace_prefix();
  3064. if(ns){
  3065. value += ns;
  3066. }
  3067. if(tokenStream.match(Tokens.STAR)){
  3068. value += "*";
  3069. }
  3070. return value.length ? value : null;
  3071. },
  3072. _attrib: function(){
  3073. var tokenStream = this._tokenStream,
  3074. value = null,
  3075. ns,
  3076. token;
  3077. if (tokenStream.match(Tokens.LBRACKET)){
  3078. token = tokenStream.token();
  3079. value = token.value;
  3080. value += this._readWhitespace();
  3081. ns = this._namespace_prefix();
  3082. if (ns){
  3083. value += ns;
  3084. }
  3085. tokenStream.mustMatch(Tokens.IDENT);
  3086. value += tokenStream.token().value;
  3087. value += this._readWhitespace();
  3088. if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
  3089. Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){
  3090. value += tokenStream.token().value;
  3091. value += this._readWhitespace();
  3092. tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
  3093. value += tokenStream.token().value;
  3094. value += this._readWhitespace();
  3095. }
  3096. tokenStream.mustMatch(Tokens.RBRACKET);
  3097. return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
  3098. } else {
  3099. return null;
  3100. }
  3101. },
  3102. _pseudo: function(){
  3103. var tokenStream = this._tokenStream,
  3104. pseudo = null,
  3105. colons = ":",
  3106. line,
  3107. col;
  3108. if (tokenStream.match(Tokens.COLON)){
  3109. if (tokenStream.match(Tokens.COLON)){
  3110. colons += ":";
  3111. }
  3112. if (tokenStream.match(Tokens.IDENT)){
  3113. pseudo = tokenStream.token().value;
  3114. line = tokenStream.token().startLine;
  3115. col = tokenStream.token().startCol - colons.length;
  3116. } else if (tokenStream.peek() == Tokens.FUNCTION){
  3117. line = tokenStream.LT(1).startLine;
  3118. col = tokenStream.LT(1).startCol - colons.length;
  3119. pseudo = this._functional_pseudo();
  3120. }
  3121. if (pseudo){
  3122. pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
  3123. }
  3124. }
  3125. return pseudo;
  3126. },
  3127. _functional_pseudo: function(){
  3128. var tokenStream = this._tokenStream,
  3129. value = null;
  3130. if(tokenStream.match(Tokens.FUNCTION)){
  3131. value = tokenStream.token().value;
  3132. value += this._readWhitespace();
  3133. value += this._expression();
  3134. tokenStream.mustMatch(Tokens.RPAREN);
  3135. value += ")";
  3136. }
  3137. return value;
  3138. },
  3139. _expression: function(){
  3140. var tokenStream = this._tokenStream,
  3141. value = "";
  3142. while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
  3143. Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
  3144. Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
  3145. Tokens.RESOLUTION, Tokens.SLASH])){
  3146. value += tokenStream.token().value;
  3147. value += this._readWhitespace();
  3148. }
  3149. return value.length ? value : null;
  3150. },
  3151. _negation: function(){
  3152. var tokenStream = this._tokenStream,
  3153. line,
  3154. col,
  3155. value = "",
  3156. arg,
  3157. subpart = null;
  3158. if (tokenStream.match(Tokens.NOT)){
  3159. value = tokenStream.token().value;
  3160. line = tokenStream.token().startLine;
  3161. col = tokenStream.token().startCol;
  3162. value += this._readWhitespace();
  3163. arg = this._negation_arg();
  3164. value += arg;
  3165. value += this._readWhitespace();
  3166. tokenStream.match(Tokens.RPAREN);
  3167. value += tokenStream.token().value;
  3168. subpart = new SelectorSubPart(value, "not", line, col);
  3169. subpart.args.push(arg);
  3170. }
  3171. return subpart;
  3172. },
  3173. _negation_arg: function(){
  3174. var tokenStream = this._tokenStream,
  3175. args = [
  3176. this._type_selector,
  3177. this._universal,
  3178. function(){
  3179. return tokenStream.match(Tokens.HASH) ?
  3180. new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
  3181. null;
  3182. },
  3183. this._class,
  3184. this._attrib,
  3185. this._pseudo
  3186. ],
  3187. arg = null,
  3188. i = 0,
  3189. len = args.length,
  3190. elementName,
  3191. line,
  3192. col,
  3193. part;
  3194. line = tokenStream.LT(1).startLine;
  3195. col = tokenStream.LT(1).startCol;
  3196. while(i < len && arg === null){
  3197. arg = args[i].call(this);
  3198. i++;
  3199. }
  3200. if (arg === null){
  3201. this._unexpectedToken(tokenStream.LT(1));
  3202. }
  3203. if (arg.type == "elementName"){
  3204. part = new SelectorPart(arg, [], arg.toString(), line, col);
  3205. } else {
  3206. part = new SelectorPart(null, [arg], arg.toString(), line, col);
  3207. }
  3208. return part;
  3209. },
  3210. _declaration: function(){
  3211. var tokenStream = this._tokenStream,
  3212. property = null,
  3213. expr = null,
  3214. prio = null,
  3215. error = null,
  3216. invalid = null,
  3217. propertyName= "";
  3218. property = this._property();
  3219. if (property !== null){
  3220. tokenStream.mustMatch(Tokens.COLON);
  3221. this._readWhitespace();
  3222. expr = this._expr();
  3223. if (!expr || expr.length === 0){
  3224. this._unexpectedToken(tokenStream.LT(1));
  3225. }
  3226. prio = this._prio();
  3227. propertyName = property.toString();
  3228. if (this.options.starHack && property.hack == "*" ||
  3229. this.options.underscoreHack && property.hack == "_") {
  3230. propertyName = property.text;
  3231. }
  3232. try {
  3233. this._validateProperty(propertyName, expr);
  3234. } catch (ex) {
  3235. invalid = ex;
  3236. }
  3237. this.fire({
  3238. type: "property",
  3239. property: property,
  3240. value: expr,
  3241. important: prio,
  3242. line: property.line,
  3243. col: property.col,
  3244. invalid: invalid
  3245. });
  3246. return true;
  3247. } else {
  3248. return false;
  3249. }
  3250. },
  3251. _prio: function(){
  3252. var tokenStream = this._tokenStream,
  3253. result = tokenStream.match(Tokens.IMPORTANT_SYM);
  3254. this._readWhitespace();
  3255. return result;
  3256. },
  3257. _expr: function(inFunction){
  3258. var tokenStream = this._tokenStream,
  3259. values = [],
  3260. value = null,
  3261. operator = null;
  3262. value = this._term();
  3263. if (value !== null){
  3264. values.push(value);
  3265. do {
  3266. operator = this._operator(inFunction);
  3267. if (operator){
  3268. values.push(operator);
  3269. } /*else {
  3270. values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
  3271. valueParts = [];
  3272. }*/
  3273. value = this._term();
  3274. if (value === null){
  3275. break;
  3276. } else {
  3277. values.push(value);
  3278. }
  3279. } while(true);
  3280. }
  3281. return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
  3282. },
  3283. _term: function(){
  3284. var tokenStream = this._tokenStream,
  3285. unary = null,
  3286. value = null,
  3287. token,
  3288. line,
  3289. col;
  3290. unary = this._unary_operator();
  3291. if (unary !== null){
  3292. line = tokenStream.token().startLine;
  3293. col = tokenStream.token().startCol;
  3294. }
  3295. if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){
  3296. value = this._ie_function();
  3297. if (unary === null){
  3298. line = tokenStream.token().startLine;
  3299. col = tokenStream.token().startCol;
  3300. }
  3301. } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
  3302. Tokens.ANGLE, Tokens.TIME,
  3303. Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){
  3304. value = tokenStream.token().value;
  3305. if (unary === null){
  3306. line = tokenStream.token().startLine;
  3307. col = tokenStream.token().startCol;
  3308. }
  3309. this._readWhitespace();
  3310. } else {
  3311. token = this._hexcolor();
  3312. if (token === null){
  3313. if (unary === null){
  3314. line = tokenStream.LT(1).startLine;
  3315. col = tokenStream.LT(1).startCol;
  3316. }
  3317. if (value === null){
  3318. if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){
  3319. value = this._ie_function();
  3320. } else {
  3321. value = this._function();
  3322. }
  3323. }
  3324. } else {
  3325. value = token.value;
  3326. if (unary === null){
  3327. line = token.startLine;
  3328. col = token.startCol;
  3329. }
  3330. }
  3331. }
  3332. return value !== null ?
  3333. new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
  3334. null;
  3335. },
  3336. _function: function(){
  3337. var tokenStream = this._tokenStream,
  3338. functionText = null,
  3339. expr = null,
  3340. lt;
  3341. if (tokenStream.match(Tokens.FUNCTION)){
  3342. functionText = tokenStream.token().value;
  3343. this._readWhitespace();
  3344. expr = this._expr(true);
  3345. functionText += expr;
  3346. if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){
  3347. do {
  3348. if (this._readWhitespace()){
  3349. functionText += tokenStream.token().value;
  3350. }
  3351. if (tokenStream.LA(0) == Tokens.COMMA){
  3352. functionText += tokenStream.token().value;
  3353. }
  3354. tokenStream.match(Tokens.IDENT);
  3355. functionText += tokenStream.token().value;
  3356. tokenStream.match(Tokens.EQUALS);
  3357. functionText += tokenStream.token().value;
  3358. lt = tokenStream.peek();
  3359. while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
  3360. tokenStream.get();
  3361. functionText += tokenStream.token().value;
  3362. lt = tokenStream.peek();
  3363. }
  3364. } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
  3365. }
  3366. tokenStream.match(Tokens.RPAREN);
  3367. functionText += ")";
  3368. this._readWhitespace();
  3369. }
  3370. return functionText;
  3371. },
  3372. _ie_function: function(){
  3373. var tokenStream = this._tokenStream,
  3374. functionText = null,
  3375. expr = null,
  3376. lt;
  3377. if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){
  3378. functionText = tokenStream.token().value;
  3379. do {
  3380. if (this._readWhitespace()){
  3381. functionText += tokenStream.token().value;
  3382. }
  3383. if (tokenStream.LA(0) == Tokens.COMMA){
  3384. functionText += tokenStream.token().value;
  3385. }
  3386. tokenStream.match(Tokens.IDENT);
  3387. functionText += tokenStream.token().value;
  3388. tokenStream.match(Tokens.EQUALS);
  3389. functionText += tokenStream.token().value;
  3390. lt = tokenStream.peek();
  3391. while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
  3392. tokenStream.get();
  3393. functionText += tokenStream.token().value;
  3394. lt = tokenStream.peek();
  3395. }
  3396. } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
  3397. tokenStream.match(Tokens.RPAREN);
  3398. functionText += ")";
  3399. this._readWhitespace();
  3400. }
  3401. return functionText;
  3402. },
  3403. _hexcolor: function(){
  3404. var tokenStream = this._tokenStream,
  3405. token = null,
  3406. color;
  3407. if(tokenStream.match(Tokens.HASH)){
  3408. token = tokenStream.token();
  3409. color = token.value;
  3410. if (!/#[a-f0-9]{3,6}/i.test(color)){
  3411. throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  3412. }
  3413. this._readWhitespace();
  3414. }
  3415. return token;
  3416. },
  3417. _keyframes: function(){
  3418. var tokenStream = this._tokenStream,
  3419. token,
  3420. tt,
  3421. name,
  3422. prefix = "";
  3423. tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
  3424. token = tokenStream.token();
  3425. if (/^@\-([^\-]+)\-/.test(token.value)) {
  3426. prefix = RegExp.$1;
  3427. }
  3428. this._readWhitespace();
  3429. name = this._keyframe_name();
  3430. this._readWhitespace();
  3431. tokenStream.mustMatch(Tokens.LBRACE);
  3432. this.fire({
  3433. type: "startkeyframes",
  3434. name: name,
  3435. prefix: prefix,
  3436. line: token.startLine,
  3437. col: token.startCol
  3438. });
  3439. this._readWhitespace();
  3440. tt = tokenStream.peek();
  3441. while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {
  3442. this._keyframe_rule();
  3443. this._readWhitespace();
  3444. tt = tokenStream.peek();
  3445. }
  3446. this.fire({
  3447. type: "endkeyframes",
  3448. name: name,
  3449. prefix: prefix,
  3450. line: token.startLine,
  3451. col: token.startCol
  3452. });
  3453. this._readWhitespace();
  3454. tokenStream.mustMatch(Tokens.RBRACE);
  3455. },
  3456. _keyframe_name: function(){
  3457. var tokenStream = this._tokenStream,
  3458. token;
  3459. tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
  3460. return SyntaxUnit.fromToken(tokenStream.token());
  3461. },
  3462. _keyframe_rule: function(){
  3463. var tokenStream = this._tokenStream,
  3464. token,
  3465. keyList = this._key_list();
  3466. this.fire({
  3467. type: "startkeyframerule",
  3468. keys: keyList,
  3469. line: keyList[0].line,
  3470. col: keyList[0].col
  3471. });
  3472. this._readDeclarations(true);
  3473. this.fire({
  3474. type: "endkeyframerule",
  3475. keys: keyList,
  3476. line: keyList[0].line,
  3477. col: keyList[0].col
  3478. });
  3479. },
  3480. _key_list: function(){
  3481. var tokenStream = this._tokenStream,
  3482. token,
  3483. key,
  3484. keyList = [];
  3485. keyList.push(this._key());
  3486. this._readWhitespace();
  3487. while(tokenStream.match(Tokens.COMMA)){
  3488. this._readWhitespace();
  3489. keyList.push(this._key());
  3490. this._readWhitespace();
  3491. }
  3492. return keyList;
  3493. },
  3494. _key: function(){
  3495. var tokenStream = this._tokenStream,
  3496. token;
  3497. if (tokenStream.match(Tokens.PERCENTAGE)){
  3498. return SyntaxUnit.fromToken(tokenStream.token());
  3499. } else if (tokenStream.match(Tokens.IDENT)){
  3500. token = tokenStream.token();
  3501. if (/from|to/i.test(token.value)){
  3502. return SyntaxUnit.fromToken(token);
  3503. }
  3504. tokenStream.unget();
  3505. }
  3506. this._unexpectedToken(tokenStream.LT(1));
  3507. },
  3508. _skipCruft: function(){
  3509. while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){
  3510. }
  3511. },
  3512. _readDeclarations: function(checkStart, readMargins){
  3513. var tokenStream = this._tokenStream,
  3514. tt;
  3515. this._readWhitespace();
  3516. if (checkStart){
  3517. tokenStream.mustMatch(Tokens.LBRACE);
  3518. }
  3519. this._readWhitespace();
  3520. try {
  3521. while(true){
  3522. if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){
  3523. } else if (this._declaration()){
  3524. if (!tokenStream.match(Tokens.SEMICOLON)){
  3525. break;
  3526. }
  3527. } else {
  3528. break;
  3529. }
  3530. this._readWhitespace();
  3531. }
  3532. tokenStream.mustMatch(Tokens.RBRACE);
  3533. this._readWhitespace();
  3534. } catch (ex) {
  3535. if (ex instanceof SyntaxError && !this.options.strict){
  3536. this.fire({
  3537. type: "error",
  3538. error: ex,
  3539. message: ex.message,
  3540. line: ex.line,
  3541. col: ex.col
  3542. });
  3543. tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
  3544. if (tt == Tokens.SEMICOLON){
  3545. this._readDeclarations(false, readMargins);
  3546. } else if (tt != Tokens.RBRACE){
  3547. throw ex;
  3548. }
  3549. } else {
  3550. throw ex;
  3551. }
  3552. }
  3553. },
  3554. _readWhitespace: function(){
  3555. var tokenStream = this._tokenStream,
  3556. ws = "";
  3557. while(tokenStream.match(Tokens.S)){
  3558. ws += tokenStream.token().value;
  3559. }
  3560. return ws;
  3561. },
  3562. _unexpectedToken: function(token){
  3563. throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  3564. },
  3565. _verifyEnd: function(){
  3566. if (this._tokenStream.LA(1) != Tokens.EOF){
  3567. this._unexpectedToken(this._tokenStream.LT(1));
  3568. }
  3569. },
  3570. _validateProperty: function(property, value){
  3571. Validation.validate(property, value);
  3572. },
  3573. parse: function(input){
  3574. this._tokenStream = new TokenStream(input, Tokens);
  3575. this._stylesheet();
  3576. },
  3577. parseStyleSheet: function(input){
  3578. return this.parse(input);
  3579. },
  3580. parseMediaQuery: function(input){
  3581. this._tokenStream = new TokenStream(input, Tokens);
  3582. var result = this._media_query();
  3583. this._verifyEnd();
  3584. return result;
  3585. },
  3586. parsePropertyValue: function(input){
  3587. this._tokenStream = new TokenStream(input, Tokens);
  3588. this._readWhitespace();
  3589. var result = this._expr();
  3590. this._readWhitespace();
  3591. this._verifyEnd();
  3592. return result;
  3593. },
  3594. parseRule: function(input){
  3595. this._tokenStream = new TokenStream(input, Tokens);
  3596. this._readWhitespace();
  3597. var result = this._ruleset();
  3598. this._readWhitespace();
  3599. this._verifyEnd();
  3600. return result;
  3601. },
  3602. parseSelector: function(input){
  3603. this._tokenStream = new TokenStream(input, Tokens);
  3604. this._readWhitespace();
  3605. var result = this._selector();
  3606. this._readWhitespace();
  3607. this._verifyEnd();
  3608. return result;
  3609. },
  3610. parseStyleAttribute: function(input){
  3611. input += "}"; // for error recovery in _readDeclarations()
  3612. this._tokenStream = new TokenStream(input, Tokens);
  3613. this._readDeclarations();
  3614. }
  3615. };
  3616. for (prop in additions){
  3617. if (additions.hasOwnProperty(prop)){
  3618. proto[prop] = additions[prop];
  3619. }
  3620. }
  3621. return proto;
  3622. }();
  3623. var Properties = {
  3624. "align-items" : "flex-start | flex-end | center | baseline | stretch",
  3625. "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
  3626. "align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
  3627. "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch",
  3628. "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
  3629. "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
  3630. "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
  3631. "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
  3632. "animation" : 1,
  3633. "animation-delay" : { multi: "<time>", comma: true },
  3634. "animation-direction" : { multi: "normal | alternate", comma: true },
  3635. "animation-duration" : { multi: "<time>", comma: true },
  3636. "animation-iteration-count" : { multi: "<number> | infinite", comma: true },
  3637. "animation-name" : { multi: "none | <ident>", comma: true },
  3638. "animation-play-state" : { multi: "running | paused", comma: true },
  3639. "animation-timing-function" : 1,
  3640. "-moz-animation-delay" : { multi: "<time>", comma: true },
  3641. "-moz-animation-direction" : { multi: "normal | alternate", comma: true },
  3642. "-moz-animation-duration" : { multi: "<time>", comma: true },
  3643. "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
  3644. "-moz-animation-name" : { multi: "none | <ident>", comma: true },
  3645. "-moz-animation-play-state" : { multi: "running | paused", comma: true },
  3646. "-ms-animation-delay" : { multi: "<time>", comma: true },
  3647. "-ms-animation-direction" : { multi: "normal | alternate", comma: true },
  3648. "-ms-animation-duration" : { multi: "<time>", comma: true },
  3649. "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
  3650. "-ms-animation-name" : { multi: "none | <ident>", comma: true },
  3651. "-ms-animation-play-state" : { multi: "running | paused", comma: true },
  3652. "-webkit-animation-delay" : { multi: "<time>", comma: true },
  3653. "-webkit-animation-direction" : { multi: "normal | alternate", comma: true },
  3654. "-webkit-animation-duration" : { multi: "<time>", comma: true },
  3655. "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
  3656. "-webkit-animation-name" : { multi: "none | <ident>", comma: true },
  3657. "-webkit-animation-play-state" : { multi: "running | paused", comma: true },
  3658. "-o-animation-delay" : { multi: "<time>", comma: true },
  3659. "-o-animation-direction" : { multi: "normal | alternate", comma: true },
  3660. "-o-animation-duration" : { multi: "<time>", comma: true },
  3661. "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
  3662. "-o-animation-name" : { multi: "none | <ident>", comma: true },
  3663. "-o-animation-play-state" : { multi: "running | paused", comma: true },
  3664. "appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit",
  3665. "azimuth" : function (expression) {
  3666. var simple = "<angle> | leftwards | rightwards | inherit",
  3667. direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",
  3668. behind = false,
  3669. valid = false,
  3670. part;
  3671. if (!ValidationTypes.isAny(expression, simple)) {
  3672. if (ValidationTypes.isAny(expression, "behind")) {
  3673. behind = true;
  3674. valid = true;
  3675. }
  3676. if (ValidationTypes.isAny(expression, direction)) {
  3677. valid = true;
  3678. if (!behind) {
  3679. ValidationTypes.isAny(expression, "behind");
  3680. }
  3681. }
  3682. }
  3683. if (expression.hasNext()) {
  3684. part = expression.next();
  3685. if (valid) {
  3686. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  3687. } else {
  3688. throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col);
  3689. }
  3690. }
  3691. },
  3692. "backface-visibility" : "visible | hidden",
  3693. "background" : 1,
  3694. "background-attachment" : { multi: "<attachment>", comma: true },
  3695. "background-clip" : { multi: "<box>", comma: true },
  3696. "background-color" : "<color> | inherit",
  3697. "background-image" : { multi: "<bg-image>", comma: true },
  3698. "background-origin" : { multi: "<box>", comma: true },
  3699. "background-position" : { multi: "<bg-position>", comma: true },
  3700. "background-repeat" : { multi: "<repeat-style>" },
  3701. "background-size" : { multi: "<bg-size>", comma: true },
  3702. "baseline-shift" : "baseline | sub | super | <percentage> | <length>",
  3703. "behavior" : 1,
  3704. "binding" : 1,
  3705. "bleed" : "<length>",
  3706. "bookmark-label" : "<content> | <attr> | <string>",
  3707. "bookmark-level" : "none | <integer>",
  3708. "bookmark-state" : "open | closed",
  3709. "bookmark-target" : "none | <uri> | <attr>",
  3710. "border" : "<border-width> || <border-style> || <color>",
  3711. "border-bottom" : "<border-width> || <border-style> || <color>",
  3712. "border-bottom-color" : "<color> | inherit",
  3713. "border-bottom-left-radius" : "<x-one-radius>",
  3714. "border-bottom-right-radius" : "<x-one-radius>",
  3715. "border-bottom-style" : "<border-style>",
  3716. "border-bottom-width" : "<border-width>",
  3717. "border-collapse" : "collapse | separate | inherit",
  3718. "border-color" : { multi: "<color> | inherit", max: 4 },
  3719. "border-image" : 1,
  3720. "border-image-outset" : { multi: "<length> | <number>", max: 4 },
  3721. "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 },
  3722. "border-image-slice" : function(expression) {
  3723. var valid = false,
  3724. numeric = "<number> | <percentage>",
  3725. fill = false,
  3726. count = 0,
  3727. max = 4,
  3728. part;
  3729. if (ValidationTypes.isAny(expression, "fill")) {
  3730. fill = true;
  3731. valid = true;
  3732. }
  3733. while (expression.hasNext() && count < max) {
  3734. valid = ValidationTypes.isAny(expression, numeric);
  3735. if (!valid) {
  3736. break;
  3737. }
  3738. count++;
  3739. }
  3740. if (!fill) {
  3741. ValidationTypes.isAny(expression, "fill");
  3742. } else {
  3743. valid = true;
  3744. }
  3745. if (expression.hasNext()) {
  3746. part = expression.next();
  3747. if (valid) {
  3748. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  3749. } else {
  3750. throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col);
  3751. }
  3752. }
  3753. },
  3754. "border-image-source" : "<image> | none",
  3755. "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 },
  3756. "border-left" : "<border-width> || <border-style> || <color>",
  3757. "border-left-color" : "<color> | inherit",
  3758. "border-left-style" : "<border-style>",
  3759. "border-left-width" : "<border-width>",
  3760. "border-radius" : function(expression) {
  3761. var valid = false,
  3762. simple = "<length> | <percentage> | inherit",
  3763. slash = false,
  3764. fill = false,
  3765. count = 0,
  3766. max = 8,
  3767. part;
  3768. while (expression.hasNext() && count < max) {
  3769. valid = ValidationTypes.isAny(expression, simple);
  3770. if (!valid) {
  3771. if (expression.peek() == "/" && count > 0 && !slash) {
  3772. slash = true;
  3773. max = count + 5;
  3774. expression.next();
  3775. } else {
  3776. break;
  3777. }
  3778. }
  3779. count++;
  3780. }
  3781. if (expression.hasNext()) {
  3782. part = expression.next();
  3783. if (valid) {
  3784. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  3785. } else {
  3786. throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col);
  3787. }
  3788. }
  3789. },
  3790. "border-right" : "<border-width> || <border-style> || <color>",
  3791. "border-right-color" : "<color> | inherit",
  3792. "border-right-style" : "<border-style>",
  3793. "border-right-width" : "<border-width>",
  3794. "border-spacing" : { multi: "<length> | inherit", max: 2 },
  3795. "border-style" : { multi: "<border-style>", max: 4 },
  3796. "border-top" : "<border-width> || <border-style> || <color>",
  3797. "border-top-color" : "<color> | inherit",
  3798. "border-top-left-radius" : "<x-one-radius>",
  3799. "border-top-right-radius" : "<x-one-radius>",
  3800. "border-top-style" : "<border-style>",
  3801. "border-top-width" : "<border-width>",
  3802. "border-width" : { multi: "<border-width>", max: 4 },
  3803. "bottom" : "<margin-width> | inherit",
  3804. "-moz-box-align" : "start | end | center | baseline | stretch",
  3805. "-moz-box-decoration-break" : "slice |clone",
  3806. "-moz-box-direction" : "normal | reverse | inherit",
  3807. "-moz-box-flex" : "<number>",
  3808. "-moz-box-flex-group" : "<integer>",
  3809. "-moz-box-lines" : "single | multiple",
  3810. "-moz-box-ordinal-group" : "<integer>",
  3811. "-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
  3812. "-moz-box-pack" : "start | end | center | justify",
  3813. "-webkit-box-align" : "start | end | center | baseline | stretch",
  3814. "-webkit-box-decoration-break" : "slice |clone",
  3815. "-webkit-box-direction" : "normal | reverse | inherit",
  3816. "-webkit-box-flex" : "<number>",
  3817. "-webkit-box-flex-group" : "<integer>",
  3818. "-webkit-box-lines" : "single | multiple",
  3819. "-webkit-box-ordinal-group" : "<integer>",
  3820. "-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
  3821. "-webkit-box-pack" : "start | end | center | justify",
  3822. "box-shadow" : function (expression) {
  3823. var result = false,
  3824. part;
  3825. if (!ValidationTypes.isAny(expression, "none")) {
  3826. Validation.multiProperty("<shadow>", expression, true, Infinity);
  3827. } else {
  3828. if (expression.hasNext()) {
  3829. part = expression.next();
  3830. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  3831. }
  3832. }
  3833. },
  3834. "box-sizing" : "content-box | border-box | inherit",
  3835. "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
  3836. "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
  3837. "break-inside" : "auto | avoid | avoid-page | avoid-column",
  3838. "caption-side" : "top | bottom | inherit",
  3839. "clear" : "none | right | left | both | inherit",
  3840. "clip" : 1,
  3841. "color" : "<color> | inherit",
  3842. "color-profile" : 1,
  3843. "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/
  3844. "column-fill" : "auto | balance",
  3845. "column-gap" : "<length> | normal",
  3846. "column-rule" : "<border-width> || <border-style> || <color>",
  3847. "column-rule-color" : "<color>",
  3848. "column-rule-style" : "<border-style>",
  3849. "column-rule-width" : "<border-width>",
  3850. "column-span" : "none | all",
  3851. "column-width" : "<length> | auto",
  3852. "columns" : 1,
  3853. "content" : 1,
  3854. "counter-increment" : 1,
  3855. "counter-reset" : 1,
  3856. "crop" : "<shape> | auto",
  3857. "cue" : "cue-after | cue-before | inherit",
  3858. "cue-after" : 1,
  3859. "cue-before" : 1,
  3860. "cursor" : 1,
  3861. "direction" : "ltr | rtl | inherit",
  3862. "display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex",
  3863. "dominant-baseline" : 1,
  3864. "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
  3865. "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
  3866. "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
  3867. "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",
  3868. "drop-initial-size" : "auto | line | <length> | <percentage>",
  3869. "drop-initial-value" : "initial | <integer>",
  3870. "elevation" : "<angle> | below | level | above | higher | lower | inherit",
  3871. "empty-cells" : "show | hide | inherit",
  3872. "filter" : 1,
  3873. "fit" : "fill | hidden | meet | slice",
  3874. "fit-position" : 1,
  3875. "flex" : "none | [ <flex-grow> <flex-shrink>? || <flex-basis>",
  3876. "flex-basis" : "<width>",
  3877. "flex-direction" : "row | row-reverse | column | column-reverse",
  3878. "flex-flow" : "<flex-direction> || <flex-wrap>",
  3879. "flex-grow" : "<number>",
  3880. "flex-shrink" : "<number>",
  3881. "flex-wrap" : "nowrap | wrap | wrap-reverse",
  3882. "-webkit-flex" : "none | [ <flex-grow> <flex-shrink>? || <flex-basis>",
  3883. "-webkit-flex-basis" : "<width>",
  3884. "-webkit-flex-direction" : "row | row-reverse | column | column-reverse",
  3885. "-webkit-flex-flow" : "<flex-direction> || <flex-wrap>",
  3886. "-webkit-flex-grow" : "<number>",
  3887. "-webkit-flex-shrink" : "<number>",
  3888. "-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse",
  3889. "-ms-flex" : "[[ <number> <number>? ] || [ <length> || <percentage> || auto ] ] | none",
  3890. "-ms-flex-align" : "start | end | center | stretch | baseline",
  3891. "-ms-flex-direction" : "row | column | row-reverse | column-reverse | inherit",
  3892. "-ms-flex-order" : "<number>",
  3893. "-ms-flex-pack" : "start | end | center | justify",
  3894. "-ms-flex-wrap" : "nowrap | wrap | wrap-reverse",
  3895. "float" : "left | right | none | inherit",
  3896. "float-offset" : 1,
  3897. "font" : 1,
  3898. "font-family" : 1,
  3899. "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",
  3900. "font-size-adjust" : "<number> | none | inherit",
  3901. "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",
  3902. "font-style" : "normal | italic | oblique | inherit",
  3903. "font-variant" : "normal | small-caps | inherit",
  3904. "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",
  3905. "grid-cell-stacking" : "columns | rows | layer",
  3906. "grid-column" : 1,
  3907. "grid-columns" : 1,
  3908. "grid-column-align" : "start | end | center | stretch",
  3909. "grid-column-sizing" : 1,
  3910. "grid-column-span" : "<integer>",
  3911. "grid-flow" : "none | rows | columns",
  3912. "grid-layer" : "<integer>",
  3913. "grid-row" : 1,
  3914. "grid-rows" : 1,
  3915. "grid-row-align" : "start | end | center | stretch",
  3916. "grid-row-span" : "<integer>",
  3917. "grid-row-sizing" : 1,
  3918. "hanging-punctuation" : 1,
  3919. "height" : "<margin-width> | inherit",
  3920. "hyphenate-after" : "<integer> | auto",
  3921. "hyphenate-before" : "<integer> | auto",
  3922. "hyphenate-character" : "<string> | auto",
  3923. "hyphenate-lines" : "no-limit | <integer>",
  3924. "hyphenate-resource" : 1,
  3925. "hyphens" : "none | manual | auto",
  3926. "icon" : 1,
  3927. "image-orientation" : "angle | auto",
  3928. "image-rendering" : 1,
  3929. "image-resolution" : 1,
  3930. "inline-box-align" : "initial | last | <integer>",
  3931. "justify-content" : "flex-start | flex-end | center | space-between | space-around",
  3932. "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around",
  3933. "left" : "<margin-width> | inherit",
  3934. "letter-spacing" : "<length> | normal | inherit",
  3935. "line-height" : "<number> | <length> | <percentage> | normal | inherit",
  3936. "line-break" : "auto | loose | normal | strict",
  3937. "line-stacking" : 1,
  3938. "line-stacking-ruby" : "exclude-ruby | include-ruby",
  3939. "line-stacking-shift" : "consider-shifts | disregard-shifts",
  3940. "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height",
  3941. "list-style" : 1,
  3942. "list-style-image" : "<uri> | none | inherit",
  3943. "list-style-position" : "inside | outside | inherit",
  3944. "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",
  3945. "margin" : { multi: "<margin-width> | inherit", max: 4 },
  3946. "margin-bottom" : "<margin-width> | inherit",
  3947. "margin-left" : "<margin-width> | inherit",
  3948. "margin-right" : "<margin-width> | inherit",
  3949. "margin-top" : "<margin-width> | inherit",
  3950. "mark" : 1,
  3951. "mark-after" : 1,
  3952. "mark-before" : 1,
  3953. "marks" : 1,
  3954. "marquee-direction" : 1,
  3955. "marquee-play-count" : 1,
  3956. "marquee-speed" : 1,
  3957. "marquee-style" : 1,
  3958. "max-height" : "<length> | <percentage> | none | inherit",
  3959. "max-width" : "<length> | <percentage> | none | inherit",
  3960. "min-height" : "<length> | <percentage> | inherit",
  3961. "min-width" : "<length> | <percentage> | inherit",
  3962. "move-to" : 1,
  3963. "nav-down" : 1,
  3964. "nav-index" : 1,
  3965. "nav-left" : 1,
  3966. "nav-right" : 1,
  3967. "nav-up" : 1,
  3968. "opacity" : "<number> | inherit",
  3969. "order" : "<integer>",
  3970. "-webkit-order" : "<integer>",
  3971. "orphans" : "<integer> | inherit",
  3972. "outline" : 1,
  3973. "outline-color" : "<color> | invert | inherit",
  3974. "outline-offset" : 1,
  3975. "outline-style" : "<border-style> | inherit",
  3976. "outline-width" : "<border-width> | inherit",
  3977. "overflow" : "visible | hidden | scroll | auto | inherit",
  3978. "overflow-style" : 1,
  3979. "overflow-wrap" : "normal | break-word",
  3980. "overflow-x" : 1,
  3981. "overflow-y" : 1,
  3982. "padding" : { multi: "<padding-width> | inherit", max: 4 },
  3983. "padding-bottom" : "<padding-width> | inherit",
  3984. "padding-left" : "<padding-width> | inherit",
  3985. "padding-right" : "<padding-width> | inherit",
  3986. "padding-top" : "<padding-width> | inherit",
  3987. "page" : 1,
  3988. "page-break-after" : "auto | always | avoid | left | right | inherit",
  3989. "page-break-before" : "auto | always | avoid | left | right | inherit",
  3990. "page-break-inside" : "auto | avoid | inherit",
  3991. "page-policy" : 1,
  3992. "pause" : 1,
  3993. "pause-after" : 1,
  3994. "pause-before" : 1,
  3995. "perspective" : 1,
  3996. "perspective-origin" : 1,
  3997. "phonemes" : 1,
  3998. "pitch" : 1,
  3999. "pitch-range" : 1,
  4000. "play-during" : 1,
  4001. "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",
  4002. "position" : "static | relative | absolute | fixed | inherit",
  4003. "presentation-level" : 1,
  4004. "punctuation-trim" : 1,
  4005. "quotes" : 1,
  4006. "rendering-intent" : 1,
  4007. "resize" : 1,
  4008. "rest" : 1,
  4009. "rest-after" : 1,
  4010. "rest-before" : 1,
  4011. "richness" : 1,
  4012. "right" : "<margin-width> | inherit",
  4013. "rotation" : 1,
  4014. "rotation-point" : 1,
  4015. "ruby-align" : 1,
  4016. "ruby-overhang" : 1,
  4017. "ruby-position" : 1,
  4018. "ruby-span" : 1,
  4019. "size" : 1,
  4020. "speak" : "normal | none | spell-out | inherit",
  4021. "speak-header" : "once | always | inherit",
  4022. "speak-numeral" : "digits | continuous | inherit",
  4023. "speak-punctuation" : "code | none | inherit",
  4024. "speech-rate" : 1,
  4025. "src" : 1,
  4026. "stress" : 1,
  4027. "string-set" : 1,
  4028. "table-layout" : "auto | fixed | inherit",
  4029. "tab-size" : "<integer> | <length>",
  4030. "target" : 1,
  4031. "target-name" : 1,
  4032. "target-new" : 1,
  4033. "target-position" : 1,
  4034. "text-align" : "left | right | center | justify | inherit" ,
  4035. "text-align-last" : 1,
  4036. "text-decoration" : 1,
  4037. "text-emphasis" : 1,
  4038. "text-height" : 1,
  4039. "text-indent" : "<length> | <percentage> | inherit",
  4040. "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
  4041. "text-outline" : 1,
  4042. "text-overflow" : 1,
  4043. "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
  4044. "text-shadow" : 1,
  4045. "text-transform" : "capitalize | uppercase | lowercase | none | inherit",
  4046. "text-wrap" : "normal | none | avoid",
  4047. "top" : "<margin-width> | inherit",
  4048. "-ms-touch-action" : "auto | none | pan-x | pan-y",
  4049. "touch-action" : "auto | none | pan-x | pan-y",
  4050. "transform" : 1,
  4051. "transform-origin" : 1,
  4052. "transform-style" : 1,
  4053. "transition" : 1,
  4054. "transition-delay" : 1,
  4055. "transition-duration" : 1,
  4056. "transition-property" : 1,
  4057. "transition-timing-function" : 1,
  4058. "unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit",
  4059. "user-modify" : "read-only | read-write | write-only | inherit",
  4060. "user-select" : "none | text | toggle | element | elements | all | inherit",
  4061. "vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",
  4062. "visibility" : "visible | hidden | collapse | inherit",
  4063. "voice-balance" : 1,
  4064. "voice-duration" : 1,
  4065. "voice-family" : 1,
  4066. "voice-pitch" : 1,
  4067. "voice-pitch-range" : 1,
  4068. "voice-rate" : 1,
  4069. "voice-stress" : 1,
  4070. "voice-volume" : 1,
  4071. "volume" : 1,
  4072. "white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap", //http://perishablepress.com/wrapping-content/
  4073. "white-space-collapse" : 1,
  4074. "widows" : "<integer> | inherit",
  4075. "width" : "<length> | <percentage> | auto | inherit" ,
  4076. "word-break" : "normal | keep-all | break-all",
  4077. "word-spacing" : "<length> | normal | inherit",
  4078. "word-wrap" : "normal | break-word",
  4079. "writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit",
  4080. "z-index" : "<integer> | auto | inherit",
  4081. "zoom" : "<number> | <percentage> | normal"
  4082. };
  4083. function PropertyName(text, hack, line, col){
  4084. SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
  4085. this.hack = hack;
  4086. }
  4087. PropertyName.prototype = new SyntaxUnit();
  4088. PropertyName.prototype.constructor = PropertyName;
  4089. PropertyName.prototype.toString = function(){
  4090. return (this.hack ? this.hack : "") + this.text;
  4091. };
  4092. function PropertyValue(parts, line, col){
  4093. SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
  4094. this.parts = parts;
  4095. }
  4096. PropertyValue.prototype = new SyntaxUnit();
  4097. PropertyValue.prototype.constructor = PropertyValue;
  4098. function PropertyValueIterator(value){
  4099. this._i = 0;
  4100. this._parts = value.parts;
  4101. this._marks = [];
  4102. this.value = value;
  4103. }
  4104. PropertyValueIterator.prototype.count = function(){
  4105. return this._parts.length;
  4106. };
  4107. PropertyValueIterator.prototype.isFirst = function(){
  4108. return this._i === 0;
  4109. };
  4110. PropertyValueIterator.prototype.hasNext = function(){
  4111. return (this._i < this._parts.length);
  4112. };
  4113. PropertyValueIterator.prototype.mark = function(){
  4114. this._marks.push(this._i);
  4115. };
  4116. PropertyValueIterator.prototype.peek = function(count){
  4117. return this.hasNext() ? this._parts[this._i + (count || 0)] : null;
  4118. };
  4119. PropertyValueIterator.prototype.next = function(){
  4120. return this.hasNext() ? this._parts[this._i++] : null;
  4121. };
  4122. PropertyValueIterator.prototype.previous = function(){
  4123. return this._i > 0 ? this._parts[--this._i] : null;
  4124. };
  4125. PropertyValueIterator.prototype.restore = function(){
  4126. if (this._marks.length){
  4127. this._i = this._marks.pop();
  4128. }
  4129. };
  4130. function PropertyValuePart(text, line, col){
  4131. SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
  4132. this.type = "unknown";
  4133. var temp;
  4134. if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension
  4135. this.type = "dimension";
  4136. this.value = +RegExp.$1;
  4137. this.units = RegExp.$2;
  4138. switch(this.units.toLowerCase()){
  4139. case "em":
  4140. case "rem":
  4141. case "ex":
  4142. case "px":
  4143. case "cm":
  4144. case "mm":
  4145. case "in":
  4146. case "pt":
  4147. case "pc":
  4148. case "ch":
  4149. case "vh":
  4150. case "vw":
  4151. case "vm":
  4152. this.type = "length";
  4153. break;
  4154. case "deg":
  4155. case "rad":
  4156. case "grad":
  4157. this.type = "angle";
  4158. break;
  4159. case "ms":
  4160. case "s":
  4161. this.type = "time";
  4162. break;
  4163. case "hz":
  4164. case "khz":
  4165. this.type = "frequency";
  4166. break;
  4167. case "dpi":
  4168. case "dpcm":
  4169. this.type = "resolution";
  4170. break;
  4171. }
  4172. } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
  4173. this.type = "percentage";
  4174. this.value = +RegExp.$1;
  4175. } else if (/^([+\-]?\d+)$/i.test(text)){ //integer
  4176. this.type = "integer";
  4177. this.value = +RegExp.$1;
  4178. } else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number
  4179. this.type = "number";
  4180. this.value = +RegExp.$1;
  4181. } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor
  4182. this.type = "color";
  4183. temp = RegExp.$1;
  4184. if (temp.length == 3){
  4185. this.red = parseInt(temp.charAt(0)+temp.charAt(0),16);
  4186. this.green = parseInt(temp.charAt(1)+temp.charAt(1),16);
  4187. this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16);
  4188. } else {
  4189. this.red = parseInt(temp.substring(0,2),16);
  4190. this.green = parseInt(temp.substring(2,4),16);
  4191. this.blue = parseInt(temp.substring(4,6),16);
  4192. }
  4193. } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers
  4194. this.type = "color";
  4195. this.red = +RegExp.$1;
  4196. this.green = +RegExp.$2;
  4197. this.blue = +RegExp.$3;
  4198. } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages
  4199. this.type = "color";
  4200. this.red = +RegExp.$1 * 255 / 100;
  4201. this.green = +RegExp.$2 * 255 / 100;
  4202. this.blue = +RegExp.$3 * 255 / 100;
  4203. } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
  4204. this.type = "color";
  4205. this.red = +RegExp.$1;
  4206. this.green = +RegExp.$2;
  4207. this.blue = +RegExp.$3;
  4208. this.alpha = +RegExp.$4;
  4209. } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
  4210. this.type = "color";
  4211. this.red = +RegExp.$1 * 255 / 100;
  4212. this.green = +RegExp.$2 * 255 / 100;
  4213. this.blue = +RegExp.$3 * 255 / 100;
  4214. this.alpha = +RegExp.$4;
  4215. } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
  4216. this.type = "color";
  4217. this.hue = +RegExp.$1;
  4218. this.saturation = +RegExp.$2 / 100;
  4219. this.lightness = +RegExp.$3 / 100;
  4220. } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
  4221. this.type = "color";
  4222. this.hue = +RegExp.$1;
  4223. this.saturation = +RegExp.$2 / 100;
  4224. this.lightness = +RegExp.$3 / 100;
  4225. this.alpha = +RegExp.$4;
  4226. } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
  4227. this.type = "uri";
  4228. this.uri = RegExp.$1;
  4229. } else if (/^([^\(]+)\(/i.test(text)){
  4230. this.type = "function";
  4231. this.name = RegExp.$1;
  4232. this.value = text;
  4233. } else if (/^["'][^"']*["']/.test(text)){ //string
  4234. this.type = "string";
  4235. this.value = eval(text);
  4236. } else if (Colors[text.toLowerCase()]){ //named color
  4237. this.type = "color";
  4238. temp = Colors[text.toLowerCase()].substring(1);
  4239. this.red = parseInt(temp.substring(0,2),16);
  4240. this.green = parseInt(temp.substring(2,4),16);
  4241. this.blue = parseInt(temp.substring(4,6),16);
  4242. } else if (/^[\,\/]$/.test(text)){
  4243. this.type = "operator";
  4244. this.value = text;
  4245. } else if (/^[a-z\-\u0080-\uFFFF][a-z0-9\-\u0080-\uFFFF]*$/i.test(text)){
  4246. this.type = "identifier";
  4247. this.value = text;
  4248. }
  4249. }
  4250. PropertyValuePart.prototype = new SyntaxUnit();
  4251. PropertyValuePart.prototype.constructor = PropertyValuePart;
  4252. PropertyValuePart.fromToken = function(token){
  4253. return new PropertyValuePart(token.value, token.startLine, token.startCol);
  4254. };
  4255. var Pseudos = {
  4256. ":first-letter": 1,
  4257. ":first-line": 1,
  4258. ":before": 1,
  4259. ":after": 1
  4260. };
  4261. Pseudos.ELEMENT = 1;
  4262. Pseudos.CLASS = 2;
  4263. Pseudos.isElement = function(pseudo){
  4264. return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;
  4265. };
  4266. function Selector(parts, line, col){
  4267. SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
  4268. this.parts = parts;
  4269. this.specificity = Specificity.calculate(this);
  4270. }
  4271. Selector.prototype = new SyntaxUnit();
  4272. Selector.prototype.constructor = Selector;
  4273. function SelectorPart(elementName, modifiers, text, line, col){
  4274. SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
  4275. this.elementName = elementName;
  4276. this.modifiers = modifiers;
  4277. }
  4278. SelectorPart.prototype = new SyntaxUnit();
  4279. SelectorPart.prototype.constructor = SelectorPart;
  4280. function SelectorSubPart(text, type, line, col){
  4281. SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
  4282. this.type = type;
  4283. this.args = [];
  4284. }
  4285. SelectorSubPart.prototype = new SyntaxUnit();
  4286. SelectorSubPart.prototype.constructor = SelectorSubPart;
  4287. function Specificity(a, b, c, d){
  4288. this.a = a;
  4289. this.b = b;
  4290. this.c = c;
  4291. this.d = d;
  4292. }
  4293. Specificity.prototype = {
  4294. constructor: Specificity,
  4295. compare: function(other){
  4296. var comps = ["a", "b", "c", "d"],
  4297. i, len;
  4298. for (i=0, len=comps.length; i < len; i++){
  4299. if (this[comps[i]] < other[comps[i]]){
  4300. return -1;
  4301. } else if (this[comps[i]] > other[comps[i]]){
  4302. return 1;
  4303. }
  4304. }
  4305. return 0;
  4306. },
  4307. valueOf: function(){
  4308. return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
  4309. },
  4310. toString: function(){
  4311. return this.a + "," + this.b + "," + this.c + "," + this.d;
  4312. }
  4313. };
  4314. Specificity.calculate = function(selector){
  4315. var i, len,
  4316. part,
  4317. b=0, c=0, d=0;
  4318. function updateValues(part){
  4319. var i, j, len, num,
  4320. elementName = part.elementName ? part.elementName.text : "",
  4321. modifier;
  4322. if (elementName && elementName.charAt(elementName.length-1) != "*") {
  4323. d++;
  4324. }
  4325. for (i=0, len=part.modifiers.length; i < len; i++){
  4326. modifier = part.modifiers[i];
  4327. switch(modifier.type){
  4328. case "class":
  4329. case "attribute":
  4330. c++;
  4331. break;
  4332. case "id":
  4333. b++;
  4334. break;
  4335. case "pseudo":
  4336. if (Pseudos.isElement(modifier.text)){
  4337. d++;
  4338. } else {
  4339. c++;
  4340. }
  4341. break;
  4342. case "not":
  4343. for (j=0, num=modifier.args.length; j < num; j++){
  4344. updateValues(modifier.args[j]);
  4345. }
  4346. }
  4347. }
  4348. }
  4349. for (i=0, len=selector.parts.length; i < len; i++){
  4350. part = selector.parts[i];
  4351. if (part instanceof SelectorPart){
  4352. updateValues(part);
  4353. }
  4354. }
  4355. return new Specificity(0, b, c, d);
  4356. };
  4357. var h = /^[0-9a-fA-F]$/,
  4358. nonascii = /^[\u0080-\uFFFF]$/,
  4359. nl = /\n|\r\n|\r|\f/;
  4360. function isHexDigit(c){
  4361. return c !== null && h.test(c);
  4362. }
  4363. function isDigit(c){
  4364. return c !== null && /\d/.test(c);
  4365. }
  4366. function isWhitespace(c){
  4367. return c !== null && /\s/.test(c);
  4368. }
  4369. function isNewLine(c){
  4370. return c !== null && nl.test(c);
  4371. }
  4372. function isNameStart(c){
  4373. return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c));
  4374. }
  4375. function isNameChar(c){
  4376. return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));
  4377. }
  4378. function isIdentStart(c){
  4379. return c !== null && (isNameStart(c) || /\-\\/.test(c));
  4380. }
  4381. function mix(receiver, supplier){
  4382. for (var prop in supplier){
  4383. if (supplier.hasOwnProperty(prop)){
  4384. receiver[prop] = supplier[prop];
  4385. }
  4386. }
  4387. return receiver;
  4388. }
  4389. function TokenStream(input){
  4390. TokenStreamBase.call(this, input, Tokens);
  4391. }
  4392. TokenStream.prototype = mix(new TokenStreamBase(), {
  4393. _getToken: function(channel){
  4394. var c,
  4395. reader = this._reader,
  4396. token = null,
  4397. startLine = reader.getLine(),
  4398. startCol = reader.getCol();
  4399. c = reader.read();
  4400. while(c){
  4401. switch(c){
  4402. case "/":
  4403. if(reader.peek() == "*"){
  4404. token = this.commentToken(c, startLine, startCol);
  4405. } else {
  4406. token = this.charToken(c, startLine, startCol);
  4407. }
  4408. break;
  4409. case "|":
  4410. case "~":
  4411. case "^":
  4412. case "$":
  4413. case "*":
  4414. if(reader.peek() == "="){
  4415. token = this.comparisonToken(c, startLine, startCol);
  4416. } else {
  4417. token = this.charToken(c, startLine, startCol);
  4418. }
  4419. break;
  4420. case "\"":
  4421. case "'":
  4422. token = this.stringToken(c, startLine, startCol);
  4423. break;
  4424. case "#":
  4425. if (isNameChar(reader.peek())){
  4426. token = this.hashToken(c, startLine, startCol);
  4427. } else {
  4428. token = this.charToken(c, startLine, startCol);
  4429. }
  4430. break;
  4431. case ".":
  4432. if (isDigit(reader.peek())){
  4433. token = this.numberToken(c, startLine, startCol);
  4434. } else {
  4435. token = this.charToken(c, startLine, startCol);
  4436. }
  4437. break;
  4438. case "-":
  4439. if (reader.peek() == "-"){ //could be closing HTML-style comment
  4440. token = this.htmlCommentEndToken(c, startLine, startCol);
  4441. } else if (isNameStart(reader.peek())){
  4442. token = this.identOrFunctionToken(c, startLine, startCol);
  4443. } else {
  4444. token = this.charToken(c, startLine, startCol);
  4445. }
  4446. break;
  4447. case "!":
  4448. token = this.importantToken(c, startLine, startCol);
  4449. break;
  4450. case "@":
  4451. token = this.atRuleToken(c, startLine, startCol);
  4452. break;
  4453. case ":":
  4454. token = this.notToken(c, startLine, startCol);
  4455. break;
  4456. case "<":
  4457. token = this.htmlCommentStartToken(c, startLine, startCol);
  4458. break;
  4459. case "U":
  4460. case "u":
  4461. if (reader.peek() == "+"){
  4462. token = this.unicodeRangeToken(c, startLine, startCol);
  4463. break;
  4464. }
  4465. default:
  4466. if (isDigit(c)){
  4467. token = this.numberToken(c, startLine, startCol);
  4468. } else
  4469. if (isWhitespace(c)){
  4470. token = this.whitespaceToken(c, startLine, startCol);
  4471. } else
  4472. if (isIdentStart(c)){
  4473. token = this.identOrFunctionToken(c, startLine, startCol);
  4474. } else
  4475. {
  4476. token = this.charToken(c, startLine, startCol);
  4477. }
  4478. }
  4479. break;
  4480. }
  4481. if (!token && c === null){
  4482. token = this.createToken(Tokens.EOF,null,startLine,startCol);
  4483. }
  4484. return token;
  4485. },
  4486. createToken: function(tt, value, startLine, startCol, options){
  4487. var reader = this._reader;
  4488. options = options || {};
  4489. return {
  4490. value: value,
  4491. type: tt,
  4492. channel: options.channel,
  4493. hide: options.hide || false,
  4494. startLine: startLine,
  4495. startCol: startCol,
  4496. endLine: reader.getLine(),
  4497. endCol: reader.getCol()
  4498. };
  4499. },
  4500. atRuleToken: function(first, startLine, startCol){
  4501. var rule = first,
  4502. reader = this._reader,
  4503. tt = Tokens.CHAR,
  4504. valid = false,
  4505. ident,
  4506. c;
  4507. reader.mark();
  4508. ident = this.readName();
  4509. rule = first + ident;
  4510. tt = Tokens.type(rule.toLowerCase());
  4511. if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){
  4512. if (rule.length > 1){
  4513. tt = Tokens.UNKNOWN_SYM;
  4514. } else {
  4515. tt = Tokens.CHAR;
  4516. rule = first;
  4517. reader.reset();
  4518. }
  4519. }
  4520. return this.createToken(tt, rule, startLine, startCol);
  4521. },
  4522. charToken: function(c, startLine, startCol){
  4523. var tt = Tokens.type(c);
  4524. if (tt == -1){
  4525. tt = Tokens.CHAR;
  4526. }
  4527. return this.createToken(tt, c, startLine, startCol);
  4528. },
  4529. commentToken: function(first, startLine, startCol){
  4530. var reader = this._reader,
  4531. comment = this.readComment(first);
  4532. return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
  4533. },
  4534. comparisonToken: function(c, startLine, startCol){
  4535. var reader = this._reader,
  4536. comparison = c + reader.read(),
  4537. tt = Tokens.type(comparison) || Tokens.CHAR;
  4538. return this.createToken(tt, comparison, startLine, startCol);
  4539. },
  4540. hashToken: function(first, startLine, startCol){
  4541. var reader = this._reader,
  4542. name = this.readName(first);
  4543. return this.createToken(Tokens.HASH, name, startLine, startCol);
  4544. },
  4545. htmlCommentStartToken: function(first, startLine, startCol){
  4546. var reader = this._reader,
  4547. text = first;
  4548. reader.mark();
  4549. text += reader.readCount(3);
  4550. if (text == "<!--"){
  4551. return this.createToken(Tokens.CDO, text, startLine, startCol);
  4552. } else {
  4553. reader.reset();
  4554. return this.charToken(first, startLine, startCol);
  4555. }
  4556. },
  4557. htmlCommentEndToken: function(first, startLine, startCol){
  4558. var reader = this._reader,
  4559. text = first;
  4560. reader.mark();
  4561. text += reader.readCount(2);
  4562. if (text == "-->"){
  4563. return this.createToken(Tokens.CDC, text, startLine, startCol);
  4564. } else {
  4565. reader.reset();
  4566. return this.charToken(first, startLine, startCol);
  4567. }
  4568. },
  4569. identOrFunctionToken: function(first, startLine, startCol){
  4570. var reader = this._reader,
  4571. ident = this.readName(first),
  4572. tt = Tokens.IDENT;
  4573. if (reader.peek() == "("){
  4574. ident += reader.read();
  4575. if (ident.toLowerCase() == "url("){
  4576. tt = Tokens.URI;
  4577. ident = this.readURI(ident);
  4578. if (ident.toLowerCase() == "url("){
  4579. tt = Tokens.FUNCTION;
  4580. }
  4581. } else {
  4582. tt = Tokens.FUNCTION;
  4583. }
  4584. } else if (reader.peek() == ":"){ //might be an IE function
  4585. if (ident.toLowerCase() == "progid"){
  4586. ident += reader.readTo("(");
  4587. tt = Tokens.IE_FUNCTION;
  4588. }
  4589. }
  4590. return this.createToken(tt, ident, startLine, startCol);
  4591. },
  4592. importantToken: function(first, startLine, startCol){
  4593. var reader = this._reader,
  4594. important = first,
  4595. tt = Tokens.CHAR,
  4596. temp,
  4597. c;
  4598. reader.mark();
  4599. c = reader.read();
  4600. while(c){
  4601. if (c == "/"){
  4602. if (reader.peek() != "*"){
  4603. break;
  4604. } else {
  4605. temp = this.readComment(c);
  4606. if (temp === ""){ //broken!
  4607. break;
  4608. }
  4609. }
  4610. } else if (isWhitespace(c)){
  4611. important += c + this.readWhitespace();
  4612. } else if (/i/i.test(c)){
  4613. temp = reader.readCount(8);
  4614. if (/mportant/i.test(temp)){
  4615. important += c + temp;
  4616. tt = Tokens.IMPORTANT_SYM;
  4617. }
  4618. break; //we're done
  4619. } else {
  4620. break;
  4621. }
  4622. c = reader.read();
  4623. }
  4624. if (tt == Tokens.CHAR){
  4625. reader.reset();
  4626. return this.charToken(first, startLine, startCol);
  4627. } else {
  4628. return this.createToken(tt, important, startLine, startCol);
  4629. }
  4630. },
  4631. notToken: function(first, startLine, startCol){
  4632. var reader = this._reader,
  4633. text = first;
  4634. reader.mark();
  4635. text += reader.readCount(4);
  4636. if (text.toLowerCase() == ":not("){
  4637. return this.createToken(Tokens.NOT, text, startLine, startCol);
  4638. } else {
  4639. reader.reset();
  4640. return this.charToken(first, startLine, startCol);
  4641. }
  4642. },
  4643. numberToken: function(first, startLine, startCol){
  4644. var reader = this._reader,
  4645. value = this.readNumber(first),
  4646. ident,
  4647. tt = Tokens.NUMBER,
  4648. c = reader.peek();
  4649. if (isIdentStart(c)){
  4650. ident = this.readName(reader.read());
  4651. value += ident;
  4652. if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vm$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){
  4653. tt = Tokens.LENGTH;
  4654. } else if (/^deg|^rad$|^grad$/i.test(ident)){
  4655. tt = Tokens.ANGLE;
  4656. } else if (/^ms$|^s$/i.test(ident)){
  4657. tt = Tokens.TIME;
  4658. } else if (/^hz$|^khz$/i.test(ident)){
  4659. tt = Tokens.FREQ;
  4660. } else if (/^dpi$|^dpcm$/i.test(ident)){
  4661. tt = Tokens.RESOLUTION;
  4662. } else {
  4663. tt = Tokens.DIMENSION;
  4664. }
  4665. } else if (c == "%"){
  4666. value += reader.read();
  4667. tt = Tokens.PERCENTAGE;
  4668. }
  4669. return this.createToken(tt, value, startLine, startCol);
  4670. },
  4671. stringToken: function(first, startLine, startCol){
  4672. var delim = first,
  4673. string = first,
  4674. reader = this._reader,
  4675. prev = first,
  4676. tt = Tokens.STRING,
  4677. c = reader.read();
  4678. while(c){
  4679. string += c;
  4680. if (c == delim && prev != "\\"){
  4681. break;
  4682. }
  4683. if (isNewLine(reader.peek()) && c != "\\"){
  4684. tt = Tokens.INVALID;
  4685. break;
  4686. }
  4687. prev = c;
  4688. c = reader.read();
  4689. }
  4690. if (c === null){
  4691. tt = Tokens.INVALID;
  4692. }
  4693. return this.createToken(tt, string, startLine, startCol);
  4694. },
  4695. unicodeRangeToken: function(first, startLine, startCol){
  4696. var reader = this._reader,
  4697. value = first,
  4698. temp,
  4699. tt = Tokens.CHAR;
  4700. if (reader.peek() == "+"){
  4701. reader.mark();
  4702. value += reader.read();
  4703. value += this.readUnicodeRangePart(true);
  4704. if (value.length == 2){
  4705. reader.reset();
  4706. } else {
  4707. tt = Tokens.UNICODE_RANGE;
  4708. if (value.indexOf("?") == -1){
  4709. if (reader.peek() == "-"){
  4710. reader.mark();
  4711. temp = reader.read();
  4712. temp += this.readUnicodeRangePart(false);
  4713. if (temp.length == 1){
  4714. reader.reset();
  4715. } else {
  4716. value += temp;
  4717. }
  4718. }
  4719. }
  4720. }
  4721. }
  4722. return this.createToken(tt, value, startLine, startCol);
  4723. },
  4724. whitespaceToken: function(first, startLine, startCol){
  4725. var reader = this._reader,
  4726. value = first + this.readWhitespace();
  4727. return this.createToken(Tokens.S, value, startLine, startCol);
  4728. },
  4729. readUnicodeRangePart: function(allowQuestionMark){
  4730. var reader = this._reader,
  4731. part = "",
  4732. c = reader.peek();
  4733. while(isHexDigit(c) && part.length < 6){
  4734. reader.read();
  4735. part += c;
  4736. c = reader.peek();
  4737. }
  4738. if (allowQuestionMark){
  4739. while(c == "?" && part.length < 6){
  4740. reader.read();
  4741. part += c;
  4742. c = reader.peek();
  4743. }
  4744. }
  4745. return part;
  4746. },
  4747. readWhitespace: function(){
  4748. var reader = this._reader,
  4749. whitespace = "",
  4750. c = reader.peek();
  4751. while(isWhitespace(c)){
  4752. reader.read();
  4753. whitespace += c;
  4754. c = reader.peek();
  4755. }
  4756. return whitespace;
  4757. },
  4758. readNumber: function(first){
  4759. var reader = this._reader,
  4760. number = first,
  4761. hasDot = (first == "."),
  4762. c = reader.peek();
  4763. while(c){
  4764. if (isDigit(c)){
  4765. number += reader.read();
  4766. } else if (c == "."){
  4767. if (hasDot){
  4768. break;
  4769. } else {
  4770. hasDot = true;
  4771. number += reader.read();
  4772. }
  4773. } else {
  4774. break;
  4775. }
  4776. c = reader.peek();
  4777. }
  4778. return number;
  4779. },
  4780. readString: function(){
  4781. var reader = this._reader,
  4782. delim = reader.read(),
  4783. string = delim,
  4784. prev = delim,
  4785. c = reader.peek();
  4786. while(c){
  4787. c = reader.read();
  4788. string += c;
  4789. if (c == delim && prev != "\\"){
  4790. break;
  4791. }
  4792. if (isNewLine(reader.peek()) && c != "\\"){
  4793. string = "";
  4794. break;
  4795. }
  4796. prev = c;
  4797. c = reader.peek();
  4798. }
  4799. if (c === null){
  4800. string = "";
  4801. }
  4802. return string;
  4803. },
  4804. readURI: function(first){
  4805. var reader = this._reader,
  4806. uri = first,
  4807. inner = "",
  4808. c = reader.peek();
  4809. reader.mark();
  4810. while(c && isWhitespace(c)){
  4811. reader.read();
  4812. c = reader.peek();
  4813. }
  4814. if (c == "'" || c == "\""){
  4815. inner = this.readString();
  4816. } else {
  4817. inner = this.readURL();
  4818. }
  4819. c = reader.peek();
  4820. while(c && isWhitespace(c)){
  4821. reader.read();
  4822. c = reader.peek();
  4823. }
  4824. if (inner === "" || c != ")"){
  4825. uri = first;
  4826. reader.reset();
  4827. } else {
  4828. uri += inner + reader.read();
  4829. }
  4830. return uri;
  4831. },
  4832. readURL: function(){
  4833. var reader = this._reader,
  4834. url = "",
  4835. c = reader.peek();
  4836. while (/^[!#$%&\\*-~]$/.test(c)){
  4837. url += reader.read();
  4838. c = reader.peek();
  4839. }
  4840. return url;
  4841. },
  4842. readName: function(first){
  4843. var reader = this._reader,
  4844. ident = first || "",
  4845. c = reader.peek();
  4846. while(true){
  4847. if (c == "\\"){
  4848. ident += this.readEscape(reader.read());
  4849. c = reader.peek();
  4850. } else if(c && isNameChar(c)){
  4851. ident += reader.read();
  4852. c = reader.peek();
  4853. } else {
  4854. break;
  4855. }
  4856. }
  4857. return ident;
  4858. },
  4859. readEscape: function(first){
  4860. var reader = this._reader,
  4861. cssEscape = first || "",
  4862. i = 0,
  4863. c = reader.peek();
  4864. if (isHexDigit(c)){
  4865. do {
  4866. cssEscape += reader.read();
  4867. c = reader.peek();
  4868. } while(c && isHexDigit(c) && ++i < 6);
  4869. }
  4870. if (cssEscape.length == 3 && /\s/.test(c) ||
  4871. cssEscape.length == 7 || cssEscape.length == 1){
  4872. reader.read();
  4873. } else {
  4874. c = "";
  4875. }
  4876. return cssEscape + c;
  4877. },
  4878. readComment: function(first){
  4879. var reader = this._reader,
  4880. comment = first || "",
  4881. c = reader.read();
  4882. if (c == "*"){
  4883. while(c){
  4884. comment += c;
  4885. if (comment.length > 2 && c == "*" && reader.peek() == "/"){
  4886. comment += reader.read();
  4887. break;
  4888. }
  4889. c = reader.read();
  4890. }
  4891. return comment;
  4892. } else {
  4893. return "";
  4894. }
  4895. }
  4896. });
  4897. var Tokens = [
  4898. { name: "CDO"},
  4899. { name: "CDC"},
  4900. { name: "S", whitespace: true/*, channel: "ws"*/},
  4901. { name: "COMMENT", comment: true, hide: true, channel: "comment" },
  4902. { name: "INCLUDES", text: "~="},
  4903. { name: "DASHMATCH", text: "|="},
  4904. { name: "PREFIXMATCH", text: "^="},
  4905. { name: "SUFFIXMATCH", text: "$="},
  4906. { name: "SUBSTRINGMATCH", text: "*="},
  4907. { name: "STRING"},
  4908. { name: "IDENT"},
  4909. { name: "HASH"},
  4910. { name: "IMPORT_SYM", text: "@import"},
  4911. { name: "PAGE_SYM", text: "@page"},
  4912. { name: "MEDIA_SYM", text: "@media"},
  4913. { name: "FONT_FACE_SYM", text: "@font-face"},
  4914. { name: "CHARSET_SYM", text: "@charset"},
  4915. { name: "NAMESPACE_SYM", text: "@namespace"},
  4916. { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]},
  4917. { name: "UNKNOWN_SYM" },
  4918. { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
  4919. { name: "IMPORTANT_SYM"},
  4920. { name: "LENGTH"},
  4921. { name: "ANGLE"},
  4922. { name: "TIME"},
  4923. { name: "FREQ"},
  4924. { name: "DIMENSION"},
  4925. { name: "PERCENTAGE"},
  4926. { name: "NUMBER"},
  4927. { name: "URI"},
  4928. { name: "FUNCTION"},
  4929. { name: "UNICODE_RANGE"},
  4930. { name: "INVALID"},
  4931. { name: "PLUS", text: "+" },
  4932. { name: "GREATER", text: ">"},
  4933. { name: "COMMA", text: ","},
  4934. { name: "TILDE", text: "~"},
  4935. { name: "NOT"},
  4936. { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},
  4937. { name: "TOPLEFT_SYM", text: "@top-left"},
  4938. { name: "TOPCENTER_SYM", text: "@top-center"},
  4939. { name: "TOPRIGHT_SYM", text: "@top-right"},
  4940. { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},
  4941. { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},
  4942. { name: "BOTTOMLEFT_SYM", text: "@bottom-left"},
  4943. { name: "BOTTOMCENTER_SYM", text: "@bottom-center"},
  4944. { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},
  4945. { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},
  4946. { name: "LEFTTOP_SYM", text: "@left-top"},
  4947. { name: "LEFTMIDDLE_SYM", text: "@left-middle"},
  4948. { name: "LEFTBOTTOM_SYM", text: "@left-bottom"},
  4949. { name: "RIGHTTOP_SYM", text: "@right-top"},
  4950. { name: "RIGHTMIDDLE_SYM", text: "@right-middle"},
  4951. { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},
  4952. { name: "RESOLUTION", state: "media"},
  4953. { name: "IE_FUNCTION" },
  4954. { name: "CHAR" },
  4955. {
  4956. name: "PIPE",
  4957. text: "|"
  4958. },
  4959. {
  4960. name: "SLASH",
  4961. text: "/"
  4962. },
  4963. {
  4964. name: "MINUS",
  4965. text: "-"
  4966. },
  4967. {
  4968. name: "STAR",
  4969. text: "*"
  4970. },
  4971. {
  4972. name: "LBRACE",
  4973. text: "{"
  4974. },
  4975. {
  4976. name: "RBRACE",
  4977. text: "}"
  4978. },
  4979. {
  4980. name: "LBRACKET",
  4981. text: "["
  4982. },
  4983. {
  4984. name: "RBRACKET",
  4985. text: "]"
  4986. },
  4987. {
  4988. name: "EQUALS",
  4989. text: "="
  4990. },
  4991. {
  4992. name: "COLON",
  4993. text: ":"
  4994. },
  4995. {
  4996. name: "SEMICOLON",
  4997. text: ";"
  4998. },
  4999. {
  5000. name: "LPAREN",
  5001. text: "("
  5002. },
  5003. {
  5004. name: "RPAREN",
  5005. text: ")"
  5006. },
  5007. {
  5008. name: "DOT",
  5009. text: "."
  5010. }
  5011. ];
  5012. (function(){
  5013. var nameMap = [],
  5014. typeMap = {};
  5015. Tokens.UNKNOWN = -1;
  5016. Tokens.unshift({name:"EOF"});
  5017. for (var i=0, len = Tokens.length; i < len; i++){
  5018. nameMap.push(Tokens[i].name);
  5019. Tokens[Tokens[i].name] = i;
  5020. if (Tokens[i].text){
  5021. if (Tokens[i].text instanceof Array){
  5022. for (var j=0; j < Tokens[i].text.length; j++){
  5023. typeMap[Tokens[i].text[j]] = i;
  5024. }
  5025. } else {
  5026. typeMap[Tokens[i].text] = i;
  5027. }
  5028. }
  5029. }
  5030. Tokens.name = function(tt){
  5031. return nameMap[tt];
  5032. };
  5033. Tokens.type = function(c){
  5034. return typeMap[c] || -1;
  5035. };
  5036. })();
  5037. var Validation = {
  5038. validate: function(property, value){
  5039. var name = property.toString().toLowerCase(),
  5040. parts = value.parts,
  5041. expression = new PropertyValueIterator(value),
  5042. spec = Properties[name],
  5043. part,
  5044. valid,
  5045. j, count,
  5046. msg,
  5047. types,
  5048. last,
  5049. literals,
  5050. max, multi, group;
  5051. if (!spec) {
  5052. if (name.indexOf("-") !== 0){ //vendor prefixed are ok
  5053. throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
  5054. }
  5055. } else if (typeof spec != "number"){
  5056. if (typeof spec == "string"){
  5057. if (spec.indexOf("||") > -1) {
  5058. this.groupProperty(spec, expression);
  5059. } else {
  5060. this.singleProperty(spec, expression, 1);
  5061. }
  5062. } else if (spec.multi) {
  5063. this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);
  5064. } else if (typeof spec == "function") {
  5065. spec(expression);
  5066. }
  5067. }
  5068. },
  5069. singleProperty: function(types, expression, max, partial) {
  5070. var result = false,
  5071. value = expression.value,
  5072. count = 0,
  5073. part;
  5074. while (expression.hasNext() && count < max) {
  5075. result = ValidationTypes.isAny(expression, types);
  5076. if (!result) {
  5077. break;
  5078. }
  5079. count++;
  5080. }
  5081. if (!result) {
  5082. if (expression.hasNext() && !expression.isFirst()) {
  5083. part = expression.peek();
  5084. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5085. } else {
  5086. throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
  5087. }
  5088. } else if (expression.hasNext()) {
  5089. part = expression.next();
  5090. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5091. }
  5092. },
  5093. multiProperty: function (types, expression, comma, max) {
  5094. var result = false,
  5095. value = expression.value,
  5096. count = 0,
  5097. sep = false,
  5098. part;
  5099. while(expression.hasNext() && !result && count < max) {
  5100. if (ValidationTypes.isAny(expression, types)) {
  5101. count++;
  5102. if (!expression.hasNext()) {
  5103. result = true;
  5104. } else if (comma) {
  5105. if (expression.peek() == ",") {
  5106. part = expression.next();
  5107. } else {
  5108. break;
  5109. }
  5110. }
  5111. } else {
  5112. break;
  5113. }
  5114. }
  5115. if (!result) {
  5116. if (expression.hasNext() && !expression.isFirst()) {
  5117. part = expression.peek();
  5118. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5119. } else {
  5120. part = expression.previous();
  5121. if (comma && part == ",") {
  5122. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5123. } else {
  5124. throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
  5125. }
  5126. }
  5127. } else if (expression.hasNext()) {
  5128. part = expression.next();
  5129. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5130. }
  5131. },
  5132. groupProperty: function (types, expression, comma) {
  5133. var result = false,
  5134. value = expression.value,
  5135. typeCount = types.split("||").length,
  5136. groups = { count: 0 },
  5137. partial = false,
  5138. name,
  5139. part;
  5140. while(expression.hasNext() && !result) {
  5141. name = ValidationTypes.isAnyOfGroup(expression, types);
  5142. if (name) {
  5143. if (groups[name]) {
  5144. break;
  5145. } else {
  5146. groups[name] = 1;
  5147. groups.count++;
  5148. partial = true;
  5149. if (groups.count == typeCount || !expression.hasNext()) {
  5150. result = true;
  5151. }
  5152. }
  5153. } else {
  5154. break;
  5155. }
  5156. }
  5157. if (!result) {
  5158. if (partial && expression.hasNext()) {
  5159. part = expression.peek();
  5160. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5161. } else {
  5162. throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
  5163. }
  5164. } else if (expression.hasNext()) {
  5165. part = expression.next();
  5166. throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5167. }
  5168. }
  5169. };
  5170. function ValidationError(message, line, col){
  5171. this.col = col;
  5172. this.line = line;
  5173. this.message = message;
  5174. }
  5175. ValidationError.prototype = new Error();
  5176. var ValidationTypes = {
  5177. isLiteral: function (part, literals) {
  5178. var text = part.text.toString().toLowerCase(),
  5179. args = literals.split(" | "),
  5180. i, len, found = false;
  5181. for (i=0,len=args.length; i < len && !found; i++){
  5182. if (text == args[i].toLowerCase()){
  5183. found = true;
  5184. }
  5185. }
  5186. return found;
  5187. },
  5188. isSimple: function(type) {
  5189. return !!this.simple[type];
  5190. },
  5191. isComplex: function(type) {
  5192. return !!this.complex[type];
  5193. },
  5194. isAny: function (expression, types) {
  5195. var args = types.split(" | "),
  5196. i, len, found = false;
  5197. for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){
  5198. found = this.isType(expression, args[i]);
  5199. }
  5200. return found;
  5201. },
  5202. isAnyOfGroup: function(expression, types) {
  5203. var args = types.split(" || "),
  5204. i, len, found = false;
  5205. for (i=0,len=args.length; i < len && !found; i++){
  5206. found = this.isType(expression, args[i]);
  5207. }
  5208. return found ? args[i-1] : false;
  5209. },
  5210. isType: function (expression, type) {
  5211. var part = expression.peek(),
  5212. result = false;
  5213. if (type.charAt(0) != "<") {
  5214. result = this.isLiteral(part, type);
  5215. if (result) {
  5216. expression.next();
  5217. }
  5218. } else if (this.simple[type]) {
  5219. result = this.simple[type](part);
  5220. if (result) {
  5221. expression.next();
  5222. }
  5223. } else {
  5224. result = this.complex[type](expression);
  5225. }
  5226. return result;
  5227. },
  5228. simple: {
  5229. "<absolute-size>": function(part){
  5230. return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
  5231. },
  5232. "<attachment>": function(part){
  5233. return ValidationTypes.isLiteral(part, "scroll | fixed | local");
  5234. },
  5235. "<attr>": function(part){
  5236. return part.type == "function" && part.name == "attr";
  5237. },
  5238. "<bg-image>": function(part){
  5239. return this["<image>"](part) || this["<gradient>"](part) || part == "none";
  5240. },
  5241. "<gradient>": function(part) {
  5242. return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
  5243. },
  5244. "<box>": function(part){
  5245. return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");
  5246. },
  5247. "<content>": function(part){
  5248. return part.type == "function" && part.name == "content";
  5249. },
  5250. "<relative-size>": function(part){
  5251. return ValidationTypes.isLiteral(part, "smaller | larger");
  5252. },
  5253. "<ident>": function(part){
  5254. return part.type == "identifier";
  5255. },
  5256. "<length>": function(part){
  5257. if (part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)){
  5258. return true;
  5259. }else{
  5260. return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";
  5261. }
  5262. },
  5263. "<color>": function(part){
  5264. return part.type == "color" || part == "transparent";
  5265. },
  5266. "<number>": function(part){
  5267. return part.type == "number" || this["<integer>"](part);
  5268. },
  5269. "<integer>": function(part){
  5270. return part.type == "integer";
  5271. },
  5272. "<line>": function(part){
  5273. return part.type == "integer";
  5274. },
  5275. "<angle>": function(part){
  5276. return part.type == "angle";
  5277. },
  5278. "<uri>": function(part){
  5279. return part.type == "uri";
  5280. },
  5281. "<image>": function(part){
  5282. return this["<uri>"](part);
  5283. },
  5284. "<percentage>": function(part){
  5285. return part.type == "percentage" || part == "0";
  5286. },
  5287. "<border-width>": function(part){
  5288. return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");
  5289. },
  5290. "<border-style>": function(part){
  5291. return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");
  5292. },
  5293. "<margin-width>": function(part){
  5294. return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");
  5295. },
  5296. "<padding-width>": function(part){
  5297. return this["<length>"](part) || this["<percentage>"](part);
  5298. },
  5299. "<shape>": function(part){
  5300. return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");
  5301. },
  5302. "<time>": function(part) {
  5303. return part.type == "time";
  5304. }
  5305. },
  5306. complex: {
  5307. "<bg-position>": function(expression){
  5308. var types = this,
  5309. result = false,
  5310. numeric = "<percentage> | <length>",
  5311. xDir = "left | right",
  5312. yDir = "top | bottom",
  5313. count = 0,
  5314. hasNext = function() {
  5315. return expression.hasNext() && expression.peek() != ",";
  5316. };
  5317. while (expression.peek(count) && expression.peek(count) != ",") {
  5318. count++;
  5319. }
  5320. if (count < 3) {
  5321. if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) {
  5322. result = true;
  5323. ValidationTypes.isAny(expression, yDir + " | center | " + numeric);
  5324. } else if (ValidationTypes.isAny(expression, yDir)) {
  5325. result = true;
  5326. ValidationTypes.isAny(expression, xDir + " | center");
  5327. }
  5328. } else {
  5329. if (ValidationTypes.isAny(expression, xDir)) {
  5330. if (ValidationTypes.isAny(expression, yDir)) {
  5331. result = true;
  5332. ValidationTypes.isAny(expression, numeric);
  5333. } else if (ValidationTypes.isAny(expression, numeric)) {
  5334. if (ValidationTypes.isAny(expression, yDir)) {
  5335. result = true;
  5336. ValidationTypes.isAny(expression, numeric);
  5337. } else if (ValidationTypes.isAny(expression, "center")) {
  5338. result = true;
  5339. }
  5340. }
  5341. } else if (ValidationTypes.isAny(expression, yDir)) {
  5342. if (ValidationTypes.isAny(expression, xDir)) {
  5343. result = true;
  5344. ValidationTypes.isAny(expression, numeric);
  5345. } else if (ValidationTypes.isAny(expression, numeric)) {
  5346. if (ValidationTypes.isAny(expression, xDir)) {
  5347. result = true;
  5348. ValidationTypes.isAny(expression, numeric);
  5349. } else if (ValidationTypes.isAny(expression, "center")) {
  5350. result = true;
  5351. }
  5352. }
  5353. } else if (ValidationTypes.isAny(expression, "center")) {
  5354. if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) {
  5355. result = true;
  5356. ValidationTypes.isAny(expression, numeric);
  5357. }
  5358. }
  5359. }
  5360. return result;
  5361. },
  5362. "<bg-size>": function(expression){
  5363. var types = this,
  5364. result = false,
  5365. numeric = "<percentage> | <length> | auto",
  5366. part,
  5367. i, len;
  5368. if (ValidationTypes.isAny(expression, "cover | contain")) {
  5369. result = true;
  5370. } else if (ValidationTypes.isAny(expression, numeric)) {
  5371. result = true;
  5372. ValidationTypes.isAny(expression, numeric);
  5373. }
  5374. return result;
  5375. },
  5376. "<repeat-style>": function(expression){
  5377. var result = false,
  5378. values = "repeat | space | round | no-repeat",
  5379. part;
  5380. if (expression.hasNext()){
  5381. part = expression.next();
  5382. if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
  5383. result = true;
  5384. } else if (ValidationTypes.isLiteral(part, values)) {
  5385. result = true;
  5386. if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
  5387. expression.next();
  5388. }
  5389. }
  5390. }
  5391. return result;
  5392. },
  5393. "<shadow>": function(expression) {
  5394. var result = false,
  5395. count = 0,
  5396. inset = false,
  5397. color = false,
  5398. part;
  5399. if (expression.hasNext()) {
  5400. if (ValidationTypes.isAny(expression, "inset")){
  5401. inset = true;
  5402. }
  5403. if (ValidationTypes.isAny(expression, "<color>")) {
  5404. color = true;
  5405. }
  5406. while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
  5407. count++;
  5408. }
  5409. if (expression.hasNext()) {
  5410. if (!color) {
  5411. ValidationTypes.isAny(expression, "<color>");
  5412. }
  5413. if (!inset) {
  5414. ValidationTypes.isAny(expression, "inset");
  5415. }
  5416. }
  5417. result = (count >= 2 && count <= 4);
  5418. }
  5419. return result;
  5420. },
  5421. "<x-one-radius>": function(expression) {
  5422. var result = false,
  5423. simple = "<length> | <percentage> | inherit";
  5424. if (ValidationTypes.isAny(expression, simple)){
  5425. result = true;
  5426. ValidationTypes.isAny(expression, simple);
  5427. }
  5428. return result;
  5429. }
  5430. }
  5431. };
  5432. parserlib.css = {
  5433. Colors :Colors,
  5434. Combinator :Combinator,
  5435. Parser :Parser,
  5436. PropertyName :PropertyName,
  5437. PropertyValue :PropertyValue,
  5438. PropertyValuePart :PropertyValuePart,
  5439. MediaFeature :MediaFeature,
  5440. MediaQuery :MediaQuery,
  5441. Selector :Selector,
  5442. SelectorPart :SelectorPart,
  5443. SelectorSubPart :SelectorSubPart,
  5444. Specificity :Specificity,
  5445. TokenStream :TokenStream,
  5446. Tokens :Tokens,
  5447. ValidationError :ValidationError
  5448. };
  5449. })();
  5450. (function(){
  5451. for(var prop in parserlib){
  5452. exports[prop] = parserlib[prop];
  5453. }
  5454. })();
  5455. var CSSLint = (function(){
  5456. var rules = [],
  5457. formatters = [],
  5458. embeddedRuleset = /\/\*csslint([^\*]*)\*\//,
  5459. api = new parserlib.util.EventTarget();
  5460. api.version = "@VERSION@";
  5461. api.addRule = function(rule){
  5462. rules.push(rule);
  5463. rules[rule.id] = rule;
  5464. };
  5465. api.clearRules = function(){
  5466. rules = [];
  5467. };
  5468. api.getRules = function(){
  5469. return [].concat(rules).sort(function(a,b){
  5470. return a.id > b.id ? 1 : 0;
  5471. });
  5472. };
  5473. api.getRuleset = function() {
  5474. var ruleset = {},
  5475. i = 0,
  5476. len = rules.length;
  5477. while (i < len){
  5478. ruleset[rules[i++].id] = 1; //by default, everything is a warning
  5479. }
  5480. return ruleset;
  5481. };
  5482. function applyEmbeddedRuleset(text, ruleset){
  5483. var valueMap,
  5484. embedded = text && text.match(embeddedRuleset),
  5485. rules = embedded && embedded[1];
  5486. if (rules) {
  5487. valueMap = {
  5488. "true": 2, // true is error
  5489. "": 1, // blank is warning
  5490. "false": 0, // false is ignore
  5491. "2": 2, // explicit error
  5492. "1": 1, // explicit warning
  5493. "0": 0 // explicit ignore
  5494. };
  5495. rules.toLowerCase().split(",").forEach(function(rule){
  5496. var pair = rule.split(":"),
  5497. property = pair[0] || "",
  5498. value = pair[1] || "";
  5499. ruleset[property.trim()] = valueMap[value.trim()];
  5500. });
  5501. }
  5502. return ruleset;
  5503. }
  5504. api.addFormatter = function(formatter) {
  5505. formatters[formatter.id] = formatter;
  5506. };
  5507. api.getFormatter = function(formatId){
  5508. return formatters[formatId];
  5509. };
  5510. api.format = function(results, filename, formatId, options) {
  5511. var formatter = this.getFormatter(formatId),
  5512. result = null;
  5513. if (formatter){
  5514. result = formatter.startFormat();
  5515. result += formatter.formatResults(results, filename, options || {});
  5516. result += formatter.endFormat();
  5517. }
  5518. return result;
  5519. };
  5520. api.hasFormat = function(formatId){
  5521. return formatters.hasOwnProperty(formatId);
  5522. };
  5523. api.verify = function(text, ruleset){
  5524. var i = 0,
  5525. len = rules.length,
  5526. reporter,
  5527. lines,
  5528. report,
  5529. parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
  5530. underscoreHack: true, strict: false });
  5531. lines = text.replace(/\n\r?/g, "$split$").split('$split$');
  5532. if (!ruleset){
  5533. ruleset = this.getRuleset();
  5534. }
  5535. if (embeddedRuleset.test(text)){
  5536. ruleset = applyEmbeddedRuleset(text, ruleset);
  5537. }
  5538. reporter = new Reporter(lines, ruleset);
  5539. ruleset.errors = 2; //always report parsing errors as errors
  5540. for (i in ruleset){
  5541. if(ruleset.hasOwnProperty(i) && ruleset[i]){
  5542. if (rules[i]){
  5543. rules[i].init(parser, reporter);
  5544. }
  5545. }
  5546. }
  5547. try {
  5548. parser.parse(text);
  5549. } catch (ex) {
  5550. reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
  5551. }
  5552. report = {
  5553. messages : reporter.messages,
  5554. stats : reporter.stats,
  5555. ruleset : reporter.ruleset
  5556. };
  5557. report.messages.sort(function (a, b){
  5558. if (a.rollup && !b.rollup){
  5559. return 1;
  5560. } else if (!a.rollup && b.rollup){
  5561. return -1;
  5562. } else {
  5563. return a.line - b.line;
  5564. }
  5565. });
  5566. return report;
  5567. };
  5568. return api;
  5569. })();
  5570. function Reporter(lines, ruleset){
  5571. this.messages = [];
  5572. this.stats = [];
  5573. this.lines = lines;
  5574. this.ruleset = ruleset;
  5575. }
  5576. Reporter.prototype = {
  5577. constructor: Reporter,
  5578. error: function(message, line, col, rule){
  5579. this.messages.push({
  5580. type : "error",
  5581. line : line,
  5582. col : col,
  5583. message : message,
  5584. evidence: this.lines[line-1],
  5585. rule : rule || {}
  5586. });
  5587. },
  5588. warn: function(message, line, col, rule){
  5589. this.report(message, line, col, rule);
  5590. },
  5591. report: function(message, line, col, rule){
  5592. this.messages.push({
  5593. type : this.ruleset[rule.id] == 2 ? "error" : "warning",
  5594. line : line,
  5595. col : col,
  5596. message : message,
  5597. evidence: this.lines[line-1],
  5598. rule : rule
  5599. });
  5600. },
  5601. info: function(message, line, col, rule){
  5602. this.messages.push({
  5603. type : "info",
  5604. line : line,
  5605. col : col,
  5606. message : message,
  5607. evidence: this.lines[line-1],
  5608. rule : rule
  5609. });
  5610. },
  5611. rollupError: function(message, rule){
  5612. this.messages.push({
  5613. type : "error",
  5614. rollup : true,
  5615. message : message,
  5616. rule : rule
  5617. });
  5618. },
  5619. rollupWarn: function(message, rule){
  5620. this.messages.push({
  5621. type : "warning",
  5622. rollup : true,
  5623. message : message,
  5624. rule : rule
  5625. });
  5626. },
  5627. stat: function(name, value){
  5628. this.stats[name] = value;
  5629. }
  5630. };
  5631. CSSLint._Reporter = Reporter;
  5632. CSSLint.Util = {
  5633. mix: function(receiver, supplier){
  5634. var prop;
  5635. for (prop in supplier){
  5636. if (supplier.hasOwnProperty(prop)){
  5637. receiver[prop] = supplier[prop];
  5638. }
  5639. }
  5640. return prop;
  5641. },
  5642. indexOf: function(values, value){
  5643. if (values.indexOf){
  5644. return values.indexOf(value);
  5645. } else {
  5646. for (var i=0, len=values.length; i < len; i++){
  5647. if (values[i] === value){
  5648. return i;
  5649. }
  5650. }
  5651. return -1;
  5652. }
  5653. },
  5654. forEach: function(values, func) {
  5655. if (values.forEach){
  5656. return values.forEach(func);
  5657. } else {
  5658. for (var i=0, len=values.length; i < len; i++){
  5659. func(values[i], i, values);
  5660. }
  5661. }
  5662. }
  5663. };
  5664. CSSLint.addRule({
  5665. id: "adjoining-classes",
  5666. name: "Disallow adjoining classes",
  5667. desc: "Don't use adjoining classes.",
  5668. browsers: "IE6",
  5669. init: function(parser, reporter){
  5670. var rule = this;
  5671. parser.addListener("startrule", function(event){
  5672. var selectors = event.selectors,
  5673. selector,
  5674. part,
  5675. modifier,
  5676. classCount,
  5677. i, j, k;
  5678. for (i=0; i < selectors.length; i++){
  5679. selector = selectors[i];
  5680. for (j=0; j < selector.parts.length; j++){
  5681. part = selector.parts[j];
  5682. if (part.type == parser.SELECTOR_PART_TYPE){
  5683. classCount = 0;
  5684. for (k=0; k < part.modifiers.length; k++){
  5685. modifier = part.modifiers[k];
  5686. if (modifier.type == "class"){
  5687. classCount++;
  5688. }
  5689. if (classCount > 1){
  5690. reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
  5691. }
  5692. }
  5693. }
  5694. }
  5695. }
  5696. });
  5697. }
  5698. });
  5699. CSSLint.addRule({
  5700. id: "box-model",
  5701. name: "Beware of broken box size",
  5702. desc: "Don't use width or height when using padding or border.",
  5703. browsers: "All",
  5704. init: function(parser, reporter){
  5705. var rule = this,
  5706. widthProperties = {
  5707. border: 1,
  5708. "border-left": 1,
  5709. "border-right": 1,
  5710. padding: 1,
  5711. "padding-left": 1,
  5712. "padding-right": 1
  5713. },
  5714. heightProperties = {
  5715. border: 1,
  5716. "border-bottom": 1,
  5717. "border-top": 1,
  5718. padding: 1,
  5719. "padding-bottom": 1,
  5720. "padding-top": 1
  5721. },
  5722. properties,
  5723. boxSizing = false;
  5724. function startRule(){
  5725. properties = {};
  5726. boxSizing = false;
  5727. }
  5728. function endRule(){
  5729. var prop, value;
  5730. if (!boxSizing) {
  5731. if (properties.height){
  5732. for (prop in heightProperties){
  5733. if (heightProperties.hasOwnProperty(prop) && properties[prop]){
  5734. value = properties[prop].value;
  5735. if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
  5736. reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
  5737. }
  5738. }
  5739. }
  5740. }
  5741. if (properties.width){
  5742. for (prop in widthProperties){
  5743. if (widthProperties.hasOwnProperty(prop) && properties[prop]){
  5744. value = properties[prop].value;
  5745. if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
  5746. reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
  5747. }
  5748. }
  5749. }
  5750. }
  5751. }
  5752. }
  5753. parser.addListener("startrule", startRule);
  5754. parser.addListener("startfontface", startRule);
  5755. parser.addListener("startpage", startRule);
  5756. parser.addListener("startpagemargin", startRule);
  5757. parser.addListener("startkeyframerule", startRule);
  5758. parser.addListener("property", function(event){
  5759. var name = event.property.text.toLowerCase();
  5760. if (heightProperties[name] || widthProperties[name]){
  5761. if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
  5762. properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
  5763. }
  5764. } else {
  5765. if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
  5766. properties[name] = 1;
  5767. } else if (name == "box-sizing") {
  5768. boxSizing = true;
  5769. }
  5770. }
  5771. });
  5772. parser.addListener("endrule", endRule);
  5773. parser.addListener("endfontface", endRule);
  5774. parser.addListener("endpage", endRule);
  5775. parser.addListener("endpagemargin", endRule);
  5776. parser.addListener("endkeyframerule", endRule);
  5777. }
  5778. });
  5779. CSSLint.addRule({
  5780. id: "box-sizing",
  5781. name: "Disallow use of box-sizing",
  5782. desc: "The box-sizing properties isn't supported in IE6 and IE7.",
  5783. browsers: "IE6, IE7",
  5784. tags: ["Compatibility"],
  5785. init: function(parser, reporter){
  5786. var rule = this;
  5787. parser.addListener("property", function(event){
  5788. var name = event.property.text.toLowerCase();
  5789. if (name == "box-sizing"){
  5790. reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
  5791. }
  5792. });
  5793. }
  5794. });
  5795. CSSLint.addRule({
  5796. id: "bulletproof-font-face",
  5797. name: "Use the bulletproof @font-face syntax",
  5798. desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",
  5799. browsers: "All",
  5800. init: function(parser, reporter){
  5801. var rule = this,
  5802. count = 0,
  5803. fontFaceRule = false,
  5804. firstSrc = true,
  5805. ruleFailed = false,
  5806. line, col;
  5807. parser.addListener("startfontface", function(event){
  5808. fontFaceRule = true;
  5809. });
  5810. parser.addListener("property", function(event){
  5811. if (!fontFaceRule) {
  5812. return;
  5813. }
  5814. var propertyName = event.property.toString().toLowerCase(),
  5815. value = event.value.toString();
  5816. line = event.line;
  5817. col = event.col;
  5818. if (propertyName === 'src') {
  5819. var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
  5820. if (!value.match(regex) && firstSrc) {
  5821. ruleFailed = true;
  5822. firstSrc = false;
  5823. } else if (value.match(regex) && !firstSrc) {
  5824. ruleFailed = false;
  5825. }
  5826. }
  5827. });
  5828. parser.addListener("endfontface", function(event){
  5829. fontFaceRule = false;
  5830. if (ruleFailed) {
  5831. reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
  5832. }
  5833. });
  5834. }
  5835. });
  5836. CSSLint.addRule({
  5837. id: "compatible-vendor-prefixes",
  5838. name: "Require compatible vendor prefixes",
  5839. desc: "Include all compatible vendor prefixes to reach a wider range of users.",
  5840. browsers: "All",
  5841. init: function (parser, reporter) {
  5842. var rule = this,
  5843. compatiblePrefixes,
  5844. properties,
  5845. prop,
  5846. variations,
  5847. prefixed,
  5848. i,
  5849. len,
  5850. inKeyFrame = false,
  5851. arrayPush = Array.prototype.push,
  5852. applyTo = [];
  5853. compatiblePrefixes = {
  5854. "animation" : "webkit moz",
  5855. "animation-delay" : "webkit moz",
  5856. "animation-direction" : "webkit moz",
  5857. "animation-duration" : "webkit moz",
  5858. "animation-fill-mode" : "webkit moz",
  5859. "animation-iteration-count" : "webkit moz",
  5860. "animation-name" : "webkit moz",
  5861. "animation-play-state" : "webkit moz",
  5862. "animation-timing-function" : "webkit moz",
  5863. "appearance" : "webkit moz",
  5864. "border-end" : "webkit moz",
  5865. "border-end-color" : "webkit moz",
  5866. "border-end-style" : "webkit moz",
  5867. "border-end-width" : "webkit moz",
  5868. "border-image" : "webkit moz o",
  5869. "border-radius" : "webkit",
  5870. "border-start" : "webkit moz",
  5871. "border-start-color" : "webkit moz",
  5872. "border-start-style" : "webkit moz",
  5873. "border-start-width" : "webkit moz",
  5874. "box-align" : "webkit moz ms",
  5875. "box-direction" : "webkit moz ms",
  5876. "box-flex" : "webkit moz ms",
  5877. "box-lines" : "webkit ms",
  5878. "box-ordinal-group" : "webkit moz ms",
  5879. "box-orient" : "webkit moz ms",
  5880. "box-pack" : "webkit moz ms",
  5881. "box-sizing" : "webkit moz",
  5882. "box-shadow" : "webkit moz",
  5883. "column-count" : "webkit moz ms",
  5884. "column-gap" : "webkit moz ms",
  5885. "column-rule" : "webkit moz ms",
  5886. "column-rule-color" : "webkit moz ms",
  5887. "column-rule-style" : "webkit moz ms",
  5888. "column-rule-width" : "webkit moz ms",
  5889. "column-width" : "webkit moz ms",
  5890. "hyphens" : "epub moz",
  5891. "line-break" : "webkit ms",
  5892. "margin-end" : "webkit moz",
  5893. "margin-start" : "webkit moz",
  5894. "marquee-speed" : "webkit wap",
  5895. "marquee-style" : "webkit wap",
  5896. "padding-end" : "webkit moz",
  5897. "padding-start" : "webkit moz",
  5898. "tab-size" : "moz o",
  5899. "text-size-adjust" : "webkit ms",
  5900. "transform" : "webkit moz ms o",
  5901. "transform-origin" : "webkit moz ms o",
  5902. "transition" : "webkit moz o",
  5903. "transition-delay" : "webkit moz o",
  5904. "transition-duration" : "webkit moz o",
  5905. "transition-property" : "webkit moz o",
  5906. "transition-timing-function" : "webkit moz o",
  5907. "user-modify" : "webkit moz",
  5908. "user-select" : "webkit moz ms",
  5909. "word-break" : "epub ms",
  5910. "writing-mode" : "epub ms"
  5911. };
  5912. for (prop in compatiblePrefixes) {
  5913. if (compatiblePrefixes.hasOwnProperty(prop)) {
  5914. variations = [];
  5915. prefixed = compatiblePrefixes[prop].split(' ');
  5916. for (i = 0, len = prefixed.length; i < len; i++) {
  5917. variations.push('-' + prefixed[i] + '-' + prop);
  5918. }
  5919. compatiblePrefixes[prop] = variations;
  5920. arrayPush.apply(applyTo, variations);
  5921. }
  5922. }
  5923. parser.addListener("startrule", function () {
  5924. properties = [];
  5925. });
  5926. parser.addListener("startkeyframes", function (event) {
  5927. inKeyFrame = event.prefix || true;
  5928. });
  5929. parser.addListener("endkeyframes", function (event) {
  5930. inKeyFrame = false;
  5931. });
  5932. parser.addListener("property", function (event) {
  5933. var name = event.property;
  5934. if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
  5935. if (!inKeyFrame || typeof inKeyFrame != "string" ||
  5936. name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
  5937. properties.push(name);
  5938. }
  5939. }
  5940. });
  5941. parser.addListener("endrule", function (event) {
  5942. if (!properties.length) {
  5943. return;
  5944. }
  5945. var propertyGroups = {},
  5946. i,
  5947. len,
  5948. name,
  5949. prop,
  5950. variations,
  5951. value,
  5952. full,
  5953. actual,
  5954. item,
  5955. propertiesSpecified;
  5956. for (i = 0, len = properties.length; i < len; i++) {
  5957. name = properties[i];
  5958. for (prop in compatiblePrefixes) {
  5959. if (compatiblePrefixes.hasOwnProperty(prop)) {
  5960. variations = compatiblePrefixes[prop];
  5961. if (CSSLint.Util.indexOf(variations, name.text) > -1) {
  5962. if (!propertyGroups[prop]) {
  5963. propertyGroups[prop] = {
  5964. full : variations.slice(0),
  5965. actual : [],
  5966. actualNodes: []
  5967. };
  5968. }
  5969. if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
  5970. propertyGroups[prop].actual.push(name.text);
  5971. propertyGroups[prop].actualNodes.push(name);
  5972. }
  5973. }
  5974. }
  5975. }
  5976. }
  5977. for (prop in propertyGroups) {
  5978. if (propertyGroups.hasOwnProperty(prop)) {
  5979. value = propertyGroups[prop];
  5980. full = value.full;
  5981. actual = value.actual;
  5982. if (full.length > actual.length) {
  5983. for (i = 0, len = full.length; i < len; i++) {
  5984. item = full[i];
  5985. if (CSSLint.Util.indexOf(actual, item) === -1) {
  5986. propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
  5987. reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
  5988. }
  5989. }
  5990. }
  5991. }
  5992. }
  5993. });
  5994. }
  5995. });
  5996. CSSLint.addRule({
  5997. id: "display-property-grouping",
  5998. name: "Require properties appropriate for display",
  5999. desc: "Certain properties shouldn't be used with certain display property values.",
  6000. browsers: "All",
  6001. init: function(parser, reporter){
  6002. var rule = this;
  6003. var propertiesToCheck = {
  6004. display: 1,
  6005. "float": "none",
  6006. height: 1,
  6007. width: 1,
  6008. margin: 1,
  6009. "margin-left": 1,
  6010. "margin-right": 1,
  6011. "margin-bottom": 1,
  6012. "margin-top": 1,
  6013. padding: 1,
  6014. "padding-left": 1,
  6015. "padding-right": 1,
  6016. "padding-bottom": 1,
  6017. "padding-top": 1,
  6018. "vertical-align": 1
  6019. },
  6020. properties;
  6021. function reportProperty(name, display, msg){
  6022. if (properties[name]){
  6023. if (typeof propertiesToCheck[name] != "string" || properties[name].value.toLowerCase() != propertiesToCheck[name]){
  6024. reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
  6025. }
  6026. }
  6027. }
  6028. function startRule(){
  6029. properties = {};
  6030. }
  6031. function endRule(){
  6032. var display = properties.display ? properties.display.value : null;
  6033. if (display){
  6034. switch(display){
  6035. case "inline":
  6036. reportProperty("height", display);
  6037. reportProperty("width", display);
  6038. reportProperty("margin", display);
  6039. reportProperty("margin-top", display);
  6040. reportProperty("margin-bottom", display);
  6041. reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
  6042. break;
  6043. case "block":
  6044. reportProperty("vertical-align", display);
  6045. break;
  6046. case "inline-block":
  6047. reportProperty("float", display);
  6048. break;
  6049. default:
  6050. if (display.indexOf("table-") === 0){
  6051. reportProperty("margin", display);
  6052. reportProperty("margin-left", display);
  6053. reportProperty("margin-right", display);
  6054. reportProperty("margin-top", display);
  6055. reportProperty("margin-bottom", display);
  6056. reportProperty("float", display);
  6057. }
  6058. }
  6059. }
  6060. }
  6061. parser.addListener("startrule", startRule);
  6062. parser.addListener("startfontface", startRule);
  6063. parser.addListener("startkeyframerule", startRule);
  6064. parser.addListener("startpagemargin", startRule);
  6065. parser.addListener("startpage", startRule);
  6066. parser.addListener("property", function(event){
  6067. var name = event.property.text.toLowerCase();
  6068. if (propertiesToCheck[name]){
  6069. properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
  6070. }
  6071. });
  6072. parser.addListener("endrule", endRule);
  6073. parser.addListener("endfontface", endRule);
  6074. parser.addListener("endkeyframerule", endRule);
  6075. parser.addListener("endpagemargin", endRule);
  6076. parser.addListener("endpage", endRule);
  6077. }
  6078. });
  6079. CSSLint.addRule({
  6080. id: "duplicate-background-images",
  6081. name: "Disallow duplicate background images",
  6082. desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
  6083. browsers: "All",
  6084. init: function(parser, reporter){
  6085. var rule = this,
  6086. stack = {};
  6087. parser.addListener("property", function(event){
  6088. var name = event.property.text,
  6089. value = event.value,
  6090. i, len;
  6091. if (name.match(/background/i)) {
  6092. for (i=0, len=value.parts.length; i < len; i++) {
  6093. if (value.parts[i].type == 'uri') {
  6094. if (typeof stack[value.parts[i].uri] === 'undefined') {
  6095. stack[value.parts[i].uri] = event;
  6096. }
  6097. else {
  6098. 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);
  6099. }
  6100. }
  6101. }
  6102. }
  6103. });
  6104. }
  6105. });
  6106. CSSLint.addRule({
  6107. id: "duplicate-properties",
  6108. name: "Disallow duplicate properties",
  6109. desc: "Duplicate properties must appear one after the other.",
  6110. browsers: "All",
  6111. init: function(parser, reporter){
  6112. var rule = this,
  6113. properties,
  6114. lastProperty;
  6115. function startRule(event){
  6116. properties = {};
  6117. }
  6118. parser.addListener("startrule", startRule);
  6119. parser.addListener("startfontface", startRule);
  6120. parser.addListener("startpage", startRule);
  6121. parser.addListener("startpagemargin", startRule);
  6122. parser.addListener("startkeyframerule", startRule);
  6123. parser.addListener("property", function(event){
  6124. var property = event.property,
  6125. name = property.text.toLowerCase();
  6126. if (properties[name] && (lastProperty != name || properties[name] == event.value.text)){
  6127. reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
  6128. }
  6129. properties[name] = event.value.text;
  6130. lastProperty = name;
  6131. });
  6132. }
  6133. });
  6134. CSSLint.addRule({
  6135. id: "empty-rules",
  6136. name: "Disallow empty rules",
  6137. desc: "Rules without any properties specified should be removed.",
  6138. browsers: "All",
  6139. init: function(parser, reporter){
  6140. var rule = this,
  6141. count = 0;
  6142. parser.addListener("startrule", function(){
  6143. count=0;
  6144. });
  6145. parser.addListener("property", function(){
  6146. count++;
  6147. });
  6148. parser.addListener("endrule", function(event){
  6149. var selectors = event.selectors;
  6150. if (count === 0){
  6151. reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
  6152. }
  6153. });
  6154. }
  6155. });
  6156. CSSLint.addRule({
  6157. id: "errors",
  6158. name: "Parsing Errors",
  6159. desc: "This rule looks for recoverable syntax errors.",
  6160. browsers: "All",
  6161. init: function(parser, reporter){
  6162. var rule = this;
  6163. parser.addListener("error", function(event){
  6164. reporter.error(event.message, event.line, event.col, rule);
  6165. });
  6166. }
  6167. });
  6168. CSSLint.addRule({
  6169. id: "fallback-colors",
  6170. name: "Require fallback colors",
  6171. desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
  6172. browsers: "IE6,IE7,IE8",
  6173. init: function(parser, reporter){
  6174. var rule = this,
  6175. lastProperty,
  6176. propertiesToCheck = {
  6177. color: 1,
  6178. background: 1,
  6179. "border-color": 1,
  6180. "border-top-color": 1,
  6181. "border-right-color": 1,
  6182. "border-bottom-color": 1,
  6183. "border-left-color": 1,
  6184. border: 1,
  6185. "border-top": 1,
  6186. "border-right": 1,
  6187. "border-bottom": 1,
  6188. "border-left": 1,
  6189. "background-color": 1
  6190. },
  6191. properties;
  6192. function startRule(event){
  6193. properties = {};
  6194. lastProperty = null;
  6195. }
  6196. parser.addListener("startrule", startRule);
  6197. parser.addListener("startfontface", startRule);
  6198. parser.addListener("startpage", startRule);
  6199. parser.addListener("startpagemargin", startRule);
  6200. parser.addListener("startkeyframerule", startRule);
  6201. parser.addListener("property", function(event){
  6202. var property = event.property,
  6203. name = property.text.toLowerCase(),
  6204. parts = event.value.parts,
  6205. i = 0,
  6206. colorType = "",
  6207. len = parts.length;
  6208. if(propertiesToCheck[name]){
  6209. while(i < len){
  6210. if (parts[i].type == "color"){
  6211. if ("alpha" in parts[i] || "hue" in parts[i]){
  6212. if (/([^\)]+)\(/.test(parts[i])){
  6213. colorType = RegExp.$1.toUpperCase();
  6214. }
  6215. if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != "compat")){
  6216. reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
  6217. }
  6218. } else {
  6219. event.colorType = "compat";
  6220. }
  6221. }
  6222. i++;
  6223. }
  6224. }
  6225. lastProperty = event;
  6226. });
  6227. }
  6228. });
  6229. CSSLint.addRule({
  6230. id: "floats",
  6231. name: "Disallow too many floats",
  6232. desc: "This rule tests if the float property is used too many times",
  6233. browsers: "All",
  6234. init: function(parser, reporter){
  6235. var rule = this;
  6236. var count = 0;
  6237. parser.addListener("property", function(event){
  6238. if (event.property.text.toLowerCase() == "float" &&
  6239. event.value.text.toLowerCase() != "none"){
  6240. count++;
  6241. }
  6242. });
  6243. parser.addListener("endstylesheet", function(){
  6244. reporter.stat("floats", count);
  6245. if (count >= 10){
  6246. reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
  6247. }
  6248. });
  6249. }
  6250. });
  6251. CSSLint.addRule({
  6252. id: "font-faces",
  6253. name: "Don't use too many web fonts",
  6254. desc: "Too many different web fonts in the same stylesheet.",
  6255. browsers: "All",
  6256. init: function(parser, reporter){
  6257. var rule = this,
  6258. count = 0;
  6259. parser.addListener("startfontface", function(){
  6260. count++;
  6261. });
  6262. parser.addListener("endstylesheet", function(){
  6263. if (count > 5){
  6264. reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
  6265. }
  6266. });
  6267. }
  6268. });
  6269. CSSLint.addRule({
  6270. id: "font-sizes",
  6271. name: "Disallow too many font sizes",
  6272. desc: "Checks the number of font-size declarations.",
  6273. browsers: "All",
  6274. init: function(parser, reporter){
  6275. var rule = this,
  6276. count = 0;
  6277. parser.addListener("property", function(event){
  6278. if (event.property == "font-size"){
  6279. count++;
  6280. }
  6281. });
  6282. parser.addListener("endstylesheet", function(){
  6283. reporter.stat("font-sizes", count);
  6284. if (count >= 10){
  6285. reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
  6286. }
  6287. });
  6288. }
  6289. });
  6290. CSSLint.addRule({
  6291. id: "gradients",
  6292. name: "Require all gradient definitions",
  6293. desc: "When using a vendor-prefixed gradient, make sure to use them all.",
  6294. browsers: "All",
  6295. init: function(parser, reporter){
  6296. var rule = this,
  6297. gradients;
  6298. parser.addListener("startrule", function(){
  6299. gradients = {
  6300. moz: 0,
  6301. webkit: 0,
  6302. oldWebkit: 0,
  6303. o: 0
  6304. };
  6305. });
  6306. parser.addListener("property", function(event){
  6307. if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
  6308. gradients[RegExp.$1] = 1;
  6309. } else if (/\-webkit\-gradient/i.test(event.value)){
  6310. gradients.oldWebkit = 1;
  6311. }
  6312. });
  6313. parser.addListener("endrule", function(event){
  6314. var missing = [];
  6315. if (!gradients.moz){
  6316. missing.push("Firefox 3.6+");
  6317. }
  6318. if (!gradients.webkit){
  6319. missing.push("Webkit (Safari 5+, Chrome)");
  6320. }
  6321. if (!gradients.oldWebkit){
  6322. missing.push("Old Webkit (Safari 4+, Chrome)");
  6323. }
  6324. if (!gradients.o){
  6325. missing.push("Opera 11.1+");
  6326. }
  6327. if (missing.length && missing.length < 4){
  6328. reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
  6329. }
  6330. });
  6331. }
  6332. });
  6333. CSSLint.addRule({
  6334. id: "ids",
  6335. name: "Disallow IDs in selectors",
  6336. desc: "Selectors should not contain IDs.",
  6337. browsers: "All",
  6338. init: function(parser, reporter){
  6339. var rule = this;
  6340. parser.addListener("startrule", function(event){
  6341. var selectors = event.selectors,
  6342. selector,
  6343. part,
  6344. modifier,
  6345. idCount,
  6346. i, j, k;
  6347. for (i=0; i < selectors.length; i++){
  6348. selector = selectors[i];
  6349. idCount = 0;
  6350. for (j=0; j < selector.parts.length; j++){
  6351. part = selector.parts[j];
  6352. if (part.type == parser.SELECTOR_PART_TYPE){
  6353. for (k=0; k < part.modifiers.length; k++){
  6354. modifier = part.modifiers[k];
  6355. if (modifier.type == "id"){
  6356. idCount++;
  6357. }
  6358. }
  6359. }
  6360. }
  6361. if (idCount == 1){
  6362. reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
  6363. } else if (idCount > 1){
  6364. reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
  6365. }
  6366. }
  6367. });
  6368. }
  6369. });
  6370. CSSLint.addRule({
  6371. id: "import",
  6372. name: "Disallow @import",
  6373. desc: "Don't use @import, use <link> instead.",
  6374. browsers: "All",
  6375. init: function(parser, reporter){
  6376. var rule = this;
  6377. parser.addListener("import", function(event){
  6378. reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
  6379. });
  6380. }
  6381. });
  6382. CSSLint.addRule({
  6383. id: "important",
  6384. name: "Disallow !important",
  6385. desc: "Be careful when using !important declaration",
  6386. browsers: "All",
  6387. init: function(parser, reporter){
  6388. var rule = this,
  6389. count = 0;
  6390. parser.addListener("property", function(event){
  6391. if (event.important === true){
  6392. count++;
  6393. reporter.report("Use of !important", event.line, event.col, rule);
  6394. }
  6395. });
  6396. parser.addListener("endstylesheet", function(){
  6397. reporter.stat("important", count);
  6398. if (count >= 10){
  6399. reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
  6400. }
  6401. });
  6402. }
  6403. });
  6404. CSSLint.addRule({
  6405. id: "known-properties",
  6406. name: "Require use of known properties",
  6407. desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
  6408. browsers: "All",
  6409. init: function(parser, reporter){
  6410. var rule = this;
  6411. parser.addListener("property", function(event){
  6412. var name = event.property.text.toLowerCase();
  6413. if (event.invalid) {
  6414. reporter.report(event.invalid.message, event.line, event.col, rule);
  6415. }
  6416. });
  6417. }
  6418. });
  6419. CSSLint.addRule({
  6420. id: "outline-none",
  6421. name: "Disallow outline: none",
  6422. desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
  6423. browsers: "All",
  6424. tags: ["Accessibility"],
  6425. init: function(parser, reporter){
  6426. var rule = this,
  6427. lastRule;
  6428. function startRule(event){
  6429. if (event.selectors){
  6430. lastRule = {
  6431. line: event.line,
  6432. col: event.col,
  6433. selectors: event.selectors,
  6434. propCount: 0,
  6435. outline: false
  6436. };
  6437. } else {
  6438. lastRule = null;
  6439. }
  6440. }
  6441. function endRule(event){
  6442. if (lastRule){
  6443. if (lastRule.outline){
  6444. if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") == -1){
  6445. reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
  6446. } else if (lastRule.propCount == 1) {
  6447. reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
  6448. }
  6449. }
  6450. }
  6451. }
  6452. parser.addListener("startrule", startRule);
  6453. parser.addListener("startfontface", startRule);
  6454. parser.addListener("startpage", startRule);
  6455. parser.addListener("startpagemargin", startRule);
  6456. parser.addListener("startkeyframerule", startRule);
  6457. parser.addListener("property", function(event){
  6458. var name = event.property.text.toLowerCase(),
  6459. value = event.value;
  6460. if (lastRule){
  6461. lastRule.propCount++;
  6462. if (name == "outline" && (value == "none" || value == "0")){
  6463. lastRule.outline = true;
  6464. }
  6465. }
  6466. });
  6467. parser.addListener("endrule", endRule);
  6468. parser.addListener("endfontface", endRule);
  6469. parser.addListener("endpage", endRule);
  6470. parser.addListener("endpagemargin", endRule);
  6471. parser.addListener("endkeyframerule", endRule);
  6472. }
  6473. });
  6474. CSSLint.addRule({
  6475. id: "overqualified-elements",
  6476. name: "Disallow overqualified elements",
  6477. desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
  6478. browsers: "All",
  6479. init: function(parser, reporter){
  6480. var rule = this,
  6481. classes = {};
  6482. parser.addListener("startrule", function(event){
  6483. var selectors = event.selectors,
  6484. selector,
  6485. part,
  6486. modifier,
  6487. i, j, k;
  6488. for (i=0; i < selectors.length; i++){
  6489. selector = selectors[i];
  6490. for (j=0; j < selector.parts.length; j++){
  6491. part = selector.parts[j];
  6492. if (part.type == parser.SELECTOR_PART_TYPE){
  6493. for (k=0; k < part.modifiers.length; k++){
  6494. modifier = part.modifiers[k];
  6495. if (part.elementName && modifier.type == "id"){
  6496. reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
  6497. } else if (modifier.type == "class"){
  6498. if (!classes[modifier]){
  6499. classes[modifier] = [];
  6500. }
  6501. classes[modifier].push({ modifier: modifier, part: part });
  6502. }
  6503. }
  6504. }
  6505. }
  6506. }
  6507. });
  6508. parser.addListener("endstylesheet", function(){
  6509. var prop;
  6510. for (prop in classes){
  6511. if (classes.hasOwnProperty(prop)){
  6512. if (classes[prop].length == 1 && classes[prop][0].part.elementName){
  6513. 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);
  6514. }
  6515. }
  6516. }
  6517. });
  6518. }
  6519. });
  6520. CSSLint.addRule({
  6521. id: "qualified-headings",
  6522. name: "Disallow qualified headings",
  6523. desc: "Headings should not be qualified (namespaced).",
  6524. browsers: "All",
  6525. init: function(parser, reporter){
  6526. var rule = this;
  6527. parser.addListener("startrule", function(event){
  6528. var selectors = event.selectors,
  6529. selector,
  6530. part,
  6531. i, j;
  6532. for (i=0; i < selectors.length; i++){
  6533. selector = selectors[i];
  6534. for (j=0; j < selector.parts.length; j++){
  6535. part = selector.parts[j];
  6536. if (part.type == parser.SELECTOR_PART_TYPE){
  6537. if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
  6538. reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
  6539. }
  6540. }
  6541. }
  6542. }
  6543. });
  6544. }
  6545. });
  6546. CSSLint.addRule({
  6547. id: "regex-selectors",
  6548. name: "Disallow selectors that look like regexs",
  6549. desc: "Selectors that look like regular expressions are slow and should be avoided.",
  6550. browsers: "All",
  6551. init: function(parser, reporter){
  6552. var rule = this;
  6553. parser.addListener("startrule", function(event){
  6554. var selectors = event.selectors,
  6555. selector,
  6556. part,
  6557. modifier,
  6558. i, j, k;
  6559. for (i=0; i < selectors.length; i++){
  6560. selector = selectors[i];
  6561. for (j=0; j < selector.parts.length; j++){
  6562. part = selector.parts[j];
  6563. if (part.type == parser.SELECTOR_PART_TYPE){
  6564. for (k=0; k < part.modifiers.length; k++){
  6565. modifier = part.modifiers[k];
  6566. if (modifier.type == "attribute"){
  6567. if (/([\~\|\^\$\*]=)/.test(modifier)){
  6568. reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
  6569. }
  6570. }
  6571. }
  6572. }
  6573. }
  6574. }
  6575. });
  6576. }
  6577. });
  6578. CSSLint.addRule({
  6579. id: "rules-count",
  6580. name: "Rules Count",
  6581. desc: "Track how many rules there are.",
  6582. browsers: "All",
  6583. init: function(parser, reporter){
  6584. var rule = this,
  6585. count = 0;
  6586. parser.addListener("startrule", function(){
  6587. count++;
  6588. });
  6589. parser.addListener("endstylesheet", function(){
  6590. reporter.stat("rule-count", count);
  6591. });
  6592. }
  6593. });
  6594. CSSLint.addRule({
  6595. id: "selector-max-approaching",
  6596. name: "Warn when approaching the 4095 selector limit for IE",
  6597. desc: "Will warn when selector count is >= 3800 selectors.",
  6598. browsers: "IE",
  6599. init: function(parser, reporter) {
  6600. var rule = this, count = 0;
  6601. parser.addListener('startrule', function(event) {
  6602. count += event.selectors.length;
  6603. });
  6604. parser.addListener("endstylesheet", function() {
  6605. if (count >= 3800) {
  6606. reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
  6607. }
  6608. });
  6609. }
  6610. });
  6611. CSSLint.addRule({
  6612. id: "selector-max",
  6613. name: "Error when past the 4095 selector limit for IE",
  6614. desc: "Will error when selector count is > 4095.",
  6615. browsers: "IE",
  6616. init: function(parser, reporter){
  6617. var rule = this, count = 0;
  6618. parser.addListener('startrule',function(event) {
  6619. count += event.selectors.length;
  6620. });
  6621. parser.addListener("endstylesheet", function() {
  6622. if (count > 4095) {
  6623. reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
  6624. }
  6625. });
  6626. }
  6627. });
  6628. CSSLint.addRule({
  6629. id: "shorthand",
  6630. name: "Require shorthand properties",
  6631. desc: "Use shorthand properties where possible.",
  6632. browsers: "All",
  6633. init: function(parser, reporter){
  6634. var rule = this,
  6635. prop, i, len,
  6636. propertiesToCheck = {},
  6637. properties,
  6638. mapping = {
  6639. "margin": [
  6640. "margin-top",
  6641. "margin-bottom",
  6642. "margin-left",
  6643. "margin-right"
  6644. ],
  6645. "padding": [
  6646. "padding-top",
  6647. "padding-bottom",
  6648. "padding-left",
  6649. "padding-right"
  6650. ]
  6651. };
  6652. for (prop in mapping){
  6653. if (mapping.hasOwnProperty(prop)){
  6654. for (i=0, len=mapping[prop].length; i < len; i++){
  6655. propertiesToCheck[mapping[prop][i]] = prop;
  6656. }
  6657. }
  6658. }
  6659. function startRule(event){
  6660. properties = {};
  6661. }
  6662. function endRule(event){
  6663. var prop, i, len, total;
  6664. for (prop in mapping){
  6665. if (mapping.hasOwnProperty(prop)){
  6666. total=0;
  6667. for (i=0, len=mapping[prop].length; i < len; i++){
  6668. total += properties[mapping[prop][i]] ? 1 : 0;
  6669. }
  6670. if (total == mapping[prop].length){
  6671. reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
  6672. }
  6673. }
  6674. }
  6675. }
  6676. parser.addListener("startrule", startRule);
  6677. parser.addListener("startfontface", startRule);
  6678. parser.addListener("property", function(event){
  6679. var name = event.property.toString().toLowerCase(),
  6680. value = event.value.parts[0].value;
  6681. if (propertiesToCheck[name]){
  6682. properties[name] = 1;
  6683. }
  6684. });
  6685. parser.addListener("endrule", endRule);
  6686. parser.addListener("endfontface", endRule);
  6687. }
  6688. });
  6689. CSSLint.addRule({
  6690. id: "star-property-hack",
  6691. name: "Disallow properties with a star prefix",
  6692. desc: "Checks for the star property hack (targets IE6/7)",
  6693. browsers: "All",
  6694. init: function(parser, reporter){
  6695. var rule = this;
  6696. parser.addListener("property", function(event){
  6697. var property = event.property;
  6698. if (property.hack == "*") {
  6699. reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
  6700. }
  6701. });
  6702. }
  6703. });
  6704. CSSLint.addRule({
  6705. id: "text-indent",
  6706. name: "Disallow negative text-indent",
  6707. desc: "Checks for text indent less than -99px",
  6708. browsers: "All",
  6709. init: function(parser, reporter){
  6710. var rule = this,
  6711. textIndent,
  6712. direction;
  6713. function startRule(event){
  6714. textIndent = false;
  6715. direction = "inherit";
  6716. }
  6717. function endRule(event){
  6718. if (textIndent && direction != "ltr"){
  6719. 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);
  6720. }
  6721. }
  6722. parser.addListener("startrule", startRule);
  6723. parser.addListener("startfontface", startRule);
  6724. parser.addListener("property", function(event){
  6725. var name = event.property.toString().toLowerCase(),
  6726. value = event.value;
  6727. if (name == "text-indent" && value.parts[0].value < -99){
  6728. textIndent = event.property;
  6729. } else if (name == "direction" && value == "ltr"){
  6730. direction = "ltr";
  6731. }
  6732. });
  6733. parser.addListener("endrule", endRule);
  6734. parser.addListener("endfontface", endRule);
  6735. }
  6736. });
  6737. CSSLint.addRule({
  6738. id: "underscore-property-hack",
  6739. name: "Disallow properties with an underscore prefix",
  6740. desc: "Checks for the underscore property hack (targets IE6)",
  6741. browsers: "All",
  6742. init: function(parser, reporter){
  6743. var rule = this;
  6744. parser.addListener("property", function(event){
  6745. var property = event.property;
  6746. if (property.hack == "_") {
  6747. reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
  6748. }
  6749. });
  6750. }
  6751. });
  6752. CSSLint.addRule({
  6753. id: "unique-headings",
  6754. name: "Headings should only be defined once",
  6755. desc: "Headings should be defined only once.",
  6756. browsers: "All",
  6757. init: function(parser, reporter){
  6758. var rule = this;
  6759. var headings = {
  6760. h1: 0,
  6761. h2: 0,
  6762. h3: 0,
  6763. h4: 0,
  6764. h5: 0,
  6765. h6: 0
  6766. };
  6767. parser.addListener("startrule", function(event){
  6768. var selectors = event.selectors,
  6769. selector,
  6770. part,
  6771. pseudo,
  6772. i, j;
  6773. for (i=0; i < selectors.length; i++){
  6774. selector = selectors[i];
  6775. part = selector.parts[selector.parts.length-1];
  6776. if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){
  6777. for (j=0; j < part.modifiers.length; j++){
  6778. if (part.modifiers[j].type == "pseudo"){
  6779. pseudo = true;
  6780. break;
  6781. }
  6782. }
  6783. if (!pseudo){
  6784. headings[RegExp.$1]++;
  6785. if (headings[RegExp.$1] > 1) {
  6786. reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
  6787. }
  6788. }
  6789. }
  6790. }
  6791. });
  6792. parser.addListener("endstylesheet", function(event){
  6793. var prop,
  6794. messages = [];
  6795. for (prop in headings){
  6796. if (headings.hasOwnProperty(prop)){
  6797. if (headings[prop] > 1){
  6798. messages.push(headings[prop] + " " + prop + "s");
  6799. }
  6800. }
  6801. }
  6802. if (messages.length){
  6803. reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
  6804. }
  6805. });
  6806. }
  6807. });
  6808. CSSLint.addRule({
  6809. id: "universal-selector",
  6810. name: "Disallow universal selector",
  6811. desc: "The universal selector (*) is known to be slow.",
  6812. browsers: "All",
  6813. init: function(parser, reporter){
  6814. var rule = this;
  6815. parser.addListener("startrule", function(event){
  6816. var selectors = event.selectors,
  6817. selector,
  6818. part,
  6819. modifier,
  6820. i, j, k;
  6821. for (i=0; i < selectors.length; i++){
  6822. selector = selectors[i];
  6823. part = selector.parts[selector.parts.length-1];
  6824. if (part.elementName == "*"){
  6825. reporter.report(rule.desc, part.line, part.col, rule);
  6826. }
  6827. }
  6828. });
  6829. }
  6830. });
  6831. CSSLint.addRule({
  6832. id: "unqualified-attributes",
  6833. name: "Disallow unqualified attribute selectors",
  6834. desc: "Unqualified attribute selectors are known to be slow.",
  6835. browsers: "All",
  6836. init: function(parser, reporter){
  6837. var rule = this;
  6838. parser.addListener("startrule", function(event){
  6839. var selectors = event.selectors,
  6840. selector,
  6841. part,
  6842. modifier,
  6843. i, j, k;
  6844. for (i=0; i < selectors.length; i++){
  6845. selector = selectors[i];
  6846. part = selector.parts[selector.parts.length-1];
  6847. if (part.type == parser.SELECTOR_PART_TYPE){
  6848. for (k=0; k < part.modifiers.length; k++){
  6849. modifier = part.modifiers[k];
  6850. if (modifier.type == "attribute" && (!part.elementName || part.elementName == "*")){
  6851. reporter.report(rule.desc, part.line, part.col, rule);
  6852. }
  6853. }
  6854. }
  6855. }
  6856. });
  6857. }
  6858. });
  6859. CSSLint.addRule({
  6860. id: "vendor-prefix",
  6861. name: "Require standard property with vendor prefix",
  6862. desc: "When using a vendor-prefixed property, make sure to include the standard one.",
  6863. browsers: "All",
  6864. init: function(parser, reporter){
  6865. var rule = this,
  6866. properties,
  6867. num,
  6868. propertiesToCheck = {
  6869. "-webkit-border-radius": "border-radius",
  6870. "-webkit-border-top-left-radius": "border-top-left-radius",
  6871. "-webkit-border-top-right-radius": "border-top-right-radius",
  6872. "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
  6873. "-webkit-border-bottom-right-radius": "border-bottom-right-radius",
  6874. "-o-border-radius": "border-radius",
  6875. "-o-border-top-left-radius": "border-top-left-radius",
  6876. "-o-border-top-right-radius": "border-top-right-radius",
  6877. "-o-border-bottom-left-radius": "border-bottom-left-radius",
  6878. "-o-border-bottom-right-radius": "border-bottom-right-radius",
  6879. "-moz-border-radius": "border-radius",
  6880. "-moz-border-radius-topleft": "border-top-left-radius",
  6881. "-moz-border-radius-topright": "border-top-right-radius",
  6882. "-moz-border-radius-bottomleft": "border-bottom-left-radius",
  6883. "-moz-border-radius-bottomright": "border-bottom-right-radius",
  6884. "-moz-column-count": "column-count",
  6885. "-webkit-column-count": "column-count",
  6886. "-moz-column-gap": "column-gap",
  6887. "-webkit-column-gap": "column-gap",
  6888. "-moz-column-rule": "column-rule",
  6889. "-webkit-column-rule": "column-rule",
  6890. "-moz-column-rule-style": "column-rule-style",
  6891. "-webkit-column-rule-style": "column-rule-style",
  6892. "-moz-column-rule-color": "column-rule-color",
  6893. "-webkit-column-rule-color": "column-rule-color",
  6894. "-moz-column-rule-width": "column-rule-width",
  6895. "-webkit-column-rule-width": "column-rule-width",
  6896. "-moz-column-width": "column-width",
  6897. "-webkit-column-width": "column-width",
  6898. "-webkit-column-span": "column-span",
  6899. "-webkit-columns": "columns",
  6900. "-moz-box-shadow": "box-shadow",
  6901. "-webkit-box-shadow": "box-shadow",
  6902. "-moz-transform" : "transform",
  6903. "-webkit-transform" : "transform",
  6904. "-o-transform" : "transform",
  6905. "-ms-transform" : "transform",
  6906. "-moz-transform-origin" : "transform-origin",
  6907. "-webkit-transform-origin" : "transform-origin",
  6908. "-o-transform-origin" : "transform-origin",
  6909. "-ms-transform-origin" : "transform-origin",
  6910. "-moz-box-sizing" : "box-sizing",
  6911. "-webkit-box-sizing" : "box-sizing",
  6912. "-moz-user-select" : "user-select",
  6913. "-khtml-user-select" : "user-select",
  6914. "-webkit-user-select" : "user-select"
  6915. };
  6916. function startRule(){
  6917. properties = {};
  6918. num=1;
  6919. }
  6920. function endRule(event){
  6921. var prop,
  6922. i, len,
  6923. standard,
  6924. needed,
  6925. actual,
  6926. needsStandard = [];
  6927. for (prop in properties){
  6928. if (propertiesToCheck[prop]){
  6929. needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
  6930. }
  6931. }
  6932. for (i=0, len=needsStandard.length; i < len; i++){
  6933. needed = needsStandard[i].needed;
  6934. actual = needsStandard[i].actual;
  6935. if (!properties[needed]){
  6936. reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
  6937. } else {
  6938. if (properties[needed][0].pos < properties[actual][0].pos){
  6939. reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
  6940. }
  6941. }
  6942. }
  6943. }
  6944. parser.addListener("startrule", startRule);
  6945. parser.addListener("startfontface", startRule);
  6946. parser.addListener("startpage", startRule);
  6947. parser.addListener("startpagemargin", startRule);
  6948. parser.addListener("startkeyframerule", startRule);
  6949. parser.addListener("property", function(event){
  6950. var name = event.property.text.toLowerCase();
  6951. if (!properties[name]){
  6952. properties[name] = [];
  6953. }
  6954. properties[name].push({ name: event.property, value : event.value, pos:num++ });
  6955. });
  6956. parser.addListener("endrule", endRule);
  6957. parser.addListener("endfontface", endRule);
  6958. parser.addListener("endpage", endRule);
  6959. parser.addListener("endpagemargin", endRule);
  6960. parser.addListener("endkeyframerule", endRule);
  6961. }
  6962. });
  6963. CSSLint.addRule({
  6964. id: "zero-units",
  6965. name: "Disallow units for 0 values",
  6966. desc: "You don't need to specify units when a value is 0.",
  6967. browsers: "All",
  6968. init: function(parser, reporter){
  6969. var rule = this;
  6970. parser.addListener("property", function(event){
  6971. var parts = event.value.parts,
  6972. i = 0,
  6973. len = parts.length;
  6974. while(i < len){
  6975. if ((parts[i].units || parts[i].type == "percentage") && parts[i].value === 0 && parts[i].type != "time"){
  6976. reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
  6977. }
  6978. i++;
  6979. }
  6980. });
  6981. }
  6982. });
  6983. (function() {
  6984. var xmlEscape = function(str) {
  6985. if (!str || str.constructor !== String) {
  6986. return "";
  6987. }
  6988. return str.replace(/[\"&><]/g, function(match) {
  6989. switch (match) {
  6990. case "\"":
  6991. return "&quot;";
  6992. case "&":
  6993. return "&amp;";
  6994. case "<":
  6995. return "&lt;";
  6996. case ">":
  6997. return "&gt;";
  6998. }
  6999. });
  7000. };
  7001. CSSLint.addFormatter({
  7002. id: "checkstyle-xml",
  7003. name: "Checkstyle XML format",
  7004. startFormat: function(){
  7005. return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
  7006. },
  7007. endFormat: function(){
  7008. return "</checkstyle>";
  7009. },
  7010. readError: function(filename, message) {
  7011. return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
  7012. },
  7013. formatResults: function(results, filename, options) {
  7014. var messages = results.messages,
  7015. output = [];
  7016. var generateSource = function(rule) {
  7017. if (!rule || !('name' in rule)) {
  7018. return "";
  7019. }
  7020. return 'net.csslint.' + rule.name.replace(/\s/g,'');
  7021. };
  7022. if (messages.length > 0) {
  7023. output.push("<file name=\""+filename+"\">");
  7024. CSSLint.Util.forEach(messages, function (message, i) {
  7025. if (!message.rollup) {
  7026. output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  7027. " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  7028. }
  7029. });
  7030. output.push("</file>");
  7031. }
  7032. return output.join("");
  7033. }
  7034. });
  7035. }());
  7036. CSSLint.addFormatter({
  7037. id: "compact",
  7038. name: "Compact, 'porcelain' format",
  7039. startFormat: function() {
  7040. return "";
  7041. },
  7042. endFormat: function() {
  7043. return "";
  7044. },
  7045. formatResults: function(results, filename, options) {
  7046. var messages = results.messages,
  7047. output = "";
  7048. options = options || {};
  7049. var capitalize = function(str) {
  7050. return str.charAt(0).toUpperCase() + str.slice(1);
  7051. };
  7052. if (messages.length === 0) {
  7053. return options.quiet ? "" : filename + ": Lint Free!";
  7054. }
  7055. CSSLint.Util.forEach(messages, function(message, i) {
  7056. if (message.rollup) {
  7057. output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n";
  7058. } else {
  7059. output += filename + ": " + "line " + message.line +
  7060. ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n";
  7061. }
  7062. });
  7063. return output;
  7064. }
  7065. });
  7066. CSSLint.addFormatter({
  7067. id: "csslint-xml",
  7068. name: "CSSLint XML format",
  7069. startFormat: function(){
  7070. return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
  7071. },
  7072. endFormat: function(){
  7073. return "</csslint>";
  7074. },
  7075. formatResults: function(results, filename, options) {
  7076. var messages = results.messages,
  7077. output = [];
  7078. var escapeSpecialCharacters = function(str) {
  7079. if (!str || str.constructor !== String) {
  7080. return "";
  7081. }
  7082. return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  7083. };
  7084. if (messages.length > 0) {
  7085. output.push("<file name=\""+filename+"\">");
  7086. CSSLint.Util.forEach(messages, function (message, i) {
  7087. if (message.rollup) {
  7088. output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  7089. } else {
  7090. output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  7091. " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  7092. }
  7093. });
  7094. output.push("</file>");
  7095. }
  7096. return output.join("");
  7097. }
  7098. });
  7099. CSSLint.addFormatter({
  7100. id: "junit-xml",
  7101. name: "JUNIT XML format",
  7102. startFormat: function(){
  7103. return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
  7104. },
  7105. endFormat: function() {
  7106. return "</testsuites>";
  7107. },
  7108. formatResults: function(results, filename, options) {
  7109. var messages = results.messages,
  7110. output = [],
  7111. tests = {
  7112. 'error': 0,
  7113. 'failure': 0
  7114. };
  7115. var generateSource = function(rule) {
  7116. if (!rule || !('name' in rule)) {
  7117. return "";
  7118. }
  7119. return 'net.csslint.' + rule.name.replace(/\s/g,'');
  7120. };
  7121. var escapeSpecialCharacters = function(str) {
  7122. if (!str || str.constructor !== String) {
  7123. return "";
  7124. }
  7125. return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  7126. };
  7127. if (messages.length > 0) {
  7128. messages.forEach(function (message, i) {
  7129. var type = message.type === 'warning' ? 'error' : message.type;
  7130. if (!message.rollup) {
  7131. output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
  7132. output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ':' + message.col + ':' + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">");
  7133. output.push("</testcase>");
  7134. tests[type] += 1;
  7135. }
  7136. });
  7137. output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
  7138. output.push("</testsuite>");
  7139. }
  7140. return output.join("");
  7141. }
  7142. });
  7143. CSSLint.addFormatter({
  7144. id: "lint-xml",
  7145. name: "Lint XML format",
  7146. startFormat: function(){
  7147. return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
  7148. },
  7149. endFormat: function(){
  7150. return "</lint>";
  7151. },
  7152. formatResults: function(results, filename, options) {
  7153. var messages = results.messages,
  7154. output = [];
  7155. var escapeSpecialCharacters = function(str) {
  7156. if (!str || str.constructor !== String) {
  7157. return "";
  7158. }
  7159. return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  7160. };
  7161. if (messages.length > 0) {
  7162. output.push("<file name=\""+filename+"\">");
  7163. CSSLint.Util.forEach(messages, function (message, i) {
  7164. if (message.rollup) {
  7165. output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  7166. } else {
  7167. output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  7168. " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  7169. }
  7170. });
  7171. output.push("</file>");
  7172. }
  7173. return output.join("");
  7174. }
  7175. });
  7176. CSSLint.addFormatter({
  7177. id: "text",
  7178. name: "Plain Text",
  7179. startFormat: function() {
  7180. return "";
  7181. },
  7182. endFormat: function() {
  7183. return "";
  7184. },
  7185. formatResults: function(results, filename, options) {
  7186. var messages = results.messages,
  7187. output = "";
  7188. options = options || {};
  7189. if (messages.length === 0) {
  7190. return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
  7191. }
  7192. output = "\n\ncsslint: There are " + messages.length + " problems in " + filename + ".";
  7193. var pos = filename.lastIndexOf("/"),
  7194. shortFilename = filename;
  7195. if (pos === -1){
  7196. pos = filename.lastIndexOf("\\");
  7197. }
  7198. if (pos > -1){
  7199. shortFilename = filename.substring(pos+1);
  7200. }
  7201. CSSLint.Util.forEach(messages, function (message, i) {
  7202. output = output + "\n\n" + shortFilename;
  7203. if (message.rollup) {
  7204. output += "\n" + (i+1) + ": " + message.type;
  7205. output += "\n" + message.message;
  7206. } else {
  7207. output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
  7208. output += "\n" + message.message;
  7209. output += "\n" + message.evidence;
  7210. }
  7211. });
  7212. return output;
  7213. }
  7214. });
  7215. exports.CSSLint = CSSLint;
  7216. });ace.define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
  7217. var Document = require("../document").Document;
  7218. var lang = require("../lib/lang");
  7219. var Mirror = exports.Mirror = function(sender) {
  7220. this.sender = sender;
  7221. var doc = this.doc = new Document("");
  7222. var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));
  7223. var _self = this;
  7224. sender.on("change", function(e) {
  7225. doc.applyDeltas(e.data);
  7226. if (_self.$timeout)
  7227. return deferredUpdate.schedule(_self.$timeout);
  7228. _self.onUpdate();
  7229. });
  7230. };
  7231. (function() {
  7232. this.$timeout = 500;
  7233. this.setTimeout = function(timeout) {
  7234. this.$timeout = timeout;
  7235. };
  7236. this.setValue = function(value) {
  7237. this.doc.setValue(value);
  7238. this.deferredUpdate.schedule(this.$timeout);
  7239. };
  7240. this.getValue = function(callbackId) {
  7241. this.sender.callback(this.doc.getValue(), callbackId);
  7242. };
  7243. this.onUpdate = function() {
  7244. };
  7245. this.isPending = function() {
  7246. return this.deferredUpdate.isPending();
  7247. };
  7248. }).call(Mirror.prototype);
  7249. });