spec/dummy/public/js/ace/src-noconflict/worker-css.js in optimacms-0.3.4 vs spec/dummy/public/js/ace/src-noconflict/worker-css.js in optimacms-0.3.5

- old
+ new

@@ -1,8682 +1,8682 @@ -"no use strict"; -;(function(window) { -if (typeof window.window != "undefined" && window.document) { - return; -} - -window.console = function() { - var msgs = Array.prototype.slice.call(arguments, 0); - postMessage({type: "log", data: msgs}); -}; -window.console.error = -window.console.warn = -window.console.log = -window.console.trace = window.console; - -window.window = window; -window.ace = window; - -window.onerror = function(message, file, line, col, err) { - postMessage({type: "error", data: { - message: message, - file: file, - line: line, - col: col, - stack: err.stack - }}); -}; - -window.normalizeModule = function(parentId, moduleName) { - // normalize plugin requires - if (moduleName.indexOf("!") !== -1) { - var chunks = moduleName.split("!"); - return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]); - } - // normalize relative requires - if (moduleName.charAt(0) == ".") { - var base = parentId.split("/").slice(0, -1).join("/"); - moduleName = (base ? base + "/" : "") + moduleName; - - while(moduleName.indexOf(".") !== -1 && previous != moduleName) { - var previous = moduleName; - moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); - } - } - - return moduleName; -}; - -window.require = function(parentId, id) { - if (!id) { - id = parentId; - parentId = null; - } - if (!id.charAt) - throw new Error("worker.js require() accepts only (parentId, id) as arguments"); - - id = window.normalizeModule(parentId, id); - - var module = window.require.modules[id]; - if (module) { - if (!module.initialized) { - module.initialized = true; - module.exports = module.factory().exports; - } - return module.exports; - } - - var chunks = id.split("/"); - if (!window.require.tlns) - return console.log("unable to load " + id); - chunks[0] = window.require.tlns[chunks[0]] || chunks[0]; - var path = chunks.join("/") + ".js"; - - window.require.id = id; - importScripts(path); - return window.require(parentId, id); -}; -window.require.modules = {}; -window.require.tlns = {}; - -window.define = function(id, deps, factory) { - if (arguments.length == 2) { - factory = deps; - if (typeof id != "string") { - deps = id; - id = window.require.id; - } - } else if (arguments.length == 1) { - factory = id; - deps = []; - id = window.require.id; - } - - if (typeof factory != "function") { - window.require.modules[id] = { - exports: factory, - initialized: true - }; - return; - } - - if (!deps.length) - // If there is no dependencies, we inject 'require', 'exports' and - // 'module' as dependencies, to provide CommonJS compatibility. - deps = ['require', 'exports', 'module']; - - var req = function(childId) { - return window.require(id, childId); - }; - - window.require.modules[id] = { - exports: {}, - factory: function() { - var module = this; - var returnExports = factory.apply(this, deps.map(function(dep) { - switch(dep) { - // Because 'require', 'exports' and 'module' aren't actual - // dependencies, we must handle them seperately. - case 'require': return req; - case 'exports': return module.exports; - case 'module': return module; - // But for all other dependencies, we can just go ahead and - // require them. - default: return req(dep); - } - })); - if (returnExports) - module.exports = returnExports; - return module; - } - }; -}; -window.define.amd = {}; - -window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { - require.tlns = topLevelNamespaces; -}; - -window.initSender = function initSender() { - - var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter; - var oop = window.require("ace/lib/oop"); - - var Sender = function() {}; - - (function() { - - oop.implement(this, EventEmitter); - - this.callback = function(data, callbackId) { - postMessage({ - type: "call", - id: callbackId, - data: data - }); - }; - - this.emit = function(name, data) { - postMessage({ - type: "event", - name: name, - data: data - }); - }; - - }).call(Sender.prototype); - - return new Sender(); -}; - -var main = window.main = null; -var sender = window.sender = null; - -window.onmessage = function(e) { - var msg = e.data; - if (msg.command) { - if (main[msg.command]) - main[msg.command].apply(main, msg.args); - else - throw new Error("Unknown command:" + msg.command); - } - else if (msg.init) { - initBaseUrls(msg.tlns); - require("ace/lib/es5-shim"); - sender = window.sender = initSender(); - var clazz = require(msg.module)[msg.classname]; - main = window.main = new clazz(sender); - } - else if (msg.event && sender) { - sender._signal(msg.event, msg.data); - } -}; -})(this); - -ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { -"use strict"; - -exports.inherits = function(ctor, superCtor) { - ctor.super_ = superCtor; - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); -}; - -exports.mixin = function(obj, mixin) { - for (var key in mixin) { - obj[key] = mixin[key]; - } - return obj; -}; - -exports.implement = function(proto, mixin) { - exports.mixin(proto, mixin); -}; - -}); - -ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { -"use strict"; - -exports.last = function(a) { - return a[a.length - 1]; -}; - -exports.stringReverse = function(string) { - return string.split("").reverse().join(""); -}; - -exports.stringRepeat = function (string, count) { - var result = ''; - while (count > 0) { - if (count & 1) - result += string; - - if (count >>= 1) - string += string; - } - return result; -}; - -var trimBeginRegexp = /^\s\s*/; -var trimEndRegexp = /\s\s*$/; - -exports.stringTrimLeft = function (string) { - return string.replace(trimBeginRegexp, ''); -}; - -exports.stringTrimRight = function (string) { - return string.replace(trimEndRegexp, ''); -}; - -exports.copyObject = function(obj) { - var copy = {}; - for (var key in obj) { - copy[key] = obj[key]; - } - return copy; -}; - -exports.copyArray = function(array){ - var copy = []; - for (var i=0, l=array.length; i<l; i++) { - if (array[i] && typeof array[i] == "object") - copy[i] = this.copyObject( array[i] ); - else - copy[i] = array[i]; - } - return copy; -}; - -exports.deepCopy = function (obj) { - if (typeof obj !== "object" || !obj) - return obj; - var cons = obj.constructor; - if (cons === RegExp) - return obj; - - var copy = cons(); - for (var key in obj) { - if (typeof obj[key] === "object") { - copy[key] = exports.deepCopy(obj[key]); - } else { - copy[key] = obj[key]; - } - } - return copy; -}; - -exports.arrayToMap = function(arr) { - var map = {}; - for (var i=0; i<arr.length; i++) { - map[arr[i]] = 1; - } - return map; - -}; - -exports.createMap = function(props) { - var map = Object.create(null); - for (var i in props) { - map[i] = props[i]; - } - return map; -}; -exports.arrayRemove = function(array, value) { - for (var i = 0; i <= array.length; i++) { - if (value === array[i]) { - array.splice(i, 1); - } - } -}; - -exports.escapeRegExp = function(str) { - return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); -}; - -exports.escapeHTML = function(str) { - return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;"); -}; - -exports.getMatchOffsets = function(string, regExp) { - var matches = []; - - string.replace(regExp, function(str) { - matches.push({ - offset: arguments[arguments.length-2], - length: str.length - }); - }); - - return matches; -}; -exports.deferredCall = function(fcn) { - var timer = null; - var callback = function() { - timer = null; - fcn(); - }; - - var deferred = function(timeout) { - deferred.cancel(); - timer = setTimeout(callback, timeout || 0); - return deferred; - }; - - deferred.schedule = deferred; - - deferred.call = function() { - this.cancel(); - fcn(); - return deferred; - }; - - deferred.cancel = function() { - clearTimeout(timer); - timer = null; - return deferred; - }; - - deferred.isPending = function() { - return timer; - }; - - return deferred; -}; - - -exports.delayedCall = function(fcn, defaultTimeout) { - var timer = null; - var callback = function() { - timer = null; - fcn(); - }; - - var _self = function(timeout) { - if (timer == null) - timer = setTimeout(callback, timeout || defaultTimeout); - }; - - _self.delay = function(timeout) { - timer && clearTimeout(timer); - timer = setTimeout(callback, timeout || defaultTimeout); - }; - _self.schedule = _self; - - _self.call = function() { - this.cancel(); - fcn(); - }; - - _self.cancel = function() { - timer && clearTimeout(timer); - timer = null; - }; - - _self.isPending = function() { - return timer; - }; - - return _self; -}; -}); - -ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { -"use strict"; - -var EventEmitter = {}; -var stopPropagation = function() { this.propagationStopped = true; }; -var preventDefault = function() { this.defaultPrevented = true; }; - -EventEmitter._emit = -EventEmitter._dispatchEvent = function(eventName, e) { - this._eventRegistry || (this._eventRegistry = {}); - this._defaultHandlers || (this._defaultHandlers = {}); - - var listeners = this._eventRegistry[eventName] || []; - var defaultHandler = this._defaultHandlers[eventName]; - if (!listeners.length && !defaultHandler) - return; - - if (typeof e != "object" || !e) - e = {}; - - if (!e.type) - e.type = eventName; - if (!e.stopPropagation) - e.stopPropagation = stopPropagation; - if (!e.preventDefault) - e.preventDefault = preventDefault; - - listeners = listeners.slice(); - for (var i=0; i<listeners.length; i++) { - listeners[i](e, this); - if (e.propagationStopped) - break; - } - - if (defaultHandler && !e.defaultPrevented) - return defaultHandler(e, this); -}; - - -EventEmitter._signal = function(eventName, e) { - var listeners = (this._eventRegistry || {})[eventName]; - if (!listeners) - return; - listeners = listeners.slice(); - for (var i=0; i<listeners.length; i++) - listeners[i](e, this); -}; - -EventEmitter.once = function(eventName, callback) { - var _self = this; - callback && this.addEventListener(eventName, function newCallback() { - _self.removeEventListener(eventName, newCallback); - callback.apply(null, arguments); - }); -}; - - -EventEmitter.setDefaultHandler = function(eventName, callback) { - var handlers = this._defaultHandlers - if (!handlers) - handlers = this._defaultHandlers = {_disabled_: {}}; - - if (handlers[eventName]) { - var old = handlers[eventName]; - var disabled = handlers._disabled_[eventName]; - if (!disabled) - handlers._disabled_[eventName] = disabled = []; - disabled.push(old); - var i = disabled.indexOf(callback); - if (i != -1) - disabled.splice(i, 1); - } - handlers[eventName] = callback; -}; -EventEmitter.removeDefaultHandler = function(eventName, callback) { - var handlers = this._defaultHandlers - if (!handlers) - return; - var disabled = handlers._disabled_[eventName]; - - if (handlers[eventName] == callback) { - var old = handlers[eventName]; - if (disabled) - this.setDefaultHandler(eventName, disabled.pop()); - } else if (disabled) { - var i = disabled.indexOf(callback); - if (i != -1) - disabled.splice(i, 1); - } -}; - -EventEmitter.on = -EventEmitter.addEventListener = function(eventName, callback, capturing) { - this._eventRegistry = this._eventRegistry || {}; - - var listeners = this._eventRegistry[eventName]; - if (!listeners) - listeners = this._eventRegistry[eventName] = []; - - if (listeners.indexOf(callback) == -1) - listeners[capturing ? "unshift" : "push"](callback); - return callback; -}; - -EventEmitter.off = -EventEmitter.removeListener = -EventEmitter.removeEventListener = function(eventName, callback) { - this._eventRegistry = this._eventRegistry || {}; - - var listeners = this._eventRegistry[eventName]; - if (!listeners) - return; - - var index = listeners.indexOf(callback); - if (index !== -1) - listeners.splice(index, 1); -}; - -EventEmitter.removeAllListeners = function(eventName) { - if (this._eventRegistry) this._eventRegistry[eventName] = []; -}; - -exports.EventEmitter = EventEmitter; - -}); - -ace.define("ace/range",["require","exports","module"], function(require, exports, module) { -"use strict"; -var comparePoints = function(p1, p2) { - return p1.row - p2.row || p1.column - p2.column; -}; -var Range = function(startRow, startColumn, endRow, endColumn) { - this.start = { - row: startRow, - column: startColumn - }; - - this.end = { - row: endRow, - column: endColumn - }; -}; - -(function() { - this.isEqual = function(range) { - return this.start.row === range.start.row && - this.end.row === range.end.row && - this.start.column === range.start.column && - this.end.column === range.end.column; - }; - this.toString = function() { - return ("Range: [" + this.start.row + "/" + this.start.column + - "] -> [" + this.end.row + "/" + this.end.column + "]"); - }; - - this.contains = function(row, column) { - return this.compare(row, column) == 0; - }; - this.compareRange = function(range) { - var cmp, - end = range.end, - start = range.start; - - cmp = this.compare(end.row, end.column); - if (cmp == 1) { - cmp = this.compare(start.row, start.column); - if (cmp == 1) { - return 2; - } else if (cmp == 0) { - return 1; - } else { - return 0; - } - } else if (cmp == -1) { - return -2; - } else { - cmp = this.compare(start.row, start.column); - if (cmp == -1) { - return -1; - } else if (cmp == 1) { - return 42; - } else { - return 0; - } - } - }; - this.comparePoint = function(p) { - return this.compare(p.row, p.column); - }; - this.containsRange = function(range) { - return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; - }; - this.intersects = function(range) { - var cmp = this.compareRange(range); - return (cmp == -1 || cmp == 0 || cmp == 1); - }; - this.isEnd = function(row, column) { - return this.end.row == row && this.end.column == column; - }; - this.isStart = function(row, column) { - return this.start.row == row && this.start.column == column; - }; - this.setStart = function(row, column) { - if (typeof row == "object") { - this.start.column = row.column; - this.start.row = row.row; - } else { - this.start.row = row; - this.start.column = column; - } - }; - this.setEnd = function(row, column) { - if (typeof row == "object") { - this.end.column = row.column; - this.end.row = row.row; - } else { - this.end.row = row; - this.end.column = column; - } - }; - this.inside = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isEnd(row, column) || this.isStart(row, column)) { - return false; - } else { - return true; - } - } - return false; - }; - this.insideStart = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isEnd(row, column)) { - return false; - } else { - return true; - } - } - return false; - }; - this.insideEnd = function(row, column) { - if (this.compare(row, column) == 0) { - if (this.isStart(row, column)) { - return false; - } else { - return true; - } - } - return false; - }; - this.compare = function(row, column) { - if (!this.isMultiLine()) { - if (row === this.start.row) { - return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); - }; - } - - if (row < this.start.row) - return -1; - - if (row > this.end.row) - return 1; - - if (this.start.row === row) - return column >= this.start.column ? 0 : -1; - - if (this.end.row === row) - return column <= this.end.column ? 0 : 1; - - return 0; - }; - this.compareStart = function(row, column) { - if (this.start.row == row && this.start.column == column) { - return -1; - } else { - return this.compare(row, column); - } - }; - this.compareEnd = function(row, column) { - if (this.end.row == row && this.end.column == column) { - return 1; - } else { - return this.compare(row, column); - } - }; - this.compareInside = function(row, column) { - if (this.end.row == row && this.end.column == column) { - return 1; - } else if (this.start.row == row && this.start.column == column) { - return -1; - } else { - return this.compare(row, column); - } - }; - this.clipRows = function(firstRow, lastRow) { - if (this.end.row > lastRow) - var end = {row: lastRow + 1, column: 0}; - else if (this.end.row < firstRow) - var end = {row: firstRow, column: 0}; - - if (this.start.row > lastRow) - var start = {row: lastRow + 1, column: 0}; - else if (this.start.row < firstRow) - var start = {row: firstRow, column: 0}; - - return Range.fromPoints(start || this.start, end || this.end); - }; - this.extend = function(row, column) { - var cmp = this.compare(row, column); - - if (cmp == 0) - return this; - else if (cmp == -1) - var start = {row: row, column: column}; - else - var end = {row: row, column: column}; - - return Range.fromPoints(start || this.start, end || this.end); - }; - - this.isEmpty = function() { - return (this.start.row === this.end.row && this.start.column === this.end.column); - }; - this.isMultiLine = function() { - return (this.start.row !== this.end.row); - }; - this.clone = function() { - return Range.fromPoints(this.start, this.end); - }; - this.collapseRows = function() { - if (this.end.column == 0) - return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) - else - return new Range(this.start.row, 0, this.end.row, 0) - }; - this.toScreenRange = function(session) { - var screenPosStart = session.documentToScreenPosition(this.start); - var screenPosEnd = session.documentToScreenPosition(this.end); - - return new Range( - screenPosStart.row, screenPosStart.column, - screenPosEnd.row, screenPosEnd.column - ); - }; - this.moveBy = function(row, column) { - this.start.row += row; - this.start.column += column; - this.end.row += row; - this.end.column += column; - }; - -}).call(Range.prototype); -Range.fromPoints = function(start, end) { - return new Range(start.row, start.column, end.row, end.column); -}; -Range.comparePoints = comparePoints; - -Range.comparePoints = function(p1, p2) { - return p1.row - p2.row || p1.column - p2.column; -}; - - -exports.Range = Range; -}); - -ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { -"use strict"; - -var oop = require("./lib/oop"); -var EventEmitter = require("./lib/event_emitter").EventEmitter; - -var Anchor = exports.Anchor = function(doc, row, column) { - this.$onChange = this.onChange.bind(this); - this.attach(doc); - - if (typeof column == "undefined") - this.setPosition(row.row, row.column); - else - this.setPosition(row, column); -}; - -(function() { - - oop.implement(this, EventEmitter); - this.getPosition = function() { - return this.$clipPositionToDocument(this.row, this.column); - }; - this.getDocument = function() { - return this.document; - }; - this.$insertRight = false; - this.onChange = function(e) { - var delta = e.data; - var range = delta.range; - - if (range.start.row == range.end.row && range.start.row != this.row) - return; - - if (range.start.row > this.row) - return; - - if (range.start.row == this.row && range.start.column > this.column) - return; - - var row = this.row; - var column = this.column; - var start = range.start; - var end = range.end; - - if (delta.action === "insertText") { - if (start.row === row && start.column <= column) { - if (start.column === column && this.$insertRight) { - } else if (start.row === end.row) { - column += end.column - start.column; - } else { - column -= start.column; - row += end.row - start.row; - } - } else if (start.row !== end.row && start.row < row) { - row += end.row - start.row; - } - } else if (delta.action === "insertLines") { - if (start.row === row && column === 0 && this.$insertRight) { - } - else if (start.row <= row) { - row += end.row - start.row; - } - } else if (delta.action === "removeText") { - if (start.row === row && start.column < column) { - if (end.column >= column) - column = start.column; - else - column = Math.max(0, column - (end.column - start.column)); - - } else if (start.row !== end.row && start.row < row) { - if (end.row === row) - column = Math.max(0, column - end.column) + start.column; - row -= (end.row - start.row); - } else if (end.row === row) { - row -= end.row - start.row; - column = Math.max(0, column - end.column) + start.column; - } - } else if (delta.action == "removeLines") { - if (start.row <= row) { - if (end.row <= row) - row -= end.row - start.row; - else { - row = start.row; - column = 0; - } - } - } - - this.setPosition(row, column, true); - }; - this.setPosition = function(row, column, noClip) { - var pos; - if (noClip) { - pos = { - row: row, - column: column - }; - } else { - pos = this.$clipPositionToDocument(row, column); - } - - if (this.row == pos.row && this.column == pos.column) - return; - - var old = { - row: this.row, - column: this.column - }; - - this.row = pos.row; - this.column = pos.column; - this._signal("change", { - old: old, - value: pos - }); - }; - this.detach = function() { - this.document.removeEventListener("change", this.$onChange); - }; - this.attach = function(doc) { - this.document = doc || this.document; - this.document.on("change", this.$onChange); - }; - this.$clipPositionToDocument = function(row, column) { - var pos = {}; - - if (row >= this.document.getLength()) { - pos.row = Math.max(0, this.document.getLength() - 1); - pos.column = this.document.getLine(pos.row).length; - } - else if (row < 0) { - pos.row = 0; - pos.column = 0; - } - else { - pos.row = row; - pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); - } - - if (column < 0) - pos.column = 0; - - return pos; - }; - -}).call(Anchor.prototype); - -}); - -ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { -"use strict"; - -var oop = require("./lib/oop"); -var EventEmitter = require("./lib/event_emitter").EventEmitter; -var Range = require("./range").Range; -var Anchor = require("./anchor").Anchor; - -var Document = function(text) { - this.$lines = []; - if (text.length === 0) { - this.$lines = [""]; - } else if (Array.isArray(text)) { - this._insertLines(0, text); - } else { - this.insert({row: 0, column:0}, text); - } -}; - -(function() { - - oop.implement(this, EventEmitter); - this.setValue = function(text) { - var len = this.getLength(); - this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insert({row: 0, column:0}, text); - }; - this.getValue = function() { - return this.getAllLines().join(this.getNewLineCharacter()); - }; - this.createAnchor = function(row, column) { - return new Anchor(this, row, column); - }; - if ("aaa".split(/a/).length === 0) - this.$split = function(text) { - return text.replace(/\r\n|\r/g, "\n").split("\n"); - }; - else - this.$split = function(text) { - return text.split(/\r\n|\r|\n/); - }; - - - this.$detectNewLine = function(text) { - var match = text.match(/^.*?(\r\n|\r|\n)/m); - this.$autoNewLine = match ? match[1] : "\n"; - this._signal("changeNewLineMode"); - }; - this.getNewLineCharacter = function() { - switch (this.$newLineMode) { - case "windows": - return "\r\n"; - case "unix": - return "\n"; - default: - return this.$autoNewLine || "\n"; - } - }; - - this.$autoNewLine = ""; - this.$newLineMode = "auto"; - this.setNewLineMode = function(newLineMode) { - if (this.$newLineMode === newLineMode) - return; - - this.$newLineMode = newLineMode; - this._signal("changeNewLineMode"); - }; - this.getNewLineMode = function() { - return this.$newLineMode; - }; - this.isNewLine = function(text) { - return (text == "\r\n" || text == "\r" || text == "\n"); - }; - this.getLine = function(row) { - return this.$lines[row] || ""; - }; - this.getLines = function(firstRow, lastRow) { - return this.$lines.slice(firstRow, lastRow + 1); - }; - this.getAllLines = function() { - return this.getLines(0, this.getLength()); - }; - this.getLength = function() { - return this.$lines.length; - }; - this.getTextRange = function(range) { - if (range.start.row == range.end.row) { - return this.getLine(range.start.row) - .substring(range.start.column, range.end.column); - } - var lines = this.getLines(range.start.row, range.end.row); - lines[0] = (lines[0] || "").substring(range.start.column); - var l = lines.length - 1; - if (range.end.row - range.start.row == l) - lines[l] = lines[l].substring(0, range.end.column); - return lines.join(this.getNewLineCharacter()); - }; - - this.$clipPosition = function(position) { - var length = this.getLength(); - if (position.row >= length) { - position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; - } else if (position.row < 0) - position.row = 0; - return position; - }; - this.insert = function(position, text) { - if (!text || text.length === 0) - return position; - - position = this.$clipPosition(position); - if (this.getLength() <= 1) - this.$detectNewLine(text); - - var lines = this.$split(text); - var firstLine = lines.splice(0, 1)[0]; - var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; - - position = this.insertInLine(position, firstLine); - if (lastLine !== null) { - position = this.insertNewLine(position); // terminate first line - position = this._insertLines(position.row, lines); - position = this.insertInLine(position, lastLine || ""); - } - return position; - }; - this.insertLines = function(row, lines) { - if (row >= this.getLength()) - return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); - return this._insertLines(Math.max(row, 0), lines); - }; - this._insertLines = function(row, lines) { - if (lines.length == 0) - return {row: row, column: 0}; - while (lines.length > 20000) { - var end = this._insertLines(row, lines.slice(0, 20000)); - lines = lines.slice(20000); - row = end.row; - } - - var args = [row, 0]; - args.push.apply(args, lines); - this.$lines.splice.apply(this.$lines, args); - - var range = new Range(row, 0, row + lines.length, 0); - var delta = { - action: "insertLines", - range: range, - lines: lines - }; - this._signal("change", { data: delta }); - return range.end; - }; - this.insertNewLine = function(position) { - position = this.$clipPosition(position); - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column); - this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); - - var end = { - row : position.row + 1, - column : 0 - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: this.getNewLineCharacter() - }; - this._signal("change", { data: delta }); - - return end; - }; - this.insertInLine = function(position, text) { - if (text.length == 0) - return position; - - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); - - var end = { - row : position.row, - column : position.column + text.length - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: text - }; - this._signal("change", { data: delta }); - - return end; - }; - this.remove = function(range) { - if (!(range instanceof Range)) - range = Range.fromPoints(range.start, range.end); - range.start = this.$clipPosition(range.start); - range.end = this.$clipPosition(range.end); - - if (range.isEmpty()) - return range.start; - - var firstRow = range.start.row; - var lastRow = range.end.row; - - if (range.isMultiLine()) { - var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; - var lastFullRow = lastRow - 1; - - if (range.end.column > 0) - this.removeInLine(lastRow, 0, range.end.column); - - if (lastFullRow >= firstFullRow) - this._removeLines(firstFullRow, lastFullRow); - - if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); - this.removeNewLine(range.start.row); - } - } - else { - this.removeInLine(firstRow, range.start.column, range.end.column); - } - return range.start; - }; - this.removeInLine = function(row, startColumn, endColumn) { - if (startColumn == endColumn) - return; - - var range = new Range(row, startColumn, row, endColumn); - var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); - this.$lines.splice(row, 1, newLine); - - var delta = { - action: "removeText", - range: range, - text: removed - }; - this._signal("change", { data: delta }); - return range.start; - }; - this.removeLines = function(firstRow, lastRow) { - if (firstRow < 0 || lastRow >= this.getLength()) - return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); - return this._removeLines(firstRow, lastRow); - }; - - this._removeLines = function(firstRow, lastRow) { - var range = new Range(firstRow, 0, lastRow + 1, 0); - var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); - - var delta = { - action: "removeLines", - range: range, - nl: this.getNewLineCharacter(), - lines: removed - }; - this._signal("change", { data: delta }); - return removed; - }; - this.removeNewLine = function(row) { - var firstLine = this.getLine(row); - var secondLine = this.getLine(row+1); - - var range = new Range(row, firstLine.length, row+1, 0); - var line = firstLine + secondLine; - - this.$lines.splice(row, 2, line); - - var delta = { - action: "removeText", - range: range, - text: this.getNewLineCharacter() - }; - this._signal("change", { data: delta }); - }; - this.replace = function(range, text) { - if (!(range instanceof Range)) - range = Range.fromPoints(range.start, range.end); - if (text.length == 0 && range.isEmpty()) - return range.start; - if (text == this.getTextRange(range)) - return range.end; - - this.remove(range); - if (text) { - var end = this.insert(range.start, text); - } - else { - end = range.start; - } - - return end; - }; - this.applyDeltas = function(deltas) { - for (var i=0; i<deltas.length; i++) { - var delta = deltas[i]; - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this.insertLines(range.start.row, delta.lines); - else if (delta.action == "insertText") - this.insert(range.start, delta.text); - else if (delta.action == "removeLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "removeText") - this.remove(range); - } - }; - this.revertDeltas = function(deltas) { - for (var i=deltas.length-1; i>=0; i--) { - var delta = deltas[i]; - - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "insertText") - this.remove(range); - else if (delta.action == "removeLines") - this._insertLines(range.start.row, delta.lines); - else if (delta.action == "removeText") - this.insert(range.start, delta.text); - } - }; - this.indexToPosition = function(index, startRow) { - var lines = this.$lines || this.getAllLines(); - var newlineLength = this.getNewLineCharacter().length; - for (var i = startRow || 0, l = lines.length; i < l; i++) { - index -= lines[i].length + newlineLength; - if (index < 0) - return {row: i, column: index + lines[i].length + newlineLength}; - } - return {row: l-1, column: lines[l-1].length}; - }; - this.positionToIndex = function(pos, startRow) { - var lines = this.$lines || this.getAllLines(); - var newlineLength = this.getNewLineCharacter().length; - var index = 0; - var row = Math.min(pos.row, lines.length); - for (var i = startRow || 0; i < row; ++i) - index += lines[i].length + newlineLength; - - return index + pos.column; - }; - -}).call(Document.prototype); - -exports.Document = Document; -}); - -ace.define("ace/worker/mirror",["require","exports","module","ace/document","ace/lib/lang"], function(require, exports, module) { -"use strict"; - -var Document = require("../document").Document; -var lang = require("../lib/lang"); - -var Mirror = exports.Mirror = function(sender) { - this.sender = sender; - var doc = this.doc = new Document(""); - - var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this)); - - var _self = this; - sender.on("change", function(e) { - doc.applyDeltas(e.data); - if (_self.$timeout) - return deferredUpdate.schedule(_self.$timeout); - _self.onUpdate(); - }); -}; - -(function() { - - this.$timeout = 500; - - this.setTimeout = function(timeout) { - this.$timeout = timeout; - }; - - this.setValue = function(value) { - this.doc.setValue(value); - this.deferredUpdate.schedule(this.$timeout); - }; - - this.getValue = function(callbackId) { - this.sender.callback(this.doc.getValue(), callbackId); - }; - - this.onUpdate = function() { - }; - - this.isPending = function() { - return this.deferredUpdate.isPending(); - }; - -}).call(Mirror.prototype); - -}); - -ace.define("ace/mode/css/csslint",["require","exports","module"], function(require, exports, module) { -var parserlib = {}; -(function(){ -function EventTarget(){ - this._listeners = {}; -} - -EventTarget.prototype = { - constructor: EventTarget, - addListener: function(type, listener){ - if (!this._listeners[type]){ - this._listeners[type] = []; - } - - this._listeners[type].push(listener); - }, - fire: function(event){ - if (typeof event == "string"){ - event = { type: event }; - } - if (typeof event.target != "undefined"){ - event.target = this; - } - - if (typeof event.type == "undefined"){ - throw new Error("Event object missing 'type' property."); - } - - if (this._listeners[event.type]){ - var listeners = this._listeners[event.type].concat(); - for (var i=0, len=listeners.length; i < len; i++){ - listeners[i].call(this, event); - } - } - }, - removeListener: function(type, listener){ - if (this._listeners[type]){ - var listeners = this._listeners[type]; - for (var i=0, len=listeners.length; i < len; i++){ - if (listeners[i] === listener){ - listeners.splice(i, 1); - break; - } - } - - - } - } -}; -function StringReader(text){ - this._input = text.replace(/\n\r?/g, "\n"); - this._line = 1; - this._col = 1; - this._cursor = 0; -} - -StringReader.prototype = { - constructor: StringReader, - getCol: function(){ - return this._col; - }, - getLine: function(){ - return this._line ; - }, - eof: function(){ - return (this._cursor == this._input.length); - }, - peek: function(count){ - var c = null; - count = (typeof count == "undefined" ? 1 : count); - if (this._cursor < this._input.length){ - c = this._input.charAt(this._cursor + count - 1); - } - - return c; - }, - read: function(){ - var c = null; - if (this._cursor < this._input.length){ - if (this._input.charAt(this._cursor) == "\n"){ - this._line++; - this._col=1; - } else { - this._col++; - } - c = this._input.charAt(this._cursor++); - } - - return c; - }, - mark: function(){ - this._bookmark = { - cursor: this._cursor, - line: this._line, - col: this._col - }; - }, - - reset: function(){ - if (this._bookmark){ - this._cursor = this._bookmark.cursor; - this._line = this._bookmark.line; - this._col = this._bookmark.col; - delete this._bookmark; - } - }, - readTo: function(pattern){ - - var buffer = "", - c; - while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ - c = this.read(); - if (c){ - buffer += c; - } else { - throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); - } - } - - return buffer; - - }, - readWhile: function(filter){ - - var buffer = "", - c = this.read(); - - while(c !== null && filter(c)){ - buffer += c; - c = this.read(); - } - - return buffer; - - }, - readMatch: function(matcher){ - - var source = this._input.substring(this._cursor), - value = null; - if (typeof matcher == "string"){ - if (source.indexOf(matcher) === 0){ - value = this.readCount(matcher.length); - } - } else if (matcher instanceof RegExp){ - if (matcher.test(source)){ - value = this.readCount(RegExp.lastMatch.length); - } - } - - return value; - }, - readCount: function(count){ - var buffer = ""; - - while(count--){ - buffer += this.read(); - } - - return buffer; - } - -}; -function SyntaxError(message, line, col){ - this.col = col; - this.line = line; - this.message = message; - -} -SyntaxError.prototype = new Error(); -function SyntaxUnit(text, line, col, type){ - this.col = col; - this.line = line; - this.text = text; - this.type = type; -} -SyntaxUnit.fromToken = function(token){ - return new SyntaxUnit(token.value, token.startLine, token.startCol); -}; - -SyntaxUnit.prototype = { - constructor: SyntaxUnit, - valueOf: function(){ - return this.text; - }, - toString: function(){ - return this.text; - } - -}; -function TokenStreamBase(input, tokenData){ - this._reader = input ? new StringReader(input.toString()) : null; - this._token = null; - this._tokenData = tokenData; - this._lt = []; - this._ltIndex = 0; - - this._ltIndexCache = []; -} -TokenStreamBase.createTokenData = function(tokens){ - - var nameMap = [], - typeMap = {}, - tokenData = tokens.concat([]), - i = 0, - len = tokenData.length+1; - - tokenData.UNKNOWN = -1; - tokenData.unshift({name:"EOF"}); - - for (; i < len; i++){ - nameMap.push(tokenData[i].name); - tokenData[tokenData[i].name] = i; - if (tokenData[i].text){ - typeMap[tokenData[i].text] = i; - } - } - - tokenData.name = function(tt){ - return nameMap[tt]; - }; - - tokenData.type = function(c){ - return typeMap[c]; - }; - - return tokenData; -}; - -TokenStreamBase.prototype = { - constructor: TokenStreamBase, - match: function(tokenTypes, channel){ - if (!(tokenTypes instanceof Array)){ - tokenTypes = [tokenTypes]; - } - - var tt = this.get(channel), - i = 0, - len = tokenTypes.length; - - while(i < len){ - if (tt == tokenTypes[i++]){ - return true; - } - } - this.unget(); - return false; - }, - mustMatch: function(tokenTypes, channel){ - - var token; - if (!(tokenTypes instanceof Array)){ - tokenTypes = [tokenTypes]; - } - - if (!this.match.apply(this, arguments)){ - token = this.LT(1); - throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + - " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); - } - }, - advance: function(tokenTypes, channel){ - - while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ - this.get(); - } - - return this.LA(0); - }, - get: function(channel){ - - var tokenInfo = this._tokenData, - reader = this._reader, - value, - i =0, - len = tokenInfo.length, - found = false, - token, - info; - if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ - - i++; - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; - while((info.channel !== undefined && channel !== info.channel) && - this._ltIndex < this._lt.length){ - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; - i++; - } - if ((info.channel === undefined || channel === info.channel) && - this._ltIndex <= this._lt.length){ - this._ltIndexCache.push(i); - return this._token.type; - } - } - token = this._getToken(); - if (token.type > -1 && !tokenInfo[token.type].hide){ - token.channel = tokenInfo[token.type].channel; - this._token = token; - this._lt.push(token); - this._ltIndexCache.push(this._lt.length - this._ltIndex + i); - if (this._lt.length > 5){ - this._lt.shift(); - } - if (this._ltIndexCache.length > 5){ - this._ltIndexCache.shift(); - } - this._ltIndex = this._lt.length; - } - info = tokenInfo[token.type]; - if (info && - (info.hide || - (info.channel !== undefined && channel !== info.channel))){ - return this.get(channel); - } else { - return token.type; - } - }, - LA: function(index){ - var total = index, - tt; - if (index > 0){ - if (index > 5){ - throw new Error("Too much lookahead."); - } - while(total){ - tt = this.get(); - total--; - } - while(total < index){ - this.unget(); - total++; - } - } else if (index < 0){ - - if(this._lt[this._ltIndex+index]){ - tt = this._lt[this._ltIndex+index].type; - } else { - throw new Error("Too much lookbehind."); - } - - } else { - tt = this._token.type; - } - - return tt; - - }, - LT: function(index){ - this.LA(index); - return this._lt[this._ltIndex+index-1]; - }, - peek: function(){ - return this.LA(1); - }, - token: function(){ - return this._token; - }, - tokenName: function(tokenType){ - if (tokenType < 0 || tokenType > this._tokenData.length){ - return "UNKNOWN_TOKEN"; - } else { - return this._tokenData[tokenType].name; - } - }, - tokenType: function(tokenName){ - return this._tokenData[tokenName] || -1; - }, - unget: function(){ - if (this._ltIndexCache.length){ - this._ltIndex -= this._ltIndexCache.pop();//--; - this._token = this._lt[this._ltIndex - 1]; - } else { - throw new Error("Too much lookahead."); - } - } - -}; - - -parserlib.util = { -StringReader: StringReader, -SyntaxError : SyntaxError, -SyntaxUnit : SyntaxUnit, -EventTarget : EventTarget, -TokenStreamBase : TokenStreamBase -}; -})(); -(function(){ -var EventTarget = parserlib.util.EventTarget, -TokenStreamBase = parserlib.util.TokenStreamBase, -StringReader = parserlib.util.StringReader, -SyntaxError = parserlib.util.SyntaxError, -SyntaxUnit = parserlib.util.SyntaxUnit; - -var Colors = { - aliceblue :"#f0f8ff", - antiquewhite :"#faebd7", - aqua :"#00ffff", - aquamarine :"#7fffd4", - azure :"#f0ffff", - beige :"#f5f5dc", - bisque :"#ffe4c4", - black :"#000000", - blanchedalmond :"#ffebcd", - blue :"#0000ff", - blueviolet :"#8a2be2", - brown :"#a52a2a", - burlywood :"#deb887", - cadetblue :"#5f9ea0", - chartreuse :"#7fff00", - chocolate :"#d2691e", - coral :"#ff7f50", - cornflowerblue :"#6495ed", - cornsilk :"#fff8dc", - crimson :"#dc143c", - cyan :"#00ffff", - darkblue :"#00008b", - darkcyan :"#008b8b", - darkgoldenrod :"#b8860b", - darkgray :"#a9a9a9", - darkgrey :"#a9a9a9", - darkgreen :"#006400", - darkkhaki :"#bdb76b", - darkmagenta :"#8b008b", - darkolivegreen :"#556b2f", - darkorange :"#ff8c00", - darkorchid :"#9932cc", - darkred :"#8b0000", - darksalmon :"#e9967a", - darkseagreen :"#8fbc8f", - darkslateblue :"#483d8b", - darkslategray :"#2f4f4f", - darkslategrey :"#2f4f4f", - darkturquoise :"#00ced1", - darkviolet :"#9400d3", - deeppink :"#ff1493", - deepskyblue :"#00bfff", - dimgray :"#696969", - dimgrey :"#696969", - dodgerblue :"#1e90ff", - firebrick :"#b22222", - floralwhite :"#fffaf0", - forestgreen :"#228b22", - fuchsia :"#ff00ff", - gainsboro :"#dcdcdc", - ghostwhite :"#f8f8ff", - gold :"#ffd700", - goldenrod :"#daa520", - gray :"#808080", - grey :"#808080", - green :"#008000", - greenyellow :"#adff2f", - honeydew :"#f0fff0", - hotpink :"#ff69b4", - indianred :"#cd5c5c", - indigo :"#4b0082", - ivory :"#fffff0", - khaki :"#f0e68c", - lavender :"#e6e6fa", - lavenderblush :"#fff0f5", - lawngreen :"#7cfc00", - lemonchiffon :"#fffacd", - lightblue :"#add8e6", - lightcoral :"#f08080", - lightcyan :"#e0ffff", - lightgoldenrodyellow :"#fafad2", - lightgray :"#d3d3d3", - lightgrey :"#d3d3d3", - lightgreen :"#90ee90", - lightpink :"#ffb6c1", - lightsalmon :"#ffa07a", - lightseagreen :"#20b2aa", - lightskyblue :"#87cefa", - lightslategray :"#778899", - lightslategrey :"#778899", - lightsteelblue :"#b0c4de", - lightyellow :"#ffffe0", - lime :"#00ff00", - limegreen :"#32cd32", - linen :"#faf0e6", - magenta :"#ff00ff", - maroon :"#800000", - mediumaquamarine:"#66cdaa", - mediumblue :"#0000cd", - mediumorchid :"#ba55d3", - mediumpurple :"#9370d8", - mediumseagreen :"#3cb371", - mediumslateblue :"#7b68ee", - mediumspringgreen :"#00fa9a", - mediumturquoise :"#48d1cc", - mediumvioletred :"#c71585", - midnightblue :"#191970", - mintcream :"#f5fffa", - mistyrose :"#ffe4e1", - moccasin :"#ffe4b5", - navajowhite :"#ffdead", - navy :"#000080", - oldlace :"#fdf5e6", - olive :"#808000", - olivedrab :"#6b8e23", - orange :"#ffa500", - orangered :"#ff4500", - orchid :"#da70d6", - palegoldenrod :"#eee8aa", - palegreen :"#98fb98", - paleturquoise :"#afeeee", - palevioletred :"#d87093", - papayawhip :"#ffefd5", - peachpuff :"#ffdab9", - peru :"#cd853f", - pink :"#ffc0cb", - plum :"#dda0dd", - powderblue :"#b0e0e6", - purple :"#800080", - red :"#ff0000", - rosybrown :"#bc8f8f", - royalblue :"#4169e1", - saddlebrown :"#8b4513", - salmon :"#fa8072", - sandybrown :"#f4a460", - seagreen :"#2e8b57", - seashell :"#fff5ee", - sienna :"#a0522d", - silver :"#c0c0c0", - skyblue :"#87ceeb", - slateblue :"#6a5acd", - slategray :"#708090", - slategrey :"#708090", - snow :"#fffafa", - springgreen :"#00ff7f", - steelblue :"#4682b4", - tan :"#d2b48c", - teal :"#008080", - thistle :"#d8bfd8", - tomato :"#ff6347", - turquoise :"#40e0d0", - violet :"#ee82ee", - wheat :"#f5deb3", - white :"#ffffff", - whitesmoke :"#f5f5f5", - yellow :"#ffff00", - yellowgreen :"#9acd32", - activeBorder :"Active window border.", - activecaption :"Active window caption.", - appworkspace :"Background color of multiple document interface.", - background :"Desktop background.", - buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", - buttontext :"Text on push buttons.", - captiontext :"Text in caption, size box, and scrollbar arrow box.", - graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", - greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", - highlight :"Item(s) selected in a control.", - highlighttext :"Text of item(s) selected in a control.", - inactiveborder :"Inactive window border.", - inactivecaption :"Inactive window caption.", - inactivecaptiontext :"Color of text in an inactive caption.", - infobackground :"Background color for tooltip controls.", - infotext :"Text color for tooltip controls.", - menu :"Menu background.", - menutext :"Text in menus.", - scrollbar :"Scroll bar gray area.", - threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", - window :"Window background.", - windowframe :"Window frame.", - windowtext :"Text in windows." -}; -function Combinator(text, line, col){ - - SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); - this.type = "unknown"; - if (/^\s+$/.test(text)){ - this.type = "descendant"; - } else if (text == ">"){ - this.type = "child"; - } else if (text == "+"){ - this.type = "adjacent-sibling"; - } else if (text == "~"){ - this.type = "sibling"; - } - -} - -Combinator.prototype = new SyntaxUnit(); -Combinator.prototype.constructor = Combinator; -function MediaFeature(name, value){ - - SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); - this.name = name; - this.value = value; -} - -MediaFeature.prototype = new SyntaxUnit(); -MediaFeature.prototype.constructor = MediaFeature; -function MediaQuery(modifier, mediaType, features, line, col){ - - SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); - this.modifier = modifier; - this.mediaType = mediaType; - this.features = features; - -} - -MediaQuery.prototype = new SyntaxUnit(); -MediaQuery.prototype.constructor = MediaQuery; -function Parser(options){ - EventTarget.call(this); - - - this.options = options || {}; - - this._tokenStream = null; -} -Parser.DEFAULT_TYPE = 0; -Parser.COMBINATOR_TYPE = 1; -Parser.MEDIA_FEATURE_TYPE = 2; -Parser.MEDIA_QUERY_TYPE = 3; -Parser.PROPERTY_NAME_TYPE = 4; -Parser.PROPERTY_VALUE_TYPE = 5; -Parser.PROPERTY_VALUE_PART_TYPE = 6; -Parser.SELECTOR_TYPE = 7; -Parser.SELECTOR_PART_TYPE = 8; -Parser.SELECTOR_SUB_PART_TYPE = 9; - -Parser.prototype = function(){ - - var proto = new EventTarget(), //new prototype - prop, - additions = { - constructor: Parser, - DEFAULT_TYPE : 0, - COMBINATOR_TYPE : 1, - MEDIA_FEATURE_TYPE : 2, - MEDIA_QUERY_TYPE : 3, - PROPERTY_NAME_TYPE : 4, - PROPERTY_VALUE_TYPE : 5, - PROPERTY_VALUE_PART_TYPE : 6, - SELECTOR_TYPE : 7, - SELECTOR_PART_TYPE : 8, - SELECTOR_SUB_PART_TYPE : 9, - - _stylesheet: function(){ - - var tokenStream = this._tokenStream, - charset = null, - count, - token, - tt; - - this.fire("startstylesheet"); - this._charset(); - - this._skipCruft(); - while (tokenStream.peek() == Tokens.IMPORT_SYM){ - this._import(); - this._skipCruft(); - } - while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ - this._namespace(); - this._skipCruft(); - } - tt = tokenStream.peek(); - while(tt > Tokens.EOF){ - - try { - - switch(tt){ - case Tokens.MEDIA_SYM: - this._media(); - this._skipCruft(); - break; - case Tokens.PAGE_SYM: - this._page(); - this._skipCruft(); - break; - case Tokens.FONT_FACE_SYM: - this._font_face(); - this._skipCruft(); - break; - case Tokens.KEYFRAMES_SYM: - this._keyframes(); - this._skipCruft(); - break; - case Tokens.VIEWPORT_SYM: - this._viewport(); - this._skipCruft(); - break; - case Tokens.UNKNOWN_SYM: //unknown @ rule - tokenStream.get(); - if (!this.options.strict){ - this.fire({ - type: "error", - error: null, - message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", - line: tokenStream.LT(0).startLine, - col: tokenStream.LT(0).startCol - }); - count=0; - while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ - count++; //keep track of nesting depth - } - - while(count){ - tokenStream.advance([Tokens.RBRACE]); - count--; - } - - } else { - throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); - } - break; - case Tokens.S: - this._readWhitespace(); - break; - default: - if(!this._ruleset()){ - switch(tt){ - case Tokens.CHARSET_SYM: - token = tokenStream.LT(1); - this._charset(false); - throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); - case Tokens.IMPORT_SYM: - token = tokenStream.LT(1); - this._import(false); - throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); - case Tokens.NAMESPACE_SYM: - token = tokenStream.LT(1); - this._namespace(false); - throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); - default: - tokenStream.get(); //get the last token - this._unexpectedToken(tokenStream.token()); - } - - } - } - } catch(ex) { - if (ex instanceof SyntaxError && !this.options.strict){ - this.fire({ - type: "error", - error: ex, - message: ex.message, - line: ex.line, - col: ex.col - }); - } else { - throw ex; - } - } - - tt = tokenStream.peek(); - } - - if (tt != Tokens.EOF){ - this._unexpectedToken(tokenStream.token()); - } - - this.fire("endstylesheet"); - }, - - _charset: function(emit){ - var tokenStream = this._tokenStream, - charset, - token, - line, - col; - - if (tokenStream.match(Tokens.CHARSET_SYM)){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.STRING); - - token = tokenStream.token(); - charset = token.value; - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.SEMICOLON); - - if (emit !== false){ - this.fire({ - type: "charset", - charset:charset, - line: line, - col: col - }); - } - } - }, - - _import: function(emit){ - - var tokenStream = this._tokenStream, - tt, - uri, - importToken, - mediaList = []; - tokenStream.mustMatch(Tokens.IMPORT_SYM); - importToken = tokenStream.token(); - this._readWhitespace(); - - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); - - this._readWhitespace(); - - mediaList = this._media_query_list(); - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); - - if (emit !== false){ - this.fire({ - type: "import", - uri: uri, - media: mediaList, - line: importToken.startLine, - col: importToken.startCol - }); - } - - }, - - _namespace: function(emit){ - - var tokenStream = this._tokenStream, - line, - col, - prefix, - uri; - tokenStream.mustMatch(Tokens.NAMESPACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - this._readWhitespace(); - if (tokenStream.match(Tokens.IDENT)){ - prefix = tokenStream.token().value; - this._readWhitespace(); - } - - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); - - if (emit !== false){ - this.fire({ - type: "namespace", - prefix: prefix, - uri: uri, - line: line, - col: col - }); - } - - }, - - _media: function(){ - var tokenStream = this._tokenStream, - line, - col, - mediaList;// = []; - tokenStream.mustMatch(Tokens.MEDIA_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - mediaList = this._media_query_list(); - - tokenStream.mustMatch(Tokens.LBRACE); - this._readWhitespace(); - - this.fire({ - type: "startmedia", - media: mediaList, - line: line, - col: col - }); - - while(true) { - if (tokenStream.peek() == Tokens.PAGE_SYM){ - this._page(); - } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ - this._font_face(); - } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ - this._viewport(); - } else if (!this._ruleset()){ - break; - } - } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - - this.fire({ - type: "endmedia", - media: mediaList, - line: line, - col: col - }); - }, - _media_query_list: function(){ - var tokenStream = this._tokenStream, - mediaList = []; - - - this._readWhitespace(); - - if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ - mediaList.push(this._media_query()); - } - - while(tokenStream.match(Tokens.COMMA)){ - this._readWhitespace(); - mediaList.push(this._media_query()); - } - - return mediaList; - }, - _media_query: function(){ - var tokenStream = this._tokenStream, - type = null, - ident = null, - token = null, - expressions = []; - - if (tokenStream.match(Tokens.IDENT)){ - ident = tokenStream.token().value.toLowerCase(); - if (ident != "only" && ident != "not"){ - tokenStream.unget(); - ident = null; - } else { - token = tokenStream.token(); - } - } - - this._readWhitespace(); - - if (tokenStream.peek() == Tokens.IDENT){ - type = this._media_type(); - if (token === null){ - token = tokenStream.token(); - } - } else if (tokenStream.peek() == Tokens.LPAREN){ - if (token === null){ - token = tokenStream.LT(1); - } - expressions.push(this._media_expression()); - } - - if (type === null && expressions.length === 0){ - return null; - } else { - this._readWhitespace(); - while (tokenStream.match(Tokens.IDENT)){ - if (tokenStream.token().value.toLowerCase() != "and"){ - this._unexpectedToken(tokenStream.token()); - } - - this._readWhitespace(); - expressions.push(this._media_expression()); - } - } - - return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); - }, - _media_type: function(){ - return this._media_feature(); - }, - _media_expression: function(){ - var tokenStream = this._tokenStream, - feature = null, - token, - expression = null; - - tokenStream.mustMatch(Tokens.LPAREN); - - feature = this._media_feature(); - this._readWhitespace(); - - if (tokenStream.match(Tokens.COLON)){ - this._readWhitespace(); - token = tokenStream.LT(1); - expression = this._expression(); - } - - tokenStream.mustMatch(Tokens.RPAREN); - this._readWhitespace(); - - return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); - }, - _media_feature: function(){ - var tokenStream = this._tokenStream; - - tokenStream.mustMatch(Tokens.IDENT); - - return SyntaxUnit.fromToken(tokenStream.token()); - }, - _page: function(){ - var tokenStream = this._tokenStream, - line, - col, - identifier = null, - pseudoPage = null; - tokenStream.mustMatch(Tokens.PAGE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - if (tokenStream.match(Tokens.IDENT)){ - identifier = tokenStream.token().value; - if (identifier.toLowerCase() === "auto"){ - this._unexpectedToken(tokenStream.token()); - } - } - if (tokenStream.peek() == Tokens.COLON){ - pseudoPage = this._pseudo_page(); - } - - this._readWhitespace(); - - this.fire({ - type: "startpage", - id: identifier, - pseudo: pseudoPage, - line: line, - col: col - }); - - this._readDeclarations(true, true); - - this.fire({ - type: "endpage", - id: identifier, - pseudo: pseudoPage, - line: line, - col: col - }); - - }, - _margin: function(){ - var tokenStream = this._tokenStream, - line, - col, - marginSym = this._margin_sym(); - - if (marginSym){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this.fire({ - type: "startpagemargin", - margin: marginSym, - line: line, - col: col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endpagemargin", - margin: marginSym, - line: line, - col: col - }); - return true; - } else { - return false; - } - }, - _margin_sym: function(){ - - var tokenStream = this._tokenStream; - - if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, - Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, - Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, - Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, - Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, - Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, - Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) - { - return SyntaxUnit.fromToken(tokenStream.token()); - } else { - return null; - } - - }, - - _pseudo_page: function(){ - - var tokenStream = this._tokenStream; - - tokenStream.mustMatch(Tokens.COLON); - tokenStream.mustMatch(Tokens.IDENT); - - return tokenStream.token().value; - }, - - _font_face: function(){ - var tokenStream = this._tokenStream, - line, - col; - tokenStream.mustMatch(Tokens.FONT_FACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - this.fire({ - type: "startfontface", - line: line, - col: col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endfontface", - line: line, - col: col - }); - }, - - _viewport: function(){ - var tokenStream = this._tokenStream, - line, - col; - - tokenStream.mustMatch(Tokens.VIEWPORT_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - this.fire({ - type: "startviewport", - line: line, - col: col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endviewport", - line: line, - col: col - }); - - }, - - _operator: function(inFunction){ - - var tokenStream = this._tokenStream, - token = null; - - if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || - (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ - token = tokenStream.token(); - this._readWhitespace(); - } - return token ? PropertyValuePart.fromToken(token) : null; - - }, - - _combinator: function(){ - - var tokenStream = this._tokenStream, - value = null, - token; - - if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ - token = tokenStream.token(); - value = new Combinator(token.value, token.startLine, token.startCol); - this._readWhitespace(); - } - - return value; - }, - - _unary_operator: function(){ - - var tokenStream = this._tokenStream; - - if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ - return tokenStream.token().value; - } else { - return null; - } - }, - - _property: function(){ - - var tokenStream = this._tokenStream, - value = null, - hack = null, - tokenValue, - token, - line, - col; - if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ - tokenStream.get(); - token = tokenStream.token(); - hack = token.value; - line = token.startLine; - col = token.startCol; - } - - if(tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); - tokenValue = token.value; - if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ - hack = "_"; - tokenValue = tokenValue.substring(1); - } - - value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); - this._readWhitespace(); - } - - return value; - }, - _ruleset: function(){ - - var tokenStream = this._tokenStream, - tt, - selectors; - try { - selectors = this._selectors_group(); - } catch (ex){ - if (ex instanceof SyntaxError && !this.options.strict){ - this.fire({ - type: "error", - error: ex, - message: ex.message, - line: ex.line, - col: ex.col - }); - tt = tokenStream.advance([Tokens.RBRACE]); - if (tt == Tokens.RBRACE){ - } else { - throw ex; - } - - } else { - throw ex; - } - return true; - } - if (selectors){ - - this.fire({ - type: "startrule", - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endrule", - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col - }); - - } - - return selectors; - - }, - _selectors_group: function(){ - var tokenStream = this._tokenStream, - selectors = [], - selector; - - selector = this._selector(); - if (selector !== null){ - - selectors.push(selector); - while(tokenStream.match(Tokens.COMMA)){ - this._readWhitespace(); - selector = this._selector(); - if (selector !== null){ - selectors.push(selector); - } else { - this._unexpectedToken(tokenStream.LT(1)); - } - } - } - - return selectors.length ? selectors : null; - }, - _selector: function(){ - - var tokenStream = this._tokenStream, - selector = [], - nextSelector = null, - combinator = null, - ws = null; - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null){ - return null; - } - - selector.push(nextSelector); - - do { - combinator = this._combinator(); - - if (combinator !== null){ - selector.push(combinator); - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null){ - this._unexpectedToken(tokenStream.LT(1)); - } else { - selector.push(nextSelector); - } - } else { - if (this._readWhitespace()){ - ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); - combinator = this._combinator(); - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null){ - if (combinator !== null){ - this._unexpectedToken(tokenStream.LT(1)); - } - } else { - - if (combinator !== null){ - selector.push(combinator); - } else { - selector.push(ws); - } - - selector.push(nextSelector); - } - } else { - break; - } - - } - } while(true); - - return new Selector(selector, selector[0].line, selector[0].col); - }, - _simple_selector_sequence: function(){ - - var tokenStream = this._tokenStream, - elementName = null, - modifiers = [], - selectorText= "", - components = [ - function(){ - return tokenStream.match(Tokens.HASH) ? - new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : - null; - }, - this._class, - this._attrib, - this._pseudo, - this._negation - ], - i = 0, - len = components.length, - component = null, - found = false, - line, - col; - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - - elementName = this._type_selector(); - if (!elementName){ - elementName = this._universal(); - } - - if (elementName !== null){ - selectorText += elementName; - } - - while(true){ - if (tokenStream.peek() === Tokens.S){ - break; - } - while(i < len && component === null){ - component = components[i++].call(this); - } - - if (component === null){ - if (selectorText === ""){ - return null; - } else { - break; - } - } else { - i = 0; - modifiers.push(component); - selectorText += component.toString(); - component = null; - } - } - - - return selectorText !== "" ? - new SelectorPart(elementName, modifiers, selectorText, line, col) : - null; - }, - _type_selector: function(){ - - var tokenStream = this._tokenStream, - ns = this._namespace_prefix(), - elementName = this._element_name(); - - if (!elementName){ - if (ns){ - tokenStream.unget(); - if (ns.length > 1){ - tokenStream.unget(); - } - } - - return null; - } else { - if (ns){ - elementName.text = ns + elementName.text; - elementName.col -= ns.length; - } - return elementName; - } - }, - _class: function(){ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.DOT)){ - tokenStream.mustMatch(Tokens.IDENT); - token = tokenStream.token(); - return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); - } else { - return null; - } - - }, - _element_name: function(){ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); - return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); - - } else { - return null; - } - }, - _namespace_prefix: function(){ - var tokenStream = this._tokenStream, - value = ""; - if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ - - if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ - value += tokenStream.token().value; - } - - tokenStream.mustMatch(Tokens.PIPE); - value += "|"; - - } - - return value.length ? value : null; - }, - _universal: function(){ - var tokenStream = this._tokenStream, - value = "", - ns; - - ns = this._namespace_prefix(); - if(ns){ - value += ns; - } - - if(tokenStream.match(Tokens.STAR)){ - value += "*"; - } - - return value.length ? value : null; - - }, - _attrib: function(){ - - var tokenStream = this._tokenStream, - value = null, - ns, - token; - - if (tokenStream.match(Tokens.LBRACKET)){ - token = tokenStream.token(); - value = token.value; - value += this._readWhitespace(); - - ns = this._namespace_prefix(); - - if (ns){ - value += ns; - } - - tokenStream.mustMatch(Tokens.IDENT); - value += tokenStream.token().value; - value += this._readWhitespace(); - - if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, - Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ - - value += tokenStream.token().value; - value += this._readWhitespace(); - - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - value += tokenStream.token().value; - value += this._readWhitespace(); - } - - tokenStream.mustMatch(Tokens.RBRACKET); - - return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); - } else { - return null; - } - }, - _pseudo: function(){ - - var tokenStream = this._tokenStream, - pseudo = null, - colons = ":", - line, - col; - - if (tokenStream.match(Tokens.COLON)){ - - if (tokenStream.match(Tokens.COLON)){ - colons += ":"; - } - - if (tokenStream.match(Tokens.IDENT)){ - pseudo = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol - colons.length; - } else if (tokenStream.peek() == Tokens.FUNCTION){ - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol - colons.length; - pseudo = this._functional_pseudo(); - } - - if (pseudo){ - pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); - } - } - - return pseudo; - }, - _functional_pseudo: function(){ - - var tokenStream = this._tokenStream, - value = null; - - if(tokenStream.match(Tokens.FUNCTION)){ - value = tokenStream.token().value; - value += this._readWhitespace(); - value += this._expression(); - tokenStream.mustMatch(Tokens.RPAREN); - value += ")"; - } - - return value; - }, - _expression: function(){ - - var tokenStream = this._tokenStream, - value = ""; - - while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, - Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, - Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, - Tokens.RESOLUTION, Tokens.SLASH])){ - - value += tokenStream.token().value; - value += this._readWhitespace(); - } - - return value.length ? value : null; - - }, - _negation: function(){ - - var tokenStream = this._tokenStream, - line, - col, - value = "", - arg, - subpart = null; - - if (tokenStream.match(Tokens.NOT)){ - value = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - value += this._readWhitespace(); - arg = this._negation_arg(); - value += arg; - value += this._readWhitespace(); - tokenStream.match(Tokens.RPAREN); - value += tokenStream.token().value; - - subpart = new SelectorSubPart(value, "not", line, col); - subpart.args.push(arg); - } - - return subpart; - }, - _negation_arg: function(){ - - var tokenStream = this._tokenStream, - args = [ - this._type_selector, - this._universal, - function(){ - return tokenStream.match(Tokens.HASH) ? - new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : - null; - }, - this._class, - this._attrib, - this._pseudo - ], - arg = null, - i = 0, - len = args.length, - elementName, - line, - col, - part; - - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - - while(i < len && arg === null){ - - arg = args[i].call(this); - i++; - } - if (arg === null){ - this._unexpectedToken(tokenStream.LT(1)); - } - if (arg.type == "elementName"){ - part = new SelectorPart(arg, [], arg.toString(), line, col); - } else { - part = new SelectorPart(null, [arg], arg.toString(), line, col); - } - - return part; - }, - - _declaration: function(){ - - var tokenStream = this._tokenStream, - property = null, - expr = null, - prio = null, - error = null, - invalid = null, - propertyName= ""; - - property = this._property(); - if (property !== null){ - - tokenStream.mustMatch(Tokens.COLON); - this._readWhitespace(); - - expr = this._expr(); - if (!expr || expr.length === 0){ - this._unexpectedToken(tokenStream.LT(1)); - } - - prio = this._prio(); - propertyName = property.toString(); - if (this.options.starHack && property.hack == "*" || - this.options.underscoreHack && property.hack == "_") { - - propertyName = property.text; - } - - try { - this._validateProperty(propertyName, expr); - } catch (ex) { - invalid = ex; - } - - this.fire({ - type: "property", - property: property, - value: expr, - important: prio, - line: property.line, - col: property.col, - invalid: invalid - }); - - return true; - } else { - return false; - } - }, - - _prio: function(){ - - var tokenStream = this._tokenStream, - result = tokenStream.match(Tokens.IMPORTANT_SYM); - - this._readWhitespace(); - return result; - }, - - _expr: function(inFunction){ - - var tokenStream = this._tokenStream, - values = [], - value = null, - operator = null; - - value = this._term(inFunction); - if (value !== null){ - - values.push(value); - - do { - operator = this._operator(inFunction); - if (operator){ - values.push(operator); - } /*else { - values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); - valueParts = []; - }*/ - - value = this._term(inFunction); - - if (value === null){ - break; - } else { - values.push(value); - } - } while(true); - } - - return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; - }, - - _term: function(inFunction){ - - var tokenStream = this._tokenStream, - unary = null, - value = null, - endChar = null, - token, - line, - col; - unary = this._unary_operator(); - if (unary !== null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ - - value = this._ie_function(); - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ - - token = tokenStream.token(); - endChar = token.endChar; - value = token.value + this._expr(inFunction).text; - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - tokenStream.mustMatch(Tokens.type(endChar)); - value += endChar; - this._readWhitespace(); - } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, - Tokens.ANGLE, Tokens.TIME, - Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ - - value = tokenStream.token().value; - if (unary === null){ - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - this._readWhitespace(); - } else { - token = this._hexcolor(); - if (token === null){ - if (unary === null){ - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - } - if (value === null){ - if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ - value = this._ie_function(); - } else { - value = this._function(); - } - } - - } else { - value = token.value; - if (unary === null){ - line = token.startLine; - col = token.startCol; - } - } - - } - - return value !== null ? - new PropertyValuePart(unary !== null ? unary + value : value, line, col) : - null; - - }, - - _function: function(){ - - var tokenStream = this._tokenStream, - functionText = null, - expr = null, - lt; - - if (tokenStream.match(Tokens.FUNCTION)){ - functionText = tokenStream.token().value; - this._readWhitespace(); - expr = this._expr(true); - functionText += expr; - if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ - do { - - if (this._readWhitespace()){ - functionText += tokenStream.token().value; - } - if (tokenStream.LA(0) == Tokens.COMMA){ - functionText += tokenStream.token().value; - } - - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; - - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - } - } while(tokenStream.match([Tokens.COMMA, Tokens.S])); - } - - tokenStream.match(Tokens.RPAREN); - functionText += ")"; - this._readWhitespace(); - } - - return functionText; - }, - - _ie_function: function(){ - - var tokenStream = this._tokenStream, - functionText = null, - expr = null, - lt; - if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ - functionText = tokenStream.token().value; - - do { - - if (this._readWhitespace()){ - functionText += tokenStream.token().value; - } - if (tokenStream.LA(0) == Tokens.COMMA){ - functionText += tokenStream.token().value; - } - - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; - - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - } - } while(tokenStream.match([Tokens.COMMA, Tokens.S])); - - tokenStream.match(Tokens.RPAREN); - functionText += ")"; - this._readWhitespace(); - } - - return functionText; - }, - - _hexcolor: function(){ - - var tokenStream = this._tokenStream, - token = null, - color; - - if(tokenStream.match(Tokens.HASH)){ - - token = tokenStream.token(); - color = token.value; - if (!/#[a-f0-9]{3,6}/i.test(color)){ - throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); - } - this._readWhitespace(); - } - - return token; - }, - - _keyframes: function(){ - var tokenStream = this._tokenStream, - token, - tt, - name, - prefix = ""; - - tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); - token = tokenStream.token(); - if (/^@\-([^\-]+)\-/.test(token.value)) { - prefix = RegExp.$1; - } - - this._readWhitespace(); - name = this._keyframe_name(); - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.LBRACE); - - this.fire({ - type: "startkeyframes", - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol - }); - - this._readWhitespace(); - tt = tokenStream.peek(); - while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { - this._keyframe_rule(); - this._readWhitespace(); - tt = tokenStream.peek(); - } - - this.fire({ - type: "endkeyframes", - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol - }); - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.RBRACE); - - }, - - _keyframe_name: function(){ - var tokenStream = this._tokenStream, - token; - - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - return SyntaxUnit.fromToken(tokenStream.token()); - }, - - _keyframe_rule: function(){ - var tokenStream = this._tokenStream, - token, - keyList = this._key_list(); - - this.fire({ - type: "startkeyframerule", - keys: keyList, - line: keyList[0].line, - col: keyList[0].col - }); - - this._readDeclarations(true); - - this.fire({ - type: "endkeyframerule", - keys: keyList, - line: keyList[0].line, - col: keyList[0].col - }); - - }, - - _key_list: function(){ - var tokenStream = this._tokenStream, - token, - key, - keyList = []; - keyList.push(this._key()); - - this._readWhitespace(); - - while(tokenStream.match(Tokens.COMMA)){ - this._readWhitespace(); - keyList.push(this._key()); - this._readWhitespace(); - } - - return keyList; - }, - - _key: function(){ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.PERCENTAGE)){ - return SyntaxUnit.fromToken(tokenStream.token()); - } else if (tokenStream.match(Tokens.IDENT)){ - token = tokenStream.token(); - - if (/from|to/i.test(token.value)){ - return SyntaxUnit.fromToken(token); - } - - tokenStream.unget(); - } - this._unexpectedToken(tokenStream.LT(1)); - }, - _skipCruft: function(){ - while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ - } - }, - _readDeclarations: function(checkStart, readMargins){ - var tokenStream = this._tokenStream, - tt; - - - this._readWhitespace(); - - if (checkStart){ - tokenStream.mustMatch(Tokens.LBRACE); - } - - this._readWhitespace(); - - try { - - while(true){ - - if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ - } else if (this._declaration()){ - if (!tokenStream.match(Tokens.SEMICOLON)){ - break; - } - } else { - break; - } - this._readWhitespace(); - } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - - } catch (ex) { - if (ex instanceof SyntaxError && !this.options.strict){ - this.fire({ - type: "error", - error: ex, - message: ex.message, - line: ex.line, - col: ex.col - }); - tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); - if (tt == Tokens.SEMICOLON){ - this._readDeclarations(false, readMargins); - } else if (tt != Tokens.RBRACE){ - throw ex; - } - - } else { - throw ex; - } - } - - }, - _readWhitespace: function(){ - - var tokenStream = this._tokenStream, - ws = ""; - - while(tokenStream.match(Tokens.S)){ - ws += tokenStream.token().value; - } - - return ws; - }, - _unexpectedToken: function(token){ - throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); - }, - _verifyEnd: function(){ - if (this._tokenStream.LA(1) != Tokens.EOF){ - this._unexpectedToken(this._tokenStream.LT(1)); - } - }, - _validateProperty: function(property, value){ - Validation.validate(property, value); - }, - - parse: function(input){ - this._tokenStream = new TokenStream(input, Tokens); - this._stylesheet(); - }, - - parseStyleSheet: function(input){ - return this.parse(input); - }, - - parseMediaQuery: function(input){ - this._tokenStream = new TokenStream(input, Tokens); - var result = this._media_query(); - this._verifyEnd(); - return result; - }, - parsePropertyValue: function(input){ - - this._tokenStream = new TokenStream(input, Tokens); - this._readWhitespace(); - - var result = this._expr(); - this._readWhitespace(); - this._verifyEnd(); - return result; - }, - parseRule: function(input){ - this._tokenStream = new TokenStream(input, Tokens); - this._readWhitespace(); - - var result = this._ruleset(); - this._readWhitespace(); - this._verifyEnd(); - return result; - }, - parseSelector: function(input){ - - this._tokenStream = new TokenStream(input, Tokens); - this._readWhitespace(); - - var result = this._selector(); - this._readWhitespace(); - this._verifyEnd(); - return result; - }, - parseStyleAttribute: function(input){ - input += "}"; // for error recovery in _readDeclarations() - this._tokenStream = new TokenStream(input, Tokens); - this._readDeclarations(); - } - }; - for (prop in additions){ - if (additions.hasOwnProperty(prop)){ - proto[prop] = additions[prop]; - } - } - - return proto; -}(); -var Properties = { - "align-items" : "flex-start | flex-end | center | baseline | stretch", - "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", - "align-self" : "auto | flex-start | flex-end | center | baseline | stretch", - "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", - "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", - "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", - "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>", - "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", - "animation" : 1, - "animation-delay" : { multi: "<time>", comma: true }, - "animation-direction" : { multi: "normal | alternate", comma: true }, - "animation-duration" : { multi: "<time>", comma: true }, - "animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true }, - "animation-iteration-count" : { multi: "<number> | infinite", comma: true }, - "animation-name" : { multi: "none | <ident>", comma: true }, - "animation-play-state" : { multi: "running | paused", comma: true }, - "animation-timing-function" : 1, - "-moz-animation-delay" : { multi: "<time>", comma: true }, - "-moz-animation-direction" : { multi: "normal | alternate", comma: true }, - "-moz-animation-duration" : { multi: "<time>", comma: true }, - "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, - "-moz-animation-name" : { multi: "none | <ident>", comma: true }, - "-moz-animation-play-state" : { multi: "running | paused", comma: true }, - - "-ms-animation-delay" : { multi: "<time>", comma: true }, - "-ms-animation-direction" : { multi: "normal | alternate", comma: true }, - "-ms-animation-duration" : { multi: "<time>", comma: true }, - "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, - "-ms-animation-name" : { multi: "none | <ident>", comma: true }, - "-ms-animation-play-state" : { multi: "running | paused", comma: true }, - - "-webkit-animation-delay" : { multi: "<time>", comma: true }, - "-webkit-animation-direction" : { multi: "normal | alternate", comma: true }, - "-webkit-animation-duration" : { multi: "<time>", comma: true }, - "-webkit-animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true }, - "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, - "-webkit-animation-name" : { multi: "none | <ident>", comma: true }, - "-webkit-animation-play-state" : { multi: "running | paused", comma: true }, - - "-o-animation-delay" : { multi: "<time>", comma: true }, - "-o-animation-direction" : { multi: "normal | alternate", comma: true }, - "-o-animation-duration" : { multi: "<time>", comma: true }, - "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, - "-o-animation-name" : { multi: "none | <ident>", comma: true }, - "-o-animation-play-state" : { multi: "running | paused", comma: true }, - - "appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit", - "azimuth" : function (expression) { - var simple = "<angle> | leftwards | rightwards | inherit", - direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side", - behind = false, - valid = false, - part; - - if (!ValidationTypes.isAny(expression, simple)) { - if (ValidationTypes.isAny(expression, "behind")) { - behind = true; - valid = true; - } - - if (ValidationTypes.isAny(expression, direction)) { - valid = true; - if (!behind) { - ValidationTypes.isAny(expression, "behind"); - } - } - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col); - } - } - }, - "backface-visibility" : "visible | hidden", - "background" : 1, - "background-attachment" : { multi: "<attachment>", comma: true }, - "background-clip" : { multi: "<box>", comma: true }, - "background-color" : "<color> | inherit", - "background-image" : { multi: "<bg-image>", comma: true }, - "background-origin" : { multi: "<box>", comma: true }, - "background-position" : { multi: "<bg-position>", comma: true }, - "background-repeat" : { multi: "<repeat-style>" }, - "background-size" : { multi: "<bg-size>", comma: true }, - "baseline-shift" : "baseline | sub | super | <percentage> | <length>", - "behavior" : 1, - "binding" : 1, - "bleed" : "<length>", - "bookmark-label" : "<content> | <attr> | <string>", - "bookmark-level" : "none | <integer>", - "bookmark-state" : "open | closed", - "bookmark-target" : "none | <uri> | <attr>", - "border" : "<border-width> || <border-style> || <color>", - "border-bottom" : "<border-width> || <border-style> || <color>", - "border-bottom-color" : "<color> | inherit", - "border-bottom-left-radius" : "<x-one-radius>", - "border-bottom-right-radius" : "<x-one-radius>", - "border-bottom-style" : "<border-style>", - "border-bottom-width" : "<border-width>", - "border-collapse" : "collapse | separate | inherit", - "border-color" : { multi: "<color> | inherit", max: 4 }, - "border-image" : 1, - "border-image-outset" : { multi: "<length> | <number>", max: 4 }, - "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 }, - "border-image-slice" : function(expression) { - - var valid = false, - numeric = "<number> | <percentage>", - fill = false, - count = 0, - max = 4, - part; - - if (ValidationTypes.isAny(expression, "fill")) { - fill = true; - valid = true; - } - - while (expression.hasNext() && count < max) { - valid = ValidationTypes.isAny(expression, numeric); - if (!valid) { - break; - } - count++; - } - - - if (!fill) { - ValidationTypes.isAny(expression, "fill"); - } else { - valid = true; - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col); - } - } - }, - "border-image-source" : "<image> | none", - "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 }, - "border-left" : "<border-width> || <border-style> || <color>", - "border-left-color" : "<color> | inherit", - "border-left-style" : "<border-style>", - "border-left-width" : "<border-width>", - "border-radius" : function(expression) { - - var valid = false, - simple = "<length> | <percentage> | inherit", - slash = false, - fill = false, - count = 0, - max = 8, - part; - - while (expression.hasNext() && count < max) { - valid = ValidationTypes.isAny(expression, simple); - if (!valid) { - - if (expression.peek() == "/" && count > 0 && !slash) { - slash = true; - max = count + 5; - expression.next(); - } else { - break; - } - } - count++; - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col); - } - } - }, - "border-right" : "<border-width> || <border-style> || <color>", - "border-right-color" : "<color> | inherit", - "border-right-style" : "<border-style>", - "border-right-width" : "<border-width>", - "border-spacing" : { multi: "<length> | inherit", max: 2 }, - "border-style" : { multi: "<border-style>", max: 4 }, - "border-top" : "<border-width> || <border-style> || <color>", - "border-top-color" : "<color> | inherit", - "border-top-left-radius" : "<x-one-radius>", - "border-top-right-radius" : "<x-one-radius>", - "border-top-style" : "<border-style>", - "border-top-width" : "<border-width>", - "border-width" : { multi: "<border-width>", max: 4 }, - "bottom" : "<margin-width> | inherit", - "-moz-box-align" : "start | end | center | baseline | stretch", - "-moz-box-decoration-break" : "slice |clone", - "-moz-box-direction" : "normal | reverse | inherit", - "-moz-box-flex" : "<number>", - "-moz-box-flex-group" : "<integer>", - "-moz-box-lines" : "single | multiple", - "-moz-box-ordinal-group" : "<integer>", - "-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit", - "-moz-box-pack" : "start | end | center | justify", - "-webkit-box-align" : "start | end | center | baseline | stretch", - "-webkit-box-decoration-break" : "slice |clone", - "-webkit-box-direction" : "normal | reverse | inherit", - "-webkit-box-flex" : "<number>", - "-webkit-box-flex-group" : "<integer>", - "-webkit-box-lines" : "single | multiple", - "-webkit-box-ordinal-group" : "<integer>", - "-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit", - "-webkit-box-pack" : "start | end | center | justify", - "box-shadow" : function (expression) { - var result = false, - part; - - if (!ValidationTypes.isAny(expression, "none")) { - Validation.multiProperty("<shadow>", expression, true, Infinity); - } else { - if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } - } - }, - "box-sizing" : "content-box | border-box | inherit", - "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column", - "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column", - "break-inside" : "auto | avoid | avoid-page | avoid-column", - "caption-side" : "top | bottom | inherit", - "clear" : "none | right | left | both | inherit", - "clip" : 1, - "color" : "<color> | inherit", - "color-profile" : 1, - "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/ - "column-fill" : "auto | balance", - "column-gap" : "<length> | normal", - "column-rule" : "<border-width> || <border-style> || <color>", - "column-rule-color" : "<color>", - "column-rule-style" : "<border-style>", - "column-rule-width" : "<border-width>", - "column-span" : "none | all", - "column-width" : "<length> | auto", - "columns" : 1, - "content" : 1, - "counter-increment" : 1, - "counter-reset" : 1, - "crop" : "<shape> | auto", - "cue" : "cue-after | cue-before | inherit", - "cue-after" : 1, - "cue-before" : 1, - "cursor" : 1, - "direction" : "ltr | rtl | inherit", - "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", - "dominant-baseline" : 1, - "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>", - "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", - "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>", - "drop-initial-before-align" : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", - "drop-initial-size" : "auto | line | <length> | <percentage>", - "drop-initial-value" : "initial | <integer>", - "elevation" : "<angle> | below | level | above | higher | lower | inherit", - "empty-cells" : "show | hide | inherit", - "filter" : 1, - "fit" : "fill | hidden | meet | slice", - "fit-position" : 1, - "flex" : "<flex>", - "flex-basis" : "<width>", - "flex-direction" : "row | row-reverse | column | column-reverse", - "flex-flow" : "<flex-direction> || <flex-wrap>", - "flex-grow" : "<number>", - "flex-shrink" : "<number>", - "flex-wrap" : "nowrap | wrap | wrap-reverse", - "-webkit-flex" : "<flex>", - "-webkit-flex-basis" : "<width>", - "-webkit-flex-direction" : "row | row-reverse | column | column-reverse", - "-webkit-flex-flow" : "<flex-direction> || <flex-wrap>", - "-webkit-flex-grow" : "<number>", - "-webkit-flex-shrink" : "<number>", - "-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse", - "-ms-flex" : "<flex>", - "-ms-flex-align" : "start | end | center | stretch | baseline", - "-ms-flex-direction" : "row | row-reverse | column | column-reverse | inherit", - "-ms-flex-order" : "<number>", - "-ms-flex-pack" : "start | end | center | justify", - "-ms-flex-wrap" : "nowrap | wrap | wrap-reverse", - "float" : "left | right | none | inherit", - "float-offset" : 1, - "font" : 1, - "font-family" : 1, - "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit", - "font-size-adjust" : "<number> | none | inherit", - "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit", - "font-style" : "normal | italic | oblique | inherit", - "font-variant" : "normal | small-caps | inherit", - "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit", - "grid-cell-stacking" : "columns | rows | layer", - "grid-column" : 1, - "grid-columns" : 1, - "grid-column-align" : "start | end | center | stretch", - "grid-column-sizing" : 1, - "grid-column-span" : "<integer>", - "grid-flow" : "none | rows | columns", - "grid-layer" : "<integer>", - "grid-row" : 1, - "grid-rows" : 1, - "grid-row-align" : "start | end | center | stretch", - "grid-row-span" : "<integer>", - "grid-row-sizing" : 1, - "hanging-punctuation" : 1, - "height" : "<margin-width> | <content-sizing> | inherit", - "hyphenate-after" : "<integer> | auto", - "hyphenate-before" : "<integer> | auto", - "hyphenate-character" : "<string> | auto", - "hyphenate-lines" : "no-limit | <integer>", - "hyphenate-resource" : 1, - "hyphens" : "none | manual | auto", - "icon" : 1, - "image-orientation" : "angle | auto", - "image-rendering" : 1, - "image-resolution" : 1, - "inline-box-align" : "initial | last | <integer>", - "justify-content" : "flex-start | flex-end | center | space-between | space-around", - "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around", - "left" : "<margin-width> | inherit", - "letter-spacing" : "<length> | normal | inherit", - "line-height" : "<number> | <length> | <percentage> | normal | inherit", - "line-break" : "auto | loose | normal | strict", - "line-stacking" : 1, - "line-stacking-ruby" : "exclude-ruby | include-ruby", - "line-stacking-shift" : "consider-shifts | disregard-shifts", - "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height", - "list-style" : 1, - "list-style-image" : "<uri> | none | inherit", - "list-style-position" : "inside | outside | inherit", - "list-style-type" : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit", - "margin" : { multi: "<margin-width> | inherit", max: 4 }, - "margin-bottom" : "<margin-width> | inherit", - "margin-left" : "<margin-width> | inherit", - "margin-right" : "<margin-width> | inherit", - "margin-top" : "<margin-width> | inherit", - "mark" : 1, - "mark-after" : 1, - "mark-before" : 1, - "marks" : 1, - "marquee-direction" : 1, - "marquee-play-count" : 1, - "marquee-speed" : 1, - "marquee-style" : 1, - "max-height" : "<length> | <percentage> | <content-sizing> | none | inherit", - "max-width" : "<length> | <percentage> | <content-sizing> | none | inherit", - "min-height" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit", - "min-width" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit", - "move-to" : 1, - "nav-down" : 1, - "nav-index" : 1, - "nav-left" : 1, - "nav-right" : 1, - "nav-up" : 1, - "opacity" : "<number> | inherit", - "order" : "<integer>", - "-webkit-order" : "<integer>", - "orphans" : "<integer> | inherit", - "outline" : 1, - "outline-color" : "<color> | invert | inherit", - "outline-offset" : 1, - "outline-style" : "<border-style> | inherit", - "outline-width" : "<border-width> | inherit", - "overflow" : "visible | hidden | scroll | auto | inherit", - "overflow-style" : 1, - "overflow-wrap" : "normal | break-word", - "overflow-x" : 1, - "overflow-y" : 1, - "padding" : { multi: "<padding-width> | inherit", max: 4 }, - "padding-bottom" : "<padding-width> | inherit", - "padding-left" : "<padding-width> | inherit", - "padding-right" : "<padding-width> | inherit", - "padding-top" : "<padding-width> | inherit", - "page" : 1, - "page-break-after" : "auto | always | avoid | left | right | inherit", - "page-break-before" : "auto | always | avoid | left | right | inherit", - "page-break-inside" : "auto | avoid | inherit", - "page-policy" : 1, - "pause" : 1, - "pause-after" : 1, - "pause-before" : 1, - "perspective" : 1, - "perspective-origin" : 1, - "phonemes" : 1, - "pitch" : 1, - "pitch-range" : 1, - "play-during" : 1, - "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit", - "position" : "static | relative | absolute | fixed | inherit", - "presentation-level" : 1, - "punctuation-trim" : 1, - "quotes" : 1, - "rendering-intent" : 1, - "resize" : 1, - "rest" : 1, - "rest-after" : 1, - "rest-before" : 1, - "richness" : 1, - "right" : "<margin-width> | inherit", - "rotation" : 1, - "rotation-point" : 1, - "ruby-align" : 1, - "ruby-overhang" : 1, - "ruby-position" : 1, - "ruby-span" : 1, - "size" : 1, - "speak" : "normal | none | spell-out | inherit", - "speak-header" : "once | always | inherit", - "speak-numeral" : "digits | continuous | inherit", - "speak-punctuation" : "code | none | inherit", - "speech-rate" : 1, - "src" : 1, - "stress" : 1, - "string-set" : 1, - - "table-layout" : "auto | fixed | inherit", - "tab-size" : "<integer> | <length>", - "target" : 1, - "target-name" : 1, - "target-new" : 1, - "target-position" : 1, - "text-align" : "left | right | center | justify | inherit" , - "text-align-last" : 1, - "text-decoration" : 1, - "text-emphasis" : 1, - "text-height" : 1, - "text-indent" : "<length> | <percentage> | inherit", - "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida", - "text-outline" : 1, - "text-overflow" : 1, - "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit", - "text-shadow" : 1, - "text-transform" : "capitalize | uppercase | lowercase | none | inherit", - "text-wrap" : "normal | none | avoid", - "top" : "<margin-width> | inherit", - "-ms-touch-action" : "auto | none | pan-x | pan-y", - "touch-action" : "auto | none | pan-x | pan-y", - "transform" : 1, - "transform-origin" : 1, - "transform-style" : 1, - "transition" : 1, - "transition-delay" : 1, - "transition-duration" : 1, - "transition-property" : 1, - "transition-timing-function" : 1, - "unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit", - "user-modify" : "read-only | read-write | write-only | inherit", - "user-select" : "none | text | toggle | element | elements | all | inherit", - "vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>", - "visibility" : "visible | hidden | collapse | inherit", - "voice-balance" : 1, - "voice-duration" : 1, - "voice-family" : 1, - "voice-pitch" : 1, - "voice-pitch-range" : 1, - "voice-rate" : 1, - "voice-stress" : 1, - "voice-volume" : 1, - "volume" : 1, - "white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap", //http://perishablepress.com/wrapping-content/ - "white-space-collapse" : 1, - "widows" : "<integer> | inherit", - "width" : "<length> | <percentage> | <content-sizing> | auto | inherit", - "word-break" : "normal | keep-all | break-all", - "word-spacing" : "<length> | normal | inherit", - "word-wrap" : "normal | break-word", - "writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit", - "z-index" : "<integer> | auto | inherit", - "zoom" : "<number> | <percentage> | normal" -}; -function PropertyName(text, hack, line, col){ - - SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE); - this.hack = hack; - -} - -PropertyName.prototype = new SyntaxUnit(); -PropertyName.prototype.constructor = PropertyName; -PropertyName.prototype.toString = function(){ - return (this.hack ? this.hack : "") + this.text; -}; -function PropertyValue(parts, line, col){ - - SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE); - this.parts = parts; - -} - -PropertyValue.prototype = new SyntaxUnit(); -PropertyValue.prototype.constructor = PropertyValue; -function PropertyValueIterator(value){ - this._i = 0; - this._parts = value.parts; - this._marks = []; - this.value = value; - -} -PropertyValueIterator.prototype.count = function(){ - return this._parts.length; -}; -PropertyValueIterator.prototype.isFirst = function(){ - return this._i === 0; -}; -PropertyValueIterator.prototype.hasNext = function(){ - return (this._i < this._parts.length); -}; -PropertyValueIterator.prototype.mark = function(){ - this._marks.push(this._i); -}; -PropertyValueIterator.prototype.peek = function(count){ - return this.hasNext() ? this._parts[this._i + (count || 0)] : null; -}; -PropertyValueIterator.prototype.next = function(){ - return this.hasNext() ? this._parts[this._i++] : null; -}; -PropertyValueIterator.prototype.previous = function(){ - return this._i > 0 ? this._parts[--this._i] : null; -}; -PropertyValueIterator.prototype.restore = function(){ - if (this._marks.length){ - this._i = this._marks.pop(); - } -}; -function PropertyValuePart(text, line, col){ - - SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE); - this.type = "unknown"; - - var temp; - if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension - this.type = "dimension"; - this.value = +RegExp.$1; - this.units = RegExp.$2; - switch(this.units.toLowerCase()){ - - case "em": - case "rem": - case "ex": - case "px": - case "cm": - case "mm": - case "in": - case "pt": - case "pc": - case "ch": - case "vh": - case "vw": - case "vmax": - case "vmin": - this.type = "length"; - break; - - case "deg": - case "rad": - case "grad": - this.type = "angle"; - break; - - case "ms": - case "s": - this.type = "time"; - break; - - case "hz": - case "khz": - this.type = "frequency"; - break; - - case "dpi": - case "dpcm": - this.type = "resolution"; - break; - - } - - } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage - this.type = "percentage"; - this.value = +RegExp.$1; - } else if (/^([+\-]?\d+)$/i.test(text)){ //integer - this.type = "integer"; - this.value = +RegExp.$1; - } else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number - this.type = "number"; - this.value = +RegExp.$1; - - } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor - this.type = "color"; - temp = RegExp.$1; - if (temp.length == 3){ - this.red = parseInt(temp.charAt(0)+temp.charAt(0),16); - this.green = parseInt(temp.charAt(1)+temp.charAt(1),16); - this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16); - } else { - this.red = parseInt(temp.substring(0,2),16); - this.green = parseInt(temp.substring(2,4),16); - this.blue = parseInt(temp.substring(4,6),16); - } - } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers - this.type = "color"; - this.red = +RegExp.$1; - this.green = +RegExp.$2; - this.blue = +RegExp.$3; - } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages - this.type = "color"; - this.red = +RegExp.$1 * 255 / 100; - this.green = +RegExp.$2 * 255 / 100; - this.blue = +RegExp.$3 * 255 / 100; - } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers - this.type = "color"; - this.red = +RegExp.$1; - this.green = +RegExp.$2; - this.blue = +RegExp.$3; - this.alpha = +RegExp.$4; - } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages - this.type = "color"; - this.red = +RegExp.$1 * 255 / 100; - this.green = +RegExp.$2 * 255 / 100; - this.blue = +RegExp.$3 * 255 / 100; - this.alpha = +RegExp.$4; - } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl() - this.type = "color"; - this.hue = +RegExp.$1; - this.saturation = +RegExp.$2 / 100; - this.lightness = +RegExp.$3 / 100; - } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages - this.type = "color"; - this.hue = +RegExp.$1; - this.saturation = +RegExp.$2 / 100; - this.lightness = +RegExp.$3 / 100; - this.alpha = +RegExp.$4; - } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI - this.type = "uri"; - this.uri = RegExp.$1; - } else if (/^([^\(]+)\(/i.test(text)){ - this.type = "function"; - this.name = RegExp.$1; - this.value = text; - } else if (/^["'][^"']*["']/.test(text)){ //string - this.type = "string"; - this.value = eval(text); - } else if (Colors[text.toLowerCase()]){ //named color - this.type = "color"; - temp = Colors[text.toLowerCase()].substring(1); - this.red = parseInt(temp.substring(0,2),16); - this.green = parseInt(temp.substring(2,4),16); - this.blue = parseInt(temp.substring(4,6),16); - } else if (/^[\,\/]$/.test(text)){ - this.type = "operator"; - this.value = text; - } else if (/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)){ - this.type = "identifier"; - this.value = text; - } - -} - -PropertyValuePart.prototype = new SyntaxUnit(); -PropertyValuePart.prototype.constructor = PropertyValuePart; -PropertyValuePart.fromToken = function(token){ - return new PropertyValuePart(token.value, token.startLine, token.startCol); -}; -var Pseudos = { - ":first-letter": 1, - ":first-line": 1, - ":before": 1, - ":after": 1 -}; - -Pseudos.ELEMENT = 1; -Pseudos.CLASS = 2; - -Pseudos.isElement = function(pseudo){ - return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT; -}; -function Selector(parts, line, col){ - - SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE); - this.parts = parts; - this.specificity = Specificity.calculate(this); - -} - -Selector.prototype = new SyntaxUnit(); -Selector.prototype.constructor = Selector; -function SelectorPart(elementName, modifiers, text, line, col){ - - SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE); - this.elementName = elementName; - this.modifiers = modifiers; - -} - -SelectorPart.prototype = new SyntaxUnit(); -SelectorPart.prototype.constructor = SelectorPart; -function SelectorSubPart(text, type, line, col){ - - SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE); - this.type = type; - this.args = []; - -} - -SelectorSubPart.prototype = new SyntaxUnit(); -SelectorSubPart.prototype.constructor = SelectorSubPart; -function Specificity(a, b, c, d){ - this.a = a; - this.b = b; - this.c = c; - this.d = d; -} - -Specificity.prototype = { - constructor: Specificity, - compare: function(other){ - var comps = ["a", "b", "c", "d"], - i, len; - - for (i=0, len=comps.length; i < len; i++){ - if (this[comps[i]] < other[comps[i]]){ - return -1; - } else if (this[comps[i]] > other[comps[i]]){ - return 1; - } - } - - return 0; - }, - valueOf: function(){ - return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d; - }, - toString: function(){ - return this.a + "," + this.b + "," + this.c + "," + this.d; - } - -}; -Specificity.calculate = function(selector){ - - var i, len, - part, - b=0, c=0, d=0; - - function updateValues(part){ - - var i, j, len, num, - elementName = part.elementName ? part.elementName.text : "", - modifier; - - if (elementName && elementName.charAt(elementName.length-1) != "*") { - d++; - } - - for (i=0, len=part.modifiers.length; i < len; i++){ - modifier = part.modifiers[i]; - switch(modifier.type){ - case "class": - case "attribute": - c++; - break; - - case "id": - b++; - break; - - case "pseudo": - if (Pseudos.isElement(modifier.text)){ - d++; - } else { - c++; - } - break; - - case "not": - for (j=0, num=modifier.args.length; j < num; j++){ - updateValues(modifier.args[j]); - } - } - } - } - - for (i=0, len=selector.parts.length; i < len; i++){ - part = selector.parts[i]; - - if (part instanceof SelectorPart){ - updateValues(part); - } - } - - return new Specificity(0, b, c, d); -}; - -var h = /^[0-9a-fA-F]$/, - nonascii = /^[\u0080-\uFFFF]$/, - nl = /\n|\r\n|\r|\f/; - - -function isHexDigit(c){ - return c !== null && h.test(c); -} - -function isDigit(c){ - return c !== null && /\d/.test(c); -} - -function isWhitespace(c){ - return c !== null && /\s/.test(c); -} - -function isNewLine(c){ - return c !== null && nl.test(c); -} - -function isNameStart(c){ - return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c)); -} - -function isNameChar(c){ - return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c)); -} - -function isIdentStart(c){ - return c !== null && (isNameStart(c) || /\-\\/.test(c)); -} - -function mix(receiver, supplier){ - for (var prop in supplier){ - if (supplier.hasOwnProperty(prop)){ - receiver[prop] = supplier[prop]; - } - } - return receiver; -} -function TokenStream(input){ - TokenStreamBase.call(this, input, Tokens); -} - -TokenStream.prototype = mix(new TokenStreamBase(), { - _getToken: function(channel){ - - var c, - reader = this._reader, - token = null, - startLine = reader.getLine(), - startCol = reader.getCol(); - - c = reader.read(); - - - while(c){ - switch(c){ - case "/": - - if(reader.peek() == "*"){ - token = this.commentToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - case "|": - case "~": - case "^": - case "$": - case "*": - if(reader.peek() == "="){ - token = this.comparisonToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - case "\"": - case "'": - token = this.stringToken(c, startLine, startCol); - break; - case "#": - if (isNameChar(reader.peek())){ - token = this.hashToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - case ".": - if (isDigit(reader.peek())){ - token = this.numberToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - case "-": - if (reader.peek() == "-"){ //could be closing HTML-style comment - token = this.htmlCommentEndToken(c, startLine, startCol); - } else if (isNameStart(reader.peek())){ - token = this.identOrFunctionToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - case "!": - token = this.importantToken(c, startLine, startCol); - break; - case "@": - token = this.atRuleToken(c, startLine, startCol); - break; - case ":": - token = this.notToken(c, startLine, startCol); - break; - case "<": - token = this.htmlCommentStartToken(c, startLine, startCol); - break; - case "U": - case "u": - if (reader.peek() == "+"){ - token = this.unicodeRangeToken(c, startLine, startCol); - break; - } - default: - if (isDigit(c)){ - token = this.numberToken(c, startLine, startCol); - } else - if (isWhitespace(c)){ - token = this.whitespaceToken(c, startLine, startCol); - } else - if (isIdentStart(c)){ - token = this.identOrFunctionToken(c, startLine, startCol); - } else - { - token = this.charToken(c, startLine, startCol); - } - - - - - - - } - break; - } - - if (!token && c === null){ - token = this.createToken(Tokens.EOF,null,startLine,startCol); - } - - return token; - }, - createToken: function(tt, value, startLine, startCol, options){ - var reader = this._reader; - options = options || {}; - - return { - value: value, - type: tt, - channel: options.channel, - endChar: options.endChar, - hide: options.hide || false, - startLine: startLine, - startCol: startCol, - endLine: reader.getLine(), - endCol: reader.getCol() - }; - }, - atRuleToken: function(first, startLine, startCol){ - var rule = first, - reader = this._reader, - tt = Tokens.CHAR, - valid = false, - ident, - c; - reader.mark(); - ident = this.readName(); - rule = first + ident; - tt = Tokens.type(rule.toLowerCase()); - if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){ - if (rule.length > 1){ - tt = Tokens.UNKNOWN_SYM; - } else { - tt = Tokens.CHAR; - rule = first; - reader.reset(); - } - } - - return this.createToken(tt, rule, startLine, startCol); - }, - charToken: function(c, startLine, startCol){ - var tt = Tokens.type(c); - var opts = {}; - - if (tt == -1){ - tt = Tokens.CHAR; - } else { - opts.endChar = Tokens[tt].endChar; - } - - return this.createToken(tt, c, startLine, startCol, opts); - }, - commentToken: function(first, startLine, startCol){ - var reader = this._reader, - comment = this.readComment(first); - - return this.createToken(Tokens.COMMENT, comment, startLine, startCol); - }, - comparisonToken: function(c, startLine, startCol){ - var reader = this._reader, - comparison = c + reader.read(), - tt = Tokens.type(comparison) || Tokens.CHAR; - - return this.createToken(tt, comparison, startLine, startCol); - }, - hashToken: function(first, startLine, startCol){ - var reader = this._reader, - name = this.readName(first); - - return this.createToken(Tokens.HASH, name, startLine, startCol); - }, - htmlCommentStartToken: function(first, startLine, startCol){ - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(3); - - if (text == "<!--"){ - return this.createToken(Tokens.CDO, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - htmlCommentEndToken: function(first, startLine, startCol){ - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(2); - - if (text == "-->"){ - return this.createToken(Tokens.CDC, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - identOrFunctionToken: function(first, startLine, startCol){ - var reader = this._reader, - ident = this.readName(first), - tt = Tokens.IDENT; - if (reader.peek() == "("){ - ident += reader.read(); - if (ident.toLowerCase() == "url("){ - tt = Tokens.URI; - ident = this.readURI(ident); - if (ident.toLowerCase() == "url("){ - tt = Tokens.FUNCTION; - } - } else { - tt = Tokens.FUNCTION; - } - } else if (reader.peek() == ":"){ //might be an IE function - if (ident.toLowerCase() == "progid"){ - ident += reader.readTo("("); - tt = Tokens.IE_FUNCTION; - } - } - - return this.createToken(tt, ident, startLine, startCol); - }, - importantToken: function(first, startLine, startCol){ - var reader = this._reader, - important = first, - tt = Tokens.CHAR, - temp, - c; - - reader.mark(); - c = reader.read(); - - while(c){ - if (c == "/"){ - if (reader.peek() != "*"){ - break; - } else { - temp = this.readComment(c); - if (temp === ""){ //broken! - break; - } - } - } else if (isWhitespace(c)){ - important += c + this.readWhitespace(); - } else if (/i/i.test(c)){ - temp = reader.readCount(8); - if (/mportant/i.test(temp)){ - important += c + temp; - tt = Tokens.IMPORTANT_SYM; - - } - break; //we're done - } else { - break; - } - - c = reader.read(); - } - - if (tt == Tokens.CHAR){ - reader.reset(); - return this.charToken(first, startLine, startCol); - } else { - return this.createToken(tt, important, startLine, startCol); - } - - - }, - notToken: function(first, startLine, startCol){ - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(4); - - if (text.toLowerCase() == ":not("){ - return this.createToken(Tokens.NOT, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - numberToken: function(first, startLine, startCol){ - var reader = this._reader, - value = this.readNumber(first), - ident, - tt = Tokens.NUMBER, - c = reader.peek(); - - if (isIdentStart(c)){ - ident = this.readName(reader.read()); - value += ident; - - if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){ - tt = Tokens.LENGTH; - } else if (/^deg|^rad$|^grad$/i.test(ident)){ - tt = Tokens.ANGLE; - } else if (/^ms$|^s$/i.test(ident)){ - tt = Tokens.TIME; - } else if (/^hz$|^khz$/i.test(ident)){ - tt = Tokens.FREQ; - } else if (/^dpi$|^dpcm$/i.test(ident)){ - tt = Tokens.RESOLUTION; - } else { - tt = Tokens.DIMENSION; - } - - } else if (c == "%"){ - value += reader.read(); - tt = Tokens.PERCENTAGE; - } - - return this.createToken(tt, value, startLine, startCol); - }, - stringToken: function(first, startLine, startCol){ - var delim = first, - string = first, - reader = this._reader, - prev = first, - tt = Tokens.STRING, - c = reader.read(); - - while(c){ - string += c; - if (c == delim && prev != "\\"){ - break; - } - if (isNewLine(reader.peek()) && c != "\\"){ - tt = Tokens.INVALID; - break; - } - prev = c; - c = reader.read(); - } - if (c === null){ - tt = Tokens.INVALID; - } - - return this.createToken(tt, string, startLine, startCol); - }, - - unicodeRangeToken: function(first, startLine, startCol){ - var reader = this._reader, - value = first, - temp, - tt = Tokens.CHAR; - if (reader.peek() == "+"){ - reader.mark(); - value += reader.read(); - value += this.readUnicodeRangePart(true); - if (value.length == 2){ - reader.reset(); - } else { - - tt = Tokens.UNICODE_RANGE; - if (value.indexOf("?") == -1){ - - if (reader.peek() == "-"){ - reader.mark(); - temp = reader.read(); - temp += this.readUnicodeRangePart(false); - if (temp.length == 1){ - reader.reset(); - } else { - value += temp; - } - } - - } - } - } - - return this.createToken(tt, value, startLine, startCol); - }, - whitespaceToken: function(first, startLine, startCol){ - var reader = this._reader, - value = first + this.readWhitespace(); - return this.createToken(Tokens.S, value, startLine, startCol); - }, - - readUnicodeRangePart: function(allowQuestionMark){ - var reader = this._reader, - part = "", - c = reader.peek(); - while(isHexDigit(c) && part.length < 6){ - reader.read(); - part += c; - c = reader.peek(); - } - if (allowQuestionMark){ - while(c == "?" && part.length < 6){ - reader.read(); - part += c; - c = reader.peek(); - } - } - - return part; - }, - - readWhitespace: function(){ - var reader = this._reader, - whitespace = "", - c = reader.peek(); - - while(isWhitespace(c)){ - reader.read(); - whitespace += c; - c = reader.peek(); - } - - return whitespace; - }, - readNumber: function(first){ - var reader = this._reader, - number = first, - hasDot = (first == "."), - c = reader.peek(); - - - while(c){ - if (isDigit(c)){ - number += reader.read(); - } else if (c == "."){ - if (hasDot){ - break; - } else { - hasDot = true; - number += reader.read(); - } - } else { - break; - } - - c = reader.peek(); - } - - return number; - }, - readString: function(){ - var reader = this._reader, - delim = reader.read(), - string = delim, - prev = delim, - c = reader.peek(); - - while(c){ - c = reader.read(); - string += c; - if (c == delim && prev != "\\"){ - break; - } - if (isNewLine(reader.peek()) && c != "\\"){ - string = ""; - break; - } - prev = c; - c = reader.peek(); - } - if (c === null){ - string = ""; - } - - return string; - }, - readURI: function(first){ - var reader = this._reader, - uri = first, - inner = "", - c = reader.peek(); - - reader.mark(); - while(c && isWhitespace(c)){ - reader.read(); - c = reader.peek(); - } - if (c == "'" || c == "\""){ - inner = this.readString(); - } else { - inner = this.readURL(); - } - - c = reader.peek(); - while(c && isWhitespace(c)){ - reader.read(); - c = reader.peek(); - } - if (inner === "" || c != ")"){ - uri = first; - reader.reset(); - } else { - uri += inner + reader.read(); - } - - return uri; - }, - readURL: function(){ - var reader = this._reader, - url = "", - c = reader.peek(); - while (/^[!#$%&\\*-~]$/.test(c)){ - url += reader.read(); - c = reader.peek(); - } - - return url; - - }, - readName: function(first){ - var reader = this._reader, - ident = first || "", - c = reader.peek(); - - while(true){ - if (c == "\\"){ - ident += this.readEscape(reader.read()); - c = reader.peek(); - } else if(c && isNameChar(c)){ - ident += reader.read(); - c = reader.peek(); - } else { - break; - } - } - - return ident; - }, - - readEscape: function(first){ - var reader = this._reader, - cssEscape = first || "", - i = 0, - c = reader.peek(); - - if (isHexDigit(c)){ - do { - cssEscape += reader.read(); - c = reader.peek(); - } while(c && isHexDigit(c) && ++i < 6); - } - - if (cssEscape.length == 3 && /\s/.test(c) || - cssEscape.length == 7 || cssEscape.length == 1){ - reader.read(); - } else { - c = ""; - } - - return cssEscape + c; - }, - - readComment: function(first){ - var reader = this._reader, - comment = first || "", - c = reader.read(); - - if (c == "*"){ - while(c){ - comment += c; - if (comment.length > 2 && c == "*" && reader.peek() == "/"){ - comment += reader.read(); - break; - } - - c = reader.read(); - } - - return comment; - } else { - return ""; - } - - } -}); - -var Tokens = [ - { name: "CDO"}, - { name: "CDC"}, - { name: "S", whitespace: true/*, channel: "ws"*/}, - { name: "COMMENT", comment: true, hide: true, channel: "comment" }, - { name: "INCLUDES", text: "~="}, - { name: "DASHMATCH", text: "|="}, - { name: "PREFIXMATCH", text: "^="}, - { name: "SUFFIXMATCH", text: "$="}, - { name: "SUBSTRINGMATCH", text: "*="}, - { name: "STRING"}, - { name: "IDENT"}, - { name: "HASH"}, - { name: "IMPORT_SYM", text: "@import"}, - { name: "PAGE_SYM", text: "@page"}, - { name: "MEDIA_SYM", text: "@media"}, - { name: "FONT_FACE_SYM", text: "@font-face"}, - { name: "CHARSET_SYM", text: "@charset"}, - { name: "NAMESPACE_SYM", text: "@namespace"}, - { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]}, - { name: "UNKNOWN_SYM" }, - { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] }, - { name: "IMPORTANT_SYM"}, - { name: "LENGTH"}, - { name: "ANGLE"}, - { name: "TIME"}, - { name: "FREQ"}, - { name: "DIMENSION"}, - { name: "PERCENTAGE"}, - { name: "NUMBER"}, - { name: "URI"}, - { name: "FUNCTION"}, - { name: "UNICODE_RANGE"}, - { name: "INVALID"}, - { name: "PLUS", text: "+" }, - { name: "GREATER", text: ">"}, - { name: "COMMA", text: ","}, - { name: "TILDE", text: "~"}, - { name: "NOT"}, - { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"}, - { name: "TOPLEFT_SYM", text: "@top-left"}, - { name: "TOPCENTER_SYM", text: "@top-center"}, - { name: "TOPRIGHT_SYM", text: "@top-right"}, - { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"}, - { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"}, - { name: "BOTTOMLEFT_SYM", text: "@bottom-left"}, - { name: "BOTTOMCENTER_SYM", text: "@bottom-center"}, - { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"}, - { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"}, - { name: "LEFTTOP_SYM", text: "@left-top"}, - { name: "LEFTMIDDLE_SYM", text: "@left-middle"}, - { name: "LEFTBOTTOM_SYM", text: "@left-bottom"}, - { name: "RIGHTTOP_SYM", text: "@right-top"}, - { name: "RIGHTMIDDLE_SYM", text: "@right-middle"}, - { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"}, - { name: "RESOLUTION", state: "media"}, - { name: "IE_FUNCTION" }, - { name: "CHAR" }, - { - name: "PIPE", - text: "|" - }, - { - name: "SLASH", - text: "/" - }, - { - name: "MINUS", - text: "-" - }, - { - name: "STAR", - text: "*" - }, - - { - name: "LBRACE", - endChar: "}", - text: "{" - }, - { - name: "RBRACE", - text: "}" - }, - { - name: "LBRACKET", - endChar: "]", - text: "[" - }, - { - name: "RBRACKET", - text: "]" - }, - { - name: "EQUALS", - text: "=" - }, - { - name: "COLON", - text: ":" - }, - { - name: "SEMICOLON", - text: ";" - }, - - { - name: "LPAREN", - endChar: ")", - text: "(" - }, - { - name: "RPAREN", - text: ")" - }, - { - name: "DOT", - text: "." - } -]; - -(function(){ - - var nameMap = [], - typeMap = {}; - - Tokens.UNKNOWN = -1; - Tokens.unshift({name:"EOF"}); - for (var i=0, len = Tokens.length; i < len; i++){ - nameMap.push(Tokens[i].name); - Tokens[Tokens[i].name] = i; - if (Tokens[i].text){ - if (Tokens[i].text instanceof Array){ - for (var j=0; j < Tokens[i].text.length; j++){ - typeMap[Tokens[i].text[j]] = i; - } - } else { - typeMap[Tokens[i].text] = i; - } - } - } - - Tokens.name = function(tt){ - return nameMap[tt]; - }; - - Tokens.type = function(c){ - return typeMap[c] || -1; - }; - -})(); -var Validation = { - - validate: function(property, value){ - var name = property.toString().toLowerCase(), - parts = value.parts, - expression = new PropertyValueIterator(value), - spec = Properties[name], - part, - valid, - j, count, - msg, - types, - last, - literals, - max, multi, group; - - if (!spec) { - if (name.indexOf("-") !== 0){ //vendor prefixed are ok - throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col); - } - } else if (typeof spec != "number"){ - if (typeof spec == "string"){ - if (spec.indexOf("||") > -1) { - this.groupProperty(spec, expression); - } else { - this.singleProperty(spec, expression, 1); - } - - } else if (spec.multi) { - this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity); - } else if (typeof spec == "function") { - spec(expression); - } - - } - - }, - - singleProperty: function(types, expression, max, partial) { - - var result = false, - value = expression.value, - count = 0, - part; - - while (expression.hasNext() && count < max) { - result = ValidationTypes.isAny(expression, types); - if (!result) { - break; - } - count++; - } - - if (!result) { - if (expression.hasNext() && !expression.isFirst()) { - part = expression.peek(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); - } - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } - - }, - - multiProperty: function (types, expression, comma, max) { - - var result = false, - value = expression.value, - count = 0, - sep = false, - part; - - while(expression.hasNext() && !result && count < max) { - if (ValidationTypes.isAny(expression, types)) { - count++; - if (!expression.hasNext()) { - result = true; - - } else if (comma) { - if (expression.peek() == ",") { - part = expression.next(); - } else { - break; - } - } - } else { - break; - - } - } - - if (!result) { - if (expression.hasNext() && !expression.isFirst()) { - part = expression.peek(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - part = expression.previous(); - if (comma && part == ",") { - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); - } - } - - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } - - }, - - groupProperty: function (types, expression, comma) { - - var result = false, - value = expression.value, - typeCount = types.split("||").length, - groups = { count: 0 }, - partial = false, - name, - part; - - while(expression.hasNext() && !result) { - name = ValidationTypes.isAnyOfGroup(expression, types); - if (name) { - if (groups[name]) { - break; - } else { - groups[name] = 1; - groups.count++; - partial = true; - - if (groups.count == typeCount || !expression.hasNext()) { - result = true; - } - } - } else { - break; - } - } - - if (!result) { - if (partial && expression.hasNext()) { - part = expression.peek(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } else { - throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); - } - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); - } - } - - - -}; -function ValidationError(message, line, col){ - this.col = col; - this.line = line; - this.message = message; - -} -ValidationError.prototype = new Error(); -var ValidationTypes = { - - isLiteral: function (part, literals) { - var text = part.text.toString().toLowerCase(), - args = literals.split(" | "), - i, len, found = false; - - for (i=0,len=args.length; i < len && !found; i++){ - if (text == args[i].toLowerCase()){ - found = true; - } - } - - return found; - }, - - isSimple: function(type) { - return !!this.simple[type]; - }, - - isComplex: function(type) { - return !!this.complex[type]; - }, - isAny: function (expression, types) { - var args = types.split(" | "), - i, len, found = false; - - for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){ - found = this.isType(expression, args[i]); - } - - return found; - }, - isAnyOfGroup: function(expression, types) { - var args = types.split(" || "), - i, len, found = false; - - for (i=0,len=args.length; i < len && !found; i++){ - found = this.isType(expression, args[i]); - } - - return found ? args[i-1] : false; - }, - isType: function (expression, type) { - var part = expression.peek(), - result = false; - - if (type.charAt(0) != "<") { - result = this.isLiteral(part, type); - if (result) { - expression.next(); - } - } else if (this.simple[type]) { - result = this.simple[type](part); - if (result) { - expression.next(); - } - } else { - result = this.complex[type](expression); - } - - return result; - }, - - - - simple: { - - "<absolute-size>": function(part){ - return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large"); - }, - - "<attachment>": function(part){ - return ValidationTypes.isLiteral(part, "scroll | fixed | local"); - }, - - "<attr>": function(part){ - return part.type == "function" && part.name == "attr"; - }, - - "<bg-image>": function(part){ - return this["<image>"](part) || this["<gradient>"](part) || part == "none"; - }, - - "<gradient>": function(part) { - return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part); - }, - - "<box>": function(part){ - return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box"); - }, - - "<content>": function(part){ - return part.type == "function" && part.name == "content"; - }, - - "<relative-size>": function(part){ - return ValidationTypes.isLiteral(part, "smaller | larger"); - }, - "<ident>": function(part){ - return part.type == "identifier"; - }, - - "<length>": function(part){ - if (part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)){ - return true; - }else{ - return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0"; - } - }, - - "<color>": function(part){ - return part.type == "color" || part == "transparent"; - }, - - "<number>": function(part){ - return part.type == "number" || this["<integer>"](part); - }, - - "<integer>": function(part){ - return part.type == "integer"; - }, - - "<line>": function(part){ - return part.type == "integer"; - }, - - "<angle>": function(part){ - return part.type == "angle"; - }, - - "<uri>": function(part){ - return part.type == "uri"; - }, - - "<image>": function(part){ - return this["<uri>"](part); - }, - - "<percentage>": function(part){ - return part.type == "percentage" || part == "0"; - }, - - "<border-width>": function(part){ - return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick"); - }, - - "<border-style>": function(part){ - return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset"); - }, - - "<content-sizing>": function(part){ // http://www.w3.org/TR/css3-sizing/#width-height-keywords - return ValidationTypes.isLiteral(part, "fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content"); - }, - - "<margin-width>": function(part){ - return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto"); - }, - - "<padding-width>": function(part){ - return this["<length>"](part) || this["<percentage>"](part); - }, - - "<shape>": function(part){ - return part.type == "function" && (part.name == "rect" || part.name == "inset-rect"); - }, - - "<time>": function(part) { - return part.type == "time"; - }, - - "<flex-grow>": function(part){ - return this["<number>"](part); - }, - - "<flex-shrink>": function(part){ - return this["<number>"](part); - }, - - "<width>": function(part){ - return this["<margin-width>"](part); - }, - - "<flex-basis>": function(part){ - return this["<width>"](part); - }, - - "<flex-direction>": function(part){ - return ValidationTypes.isLiteral(part, "row | row-reverse | column | column-reverse"); - }, - - "<flex-wrap>": function(part){ - return ValidationTypes.isLiteral(part, "nowrap | wrap | wrap-reverse"); - } - }, - - complex: { - - "<bg-position>": function(expression){ - var types = this, - result = false, - numeric = "<percentage> | <length>", - xDir = "left | right", - yDir = "top | bottom", - count = 0, - hasNext = function() { - return expression.hasNext() && expression.peek() != ","; - }; - - while (expression.peek(count) && expression.peek(count) != ",") { - count++; - } - - if (count < 3) { - if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) { - result = true; - ValidationTypes.isAny(expression, yDir + " | center | " + numeric); - } else if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, xDir + " | center"); - } - } else { - if (ValidationTypes.isAny(expression, xDir)) { - if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, numeric)) { - if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, "center")) { - result = true; - } - } - } else if (ValidationTypes.isAny(expression, yDir)) { - if (ValidationTypes.isAny(expression, xDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, numeric)) { - if (ValidationTypes.isAny(expression, xDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, "center")) { - result = true; - } - } - } else if (ValidationTypes.isAny(expression, "center")) { - if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } - } - } - - return result; - }, - - "<bg-size>": function(expression){ - var types = this, - result = false, - numeric = "<percentage> | <length> | auto", - part, - i, len; - - if (ValidationTypes.isAny(expression, "cover | contain")) { - result = true; - } else if (ValidationTypes.isAny(expression, numeric)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } - - return result; - }, - - "<repeat-style>": function(expression){ - var result = false, - values = "repeat | space | round | no-repeat", - part; - - if (expression.hasNext()){ - part = expression.next(); - - if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) { - result = true; - } else if (ValidationTypes.isLiteral(part, values)) { - result = true; - - if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) { - expression.next(); - } - } - } - - return result; - - }, - - "<shadow>": function(expression) { - var result = false, - count = 0, - inset = false, - color = false, - part; - - if (expression.hasNext()) { - - if (ValidationTypes.isAny(expression, "inset")){ - inset = true; - } - - if (ValidationTypes.isAny(expression, "<color>")) { - color = true; - } - - while (ValidationTypes.isAny(expression, "<length>") && count < 4) { - count++; - } - - - if (expression.hasNext()) { - if (!color) { - ValidationTypes.isAny(expression, "<color>"); - } - - if (!inset) { - ValidationTypes.isAny(expression, "inset"); - } - - } - - result = (count >= 2 && count <= 4); - - } - - return result; - }, - - "<x-one-radius>": function(expression) { - var result = false, - simple = "<length> | <percentage> | inherit"; - - if (ValidationTypes.isAny(expression, simple)){ - result = true; - ValidationTypes.isAny(expression, simple); - } - - return result; - }, - - "<flex>": function(expression) { - var part, - result = false; - if (ValidationTypes.isAny(expression, "none | inherit")) { - result = true; - } else { - if (ValidationTypes.isType(expression, "<flex-grow>")) { - if (expression.peek()) { - if (ValidationTypes.isType(expression, "<flex-shrink>")) { - if (expression.peek()) { - result = ValidationTypes.isType(expression, "<flex-basis>"); - } else { - result = true; - } - } else if (ValidationTypes.isType(expression, "<flex-basis>")) { - result = expression.peek() === null; - } - } else { - result = true; - } - } else if (ValidationTypes.isType(expression, "<flex-basis>")) { - result = true; - } - } - - if (!result) { - part = expression.peek(); - throw new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression.value.text + "'.", part.line, part.col); - } - - return result; - } - } -}; - -parserlib.css = { -Colors :Colors, -Combinator :Combinator, -Parser :Parser, -PropertyName :PropertyName, -PropertyValue :PropertyValue, -PropertyValuePart :PropertyValuePart, -MediaFeature :MediaFeature, -MediaQuery :MediaQuery, -Selector :Selector, -SelectorPart :SelectorPart, -SelectorSubPart :SelectorSubPart, -Specificity :Specificity, -TokenStream :TokenStream, -Tokens :Tokens, -ValidationError :ValidationError -}; -})(); - -(function(){ -for(var prop in parserlib){ -exports[prop] = parserlib[prop]; -} -})(); - - -function objectToString(o) { - return Object.prototype.toString.call(o); -} -var util = { - isArray: function (ar) { - return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]'); - }, - isDate: function (d) { - return typeof d === 'object' && objectToString(d) === '[object Date]'; - }, - isRegExp: function (re) { - return typeof re === 'object' && objectToString(re) === '[object RegExp]'; - }, - getRegExpFlags: function (re) { - var flags = ''; - re.global && (flags += 'g'); - re.ignoreCase && (flags += 'i'); - re.multiline && (flags += 'm'); - return flags; - } -}; - - -if (typeof module === 'object') - module.exports = clone; - -function clone(parent, circular, depth, prototype) { - var allParents = []; - var allChildren = []; - - var useBuffer = typeof Buffer != 'undefined'; - - if (typeof circular == 'undefined') - circular = true; - - if (typeof depth == 'undefined') - depth = Infinity; - function _clone(parent, depth) { - if (parent === null) - return null; - - if (depth == 0) - return parent; - - var child; - if (typeof parent != 'object') { - return parent; - } - - if (util.isArray(parent)) { - child = []; - } else if (util.isRegExp(parent)) { - child = new RegExp(parent.source, util.getRegExpFlags(parent)); - if (parent.lastIndex) child.lastIndex = parent.lastIndex; - } else if (util.isDate(parent)) { - child = new Date(parent.getTime()); - } else if (useBuffer && Buffer.isBuffer(parent)) { - child = new Buffer(parent.length); - parent.copy(child); - return child; - } else { - if (typeof prototype == 'undefined') child = Object.create(Object.getPrototypeOf(parent)); - else child = Object.create(prototype); - } - - if (circular) { - var index = allParents.indexOf(parent); - - if (index != -1) { - return allChildren[index]; - } - allParents.push(parent); - allChildren.push(child); - } - - for (var i in parent) { - child[i] = _clone(parent[i], depth - 1); - } - - return child; - } - - return _clone(parent, depth); -} -clone.clonePrototype = function(parent) { - if (parent === null) - return null; - - var c = function () {}; - c.prototype = parent; - return new c(); -}; - -var CSSLint = (function(){ - - var rules = [], - formatters = [], - embeddedRuleset = /\/\*csslint([^\*]*)\*\//, - api = new parserlib.util.EventTarget(); - - api.version = "@VERSION@"; - api.addRule = function(rule){ - rules.push(rule); - rules[rule.id] = rule; - }; - api.clearRules = function(){ - rules = []; - }; - api.getRules = function(){ - return [].concat(rules).sort(function(a,b){ - return a.id > b.id ? 1 : 0; - }); - }; - api.getRuleset = function() { - var ruleset = {}, - i = 0, - len = rules.length; - - while (i < len){ - ruleset[rules[i++].id] = 1; //by default, everything is a warning - } - - return ruleset; - }; - function applyEmbeddedRuleset(text, ruleset){ - var valueMap, - embedded = text && text.match(embeddedRuleset), - rules = embedded && embedded[1]; - - if (rules) { - valueMap = { - "true": 2, // true is error - "": 1, // blank is warning - "false": 0, // false is ignore - - "2": 2, // explicit error - "1": 1, // explicit warning - "0": 0 // explicit ignore - }; - - rules.toLowerCase().split(",").forEach(function(rule){ - var pair = rule.split(":"), - property = pair[0] || "", - value = pair[1] || ""; - - ruleset[property.trim()] = valueMap[value.trim()]; - }); - } - - return ruleset; - } - api.addFormatter = function(formatter) { - formatters[formatter.id] = formatter; - }; - api.getFormatter = function(formatId){ - return formatters[formatId]; - }; - api.format = function(results, filename, formatId, options) { - var formatter = this.getFormatter(formatId), - result = null; - - if (formatter){ - result = formatter.startFormat(); - result += formatter.formatResults(results, filename, options || {}); - result += formatter.endFormat(); - } - - return result; - }; - api.hasFormat = function(formatId){ - return formatters.hasOwnProperty(formatId); - }; - api.verify = function(text, ruleset){ - - var i = 0, - reporter, - lines, - report, - parser = new parserlib.css.Parser({ starHack: true, ieFilters: true, - underscoreHack: true, strict: false }); - lines = text.replace(/\n\r?/g, "$split$").split("$split$"); - - if (!ruleset){ - ruleset = this.getRuleset(); - } - - if (embeddedRuleset.test(text)){ - ruleset = clone(ruleset); - ruleset = applyEmbeddedRuleset(text, ruleset); - } - - reporter = new Reporter(lines, ruleset); - - ruleset.errors = 2; //always report parsing errors as errors - for (i in ruleset){ - if(ruleset.hasOwnProperty(i) && ruleset[i]){ - if (rules[i]){ - rules[i].init(parser, reporter); - } - } - } - try { - parser.parse(text); - } catch (ex) { - reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {}); - } - - report = { - messages : reporter.messages, - stats : reporter.stats, - ruleset : reporter.ruleset - }; - report.messages.sort(function (a, b){ - if (a.rollup && !b.rollup){ - return 1; - } else if (!a.rollup && b.rollup){ - return -1; - } else { - return a.line - b.line; - } - }); - - return report; - }; - - return api; - -})(); -function Reporter(lines, ruleset){ - this.messages = []; - this.stats = []; - this.lines = lines; - this.ruleset = ruleset; -} - -Reporter.prototype = { - constructor: Reporter, - error: function(message, line, col, rule){ - this.messages.push({ - type : "error", - line : line, - col : col, - message : message, - evidence: this.lines[line-1], - rule : rule || {} - }); - }, - warn: function(message, line, col, rule){ - this.report(message, line, col, rule); - }, - report: function(message, line, col, rule){ - this.messages.push({ - type : this.ruleset[rule.id] === 2 ? "error" : "warning", - line : line, - col : col, - message : message, - evidence: this.lines[line-1], - rule : rule - }); - }, - info: function(message, line, col, rule){ - this.messages.push({ - type : "info", - line : line, - col : col, - message : message, - evidence: this.lines[line-1], - rule : rule - }); - }, - rollupError: function(message, rule){ - this.messages.push({ - type : "error", - rollup : true, - message : message, - rule : rule - }); - }, - rollupWarn: function(message, rule){ - this.messages.push({ - type : "warning", - rollup : true, - message : message, - rule : rule - }); - }, - stat: function(name, value){ - this.stats[name] = value; - } -}; -CSSLint._Reporter = Reporter; -CSSLint.Util = { - mix: function(receiver, supplier){ - var prop; - - for (prop in supplier){ - if (supplier.hasOwnProperty(prop)){ - receiver[prop] = supplier[prop]; - } - } - - return prop; - }, - indexOf: function(values, value){ - if (values.indexOf){ - return values.indexOf(value); - } else { - for (var i=0, len=values.length; i < len; i++){ - if (values[i] === value){ - return i; - } - } - return -1; - } - }, - forEach: function(values, func) { - if (values.forEach){ - return values.forEach(func); - } else { - for (var i=0, len=values.length; i < len; i++){ - func(values[i], i, values); - } - } - } -}; - -CSSLint.addRule({ - id: "adjoining-classes", - name: "Disallow adjoining classes", - desc: "Don't use adjoining classes.", - browsers: "IE6", - init: function(parser, reporter){ - var rule = this; - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - modifier, - classCount, - i, j, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - classCount = 0; - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (modifier.type === "class"){ - classCount++; - } - if (classCount > 1){ - reporter.report("Don't use adjoining classes.", part.line, part.col, rule); - } - } - } - } - } - }); - } - -}); -CSSLint.addRule({ - id: "box-model", - name: "Beware of broken box size", - desc: "Don't use width or height when using padding or border.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - widthProperties = { - border: 1, - "border-left": 1, - "border-right": 1, - padding: 1, - "padding-left": 1, - "padding-right": 1 - }, - heightProperties = { - border: 1, - "border-bottom": 1, - "border-top": 1, - padding: 1, - "padding-bottom": 1, - "padding-top": 1 - }, - properties, - boxSizing = false; - - function startRule(){ - properties = {}; - boxSizing = false; - } - - function endRule(){ - var prop, value; - - if (!boxSizing) { - if (properties.height){ - for (prop in heightProperties){ - if (heightProperties.hasOwnProperty(prop) && properties[prop]){ - value = properties[prop].value; - if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)){ - reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule); - } - } - } - } - - if (properties.width){ - for (prop in widthProperties){ - if (widthProperties.hasOwnProperty(prop) && properties[prop]){ - value = properties[prop].value; - - if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)){ - reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule); - } - } - } - } - } - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(); - - if (heightProperties[name] || widthProperties[name]){ - if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")){ - properties[name] = { line: event.property.line, col: event.property.col, value: event.value }; - } - } else { - if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){ - properties[name] = 1; - } else if (name === "box-sizing") { - boxSizing = true; - } - } - - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - parser.addListener("endpage", endRule); - parser.addListener("endpagemargin", endRule); - parser.addListener("endkeyframerule", endRule); - } - -}); - -CSSLint.addRule({ - id: "box-sizing", - name: "Disallow use of box-sizing", - desc: "The box-sizing properties isn't supported in IE6 and IE7.", - browsers: "IE6, IE7", - tags: ["Compatibility"], - init: function(parser, reporter){ - var rule = this; - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(); - - if (name === "box-sizing"){ - reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "bulletproof-font-face", - name: "Use the bulletproof @font-face syntax", - desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - fontFaceRule = false, - firstSrc = true, - ruleFailed = false, - line, col; - parser.addListener("startfontface", function(){ - fontFaceRule = true; - }); - - parser.addListener("property", function(event){ - if (!fontFaceRule) { - return; - } - - var propertyName = event.property.toString().toLowerCase(), - value = event.value.toString(); - line = event.line; - col = event.col; - if (propertyName === "src") { - var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i; - if (!value.match(regex) && firstSrc) { - ruleFailed = true; - firstSrc = false; - } else if (value.match(regex) && !firstSrc) { - ruleFailed = false; - } - } - - - }); - parser.addListener("endfontface", function(){ - fontFaceRule = false; - - if (ruleFailed) { - reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule); - } - }); - } -}); - -CSSLint.addRule({ - id: "compatible-vendor-prefixes", - name: "Require compatible vendor prefixes", - desc: "Include all compatible vendor prefixes to reach a wider range of users.", - browsers: "All", - init: function (parser, reporter) { - var rule = this, - compatiblePrefixes, - properties, - prop, - variations, - prefixed, - i, - len, - inKeyFrame = false, - arrayPush = Array.prototype.push, - applyTo = []; - compatiblePrefixes = { - "animation" : "webkit moz", - "animation-delay" : "webkit moz", - "animation-direction" : "webkit moz", - "animation-duration" : "webkit moz", - "animation-fill-mode" : "webkit moz", - "animation-iteration-count" : "webkit moz", - "animation-name" : "webkit moz", - "animation-play-state" : "webkit moz", - "animation-timing-function" : "webkit moz", - "appearance" : "webkit moz", - "border-end" : "webkit moz", - "border-end-color" : "webkit moz", - "border-end-style" : "webkit moz", - "border-end-width" : "webkit moz", - "border-image" : "webkit moz o", - "border-radius" : "webkit", - "border-start" : "webkit moz", - "border-start-color" : "webkit moz", - "border-start-style" : "webkit moz", - "border-start-width" : "webkit moz", - "box-align" : "webkit moz ms", - "box-direction" : "webkit moz ms", - "box-flex" : "webkit moz ms", - "box-lines" : "webkit ms", - "box-ordinal-group" : "webkit moz ms", - "box-orient" : "webkit moz ms", - "box-pack" : "webkit moz ms", - "box-sizing" : "webkit moz", - "box-shadow" : "webkit moz", - "column-count" : "webkit moz ms", - "column-gap" : "webkit moz ms", - "column-rule" : "webkit moz ms", - "column-rule-color" : "webkit moz ms", - "column-rule-style" : "webkit moz ms", - "column-rule-width" : "webkit moz ms", - "column-width" : "webkit moz ms", - "hyphens" : "epub moz", - "line-break" : "webkit ms", - "margin-end" : "webkit moz", - "margin-start" : "webkit moz", - "marquee-speed" : "webkit wap", - "marquee-style" : "webkit wap", - "padding-end" : "webkit moz", - "padding-start" : "webkit moz", - "tab-size" : "moz o", - "text-size-adjust" : "webkit ms", - "transform" : "webkit moz ms o", - "transform-origin" : "webkit moz ms o", - "transition" : "webkit moz o", - "transition-delay" : "webkit moz o", - "transition-duration" : "webkit moz o", - "transition-property" : "webkit moz o", - "transition-timing-function" : "webkit moz o", - "user-modify" : "webkit moz", - "user-select" : "webkit moz ms", - "word-break" : "epub ms", - "writing-mode" : "epub ms" - }; - - - for (prop in compatiblePrefixes) { - if (compatiblePrefixes.hasOwnProperty(prop)) { - variations = []; - prefixed = compatiblePrefixes[prop].split(" "); - for (i = 0, len = prefixed.length; i < len; i++) { - variations.push("-" + prefixed[i] + "-" + prop); - } - compatiblePrefixes[prop] = variations; - arrayPush.apply(applyTo, variations); - } - } - - parser.addListener("startrule", function () { - properties = []; - }); - - parser.addListener("startkeyframes", function (event) { - inKeyFrame = event.prefix || true; - }); - - parser.addListener("endkeyframes", function () { - inKeyFrame = false; - }); - - parser.addListener("property", function (event) { - var name = event.property; - if (CSSLint.Util.indexOf(applyTo, name.text) > -1) { - if (!inKeyFrame || typeof inKeyFrame !== "string" || - name.text.indexOf("-" + inKeyFrame + "-") !== 0) { - properties.push(name); - } - } - }); - - parser.addListener("endrule", function () { - if (!properties.length) { - return; - } - - var propertyGroups = {}, - i, - len, - name, - prop, - variations, - value, - full, - actual, - item, - propertiesSpecified; - - for (i = 0, len = properties.length; i < len; i++) { - name = properties[i]; - - for (prop in compatiblePrefixes) { - if (compatiblePrefixes.hasOwnProperty(prop)) { - variations = compatiblePrefixes[prop]; - if (CSSLint.Util.indexOf(variations, name.text) > -1) { - if (!propertyGroups[prop]) { - propertyGroups[prop] = { - full : variations.slice(0), - actual : [], - actualNodes: [] - }; - } - if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) { - propertyGroups[prop].actual.push(name.text); - propertyGroups[prop].actualNodes.push(name); - } - } - } - } - } - - for (prop in propertyGroups) { - if (propertyGroups.hasOwnProperty(prop)) { - value = propertyGroups[prop]; - full = value.full; - actual = value.actual; - - if (full.length > actual.length) { - for (i = 0, len = full.length; i < len; i++) { - item = full[i]; - if (CSSLint.Util.indexOf(actual, item) === -1) { - propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length === 2) ? actual.join(" and ") : actual.join(", "); - reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule); - } - } - - } - } - } - }); - } -}); - -CSSLint.addRule({ - id: "display-property-grouping", - name: "Require properties appropriate for display", - desc: "Certain properties shouldn't be used with certain display property values.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - var propertiesToCheck = { - display: 1, - "float": "none", - height: 1, - width: 1, - margin: 1, - "margin-left": 1, - "margin-right": 1, - "margin-bottom": 1, - "margin-top": 1, - padding: 1, - "padding-left": 1, - "padding-right": 1, - "padding-bottom": 1, - "padding-top": 1, - "vertical-align": 1 - }, - properties; - - function reportProperty(name, display, msg){ - if (properties[name]){ - if (typeof propertiesToCheck[name] !== "string" || properties[name].value.toLowerCase() !== propertiesToCheck[name]){ - reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule); - } - } - } - - function startRule(){ - properties = {}; - } - - function endRule(){ - - var display = properties.display ? properties.display.value : null; - if (display){ - switch(display){ - - case "inline": - reportProperty("height", display); - reportProperty("width", display); - reportProperty("margin", display); - reportProperty("margin-top", display); - reportProperty("margin-bottom", display); - reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug)."); - break; - - case "block": - reportProperty("vertical-align", display); - break; - - case "inline-block": - reportProperty("float", display); - break; - - default: - if (display.indexOf("table-") === 0){ - reportProperty("margin", display); - reportProperty("margin-left", display); - reportProperty("margin-right", display); - reportProperty("margin-top", display); - reportProperty("margin-bottom", display); - reportProperty("float", display); - } - } - } - - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startkeyframerule", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startpage", startRule); - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(); - - if (propertiesToCheck[name]){ - properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col }; - } - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - parser.addListener("endkeyframerule", endRule); - parser.addListener("endpagemargin", endRule); - parser.addListener("endpage", endRule); - - } - -}); - -CSSLint.addRule({ - id: "duplicate-background-images", - name: "Disallow duplicate background images", - desc: "Every background-image should be unique. Use a common class for e.g. sprites.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - stack = {}; - - parser.addListener("property", function(event){ - var name = event.property.text, - value = event.value, - i, len; - - if (name.match(/background/i)) { - for (i=0, len=value.parts.length; i < len; i++) { - if (value.parts[i].type === "uri") { - if (typeof stack[value.parts[i].uri] === "undefined") { - stack[value.parts[i].uri] = event; - } - else { - reporter.report("Background image '" + value.parts[i].uri + "' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule); - } - } - } - } - }); - } -}); - -CSSLint.addRule({ - id: "duplicate-properties", - name: "Disallow duplicate properties", - desc: "Duplicate properties must appear one after the other.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - properties, - lastProperty; - - function startRule(){ - properties = {}; - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var property = event.property, - name = property.text.toLowerCase(); - - if (properties[name] && (lastProperty !== name || properties[name] === event.value.text)){ - reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule); - } - - properties[name] = event.value.text; - lastProperty = name; - - }); - - - } - -}); - -CSSLint.addRule({ - id: "empty-rules", - name: "Disallow empty rules", - desc: "Rules without any properties specified should be removed.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - count = 0; - - parser.addListener("startrule", function(){ - count=0; - }); - - parser.addListener("property", function(){ - count++; - }); - - parser.addListener("endrule", function(event){ - var selectors = event.selectors; - if (count === 0){ - reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "errors", - name: "Parsing Errors", - desc: "This rule looks for recoverable syntax errors.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("error", function(event){ - reporter.error(event.message, event.line, event.col, rule); - }); - - } - -}); - -CSSLint.addRule({ - id: "fallback-colors", - name: "Require fallback colors", - desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.", - browsers: "IE6,IE7,IE8", - init: function(parser, reporter){ - var rule = this, - lastProperty, - propertiesToCheck = { - color: 1, - background: 1, - "border-color": 1, - "border-top-color": 1, - "border-right-color": 1, - "border-bottom-color": 1, - "border-left-color": 1, - border: 1, - "border-top": 1, - "border-right": 1, - "border-bottom": 1, - "border-left": 1, - "background-color": 1 - }, - properties; - - function startRule(){ - properties = {}; - lastProperty = null; - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var property = event.property, - name = property.text.toLowerCase(), - parts = event.value.parts, - i = 0, - colorType = "", - len = parts.length; - - if(propertiesToCheck[name]){ - while(i < len){ - if (parts[i].type === "color"){ - if ("alpha" in parts[i] || "hue" in parts[i]){ - - if (/([^\)]+)\(/.test(parts[i])){ - colorType = RegExp.$1.toUpperCase(); - } - - if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){ - reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule); - } - } else { - event.colorType = "compat"; - } - } - - i++; - } - } - - lastProperty = event; - }); - - } - -}); - -CSSLint.addRule({ - id: "floats", - name: "Disallow too many floats", - desc: "This rule tests if the float property is used too many times", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - var count = 0; - parser.addListener("property", function(event){ - if (event.property.text.toLowerCase() === "float" && - event.value.text.toLowerCase() !== "none"){ - count++; - } - }); - parser.addListener("endstylesheet", function(){ - reporter.stat("floats", count); - if (count >= 10){ - reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "font-faces", - name: "Don't use too many web fonts", - desc: "Too many different web fonts in the same stylesheet.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - count = 0; - - - parser.addListener("startfontface", function(){ - count++; - }); - - parser.addListener("endstylesheet", function(){ - if (count > 5){ - reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "font-sizes", - name: "Disallow too many font sizes", - desc: "Checks the number of font-size declarations.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - count = 0; - parser.addListener("property", function(event){ - if (event.property.toString() === "font-size"){ - count++; - } - }); - parser.addListener("endstylesheet", function(){ - reporter.stat("font-sizes", count); - if (count >= 10){ - reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "gradients", - name: "Require all gradient definitions", - desc: "When using a vendor-prefixed gradient, make sure to use them all.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - gradients; - - parser.addListener("startrule", function(){ - gradients = { - moz: 0, - webkit: 0, - oldWebkit: 0, - o: 0 - }; - }); - - parser.addListener("property", function(event){ - - if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){ - gradients[RegExp.$1] = 1; - } else if (/\-webkit\-gradient/i.test(event.value)){ - gradients.oldWebkit = 1; - } - - }); - - parser.addListener("endrule", function(event){ - var missing = []; - - if (!gradients.moz){ - missing.push("Firefox 3.6+"); - } - - if (!gradients.webkit){ - missing.push("Webkit (Safari 5+, Chrome)"); - } - - if (!gradients.oldWebkit){ - missing.push("Old Webkit (Safari 4+, Chrome)"); - } - - if (!gradients.o){ - missing.push("Opera 11.1+"); - } - - if (missing.length && missing.length < 4){ - reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule); - } - - }); - - } - -}); - -CSSLint.addRule({ - id: "ids", - name: "Disallow IDs in selectors", - desc: "Selectors should not contain IDs.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - modifier, - idCount, - i, j, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - idCount = 0; - - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (modifier.type === "id"){ - idCount++; - } - } - } - } - - if (idCount === 1){ - reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule); - } else if (idCount > 1){ - reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule); - } - } - - }); - } - -}); - -CSSLint.addRule({ - id: "import", - name: "Disallow @import", - desc: "Don't use @import, use <link> instead.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("import", function(event){ - reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule); - }); - - } - -}); - -CSSLint.addRule({ - id: "important", - name: "Disallow !important", - desc: "Be careful when using !important declaration", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - count = 0; - parser.addListener("property", function(event){ - if (event.important === true){ - count++; - reporter.report("Use of !important", event.line, event.col, rule); - } - }); - parser.addListener("endstylesheet", function(){ - reporter.stat("important", count); - if (count >= 10){ - reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "known-properties", - name: "Require use of known properties", - desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("property", function(event){ - if (event.invalid) { - reporter.report(event.invalid.message, event.line, event.col, rule); - } - - }); - } - -}); -CSSLint.addRule({ - id: "order-alphabetical", - name: "Alphabetical order", - desc: "Assure properties are in alphabetical order", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - properties; - - var startRule = function () { - properties = []; - }; - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var name = event.property.text, - lowerCasePrefixLessName = name.toLowerCase().replace(/^-.*?-/, ""); - - properties.push(lowerCasePrefixLessName); - }); - - parser.addListener("endrule", function(event){ - var currentProperties = properties.join(","), - expectedProperties = properties.sort().join(","); - - if (currentProperties !== expectedProperties){ - reporter.report("Rule doesn't have all its properties in alphabetical ordered.", event.line, event.col, rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "outline-none", - name: "Disallow outline: none", - desc: "Use of outline: none or outline: 0 should be limited to :focus rules.", - browsers: "All", - tags: ["Accessibility"], - init: function(parser, reporter){ - var rule = this, - lastRule; - - function startRule(event){ - if (event.selectors){ - lastRule = { - line: event.line, - col: event.col, - selectors: event.selectors, - propCount: 0, - outline: false - }; - } else { - lastRule = null; - } - } - - function endRule(){ - if (lastRule){ - if (lastRule.outline){ - if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") === -1){ - reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule); - } else if (lastRule.propCount === 1) { - reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule); - } - } - } - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(), - value = event.value; - - if (lastRule){ - lastRule.propCount++; - if (name === "outline" && (value.toString() === "none" || value.toString() === "0")){ - lastRule.outline = true; - } - } - - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - parser.addListener("endpage", endRule); - parser.addListener("endpagemargin", endRule); - parser.addListener("endkeyframerule", endRule); - - } - -}); - -CSSLint.addRule({ - id: "overqualified-elements", - name: "Disallow overqualified elements", - desc: "Don't use classes or IDs with elements (a.foo or a#foo).", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - classes = {}; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - modifier, - i, j, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (part.elementName && modifier.type === "id"){ - reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule); - } else if (modifier.type === "class"){ - - if (!classes[modifier]){ - classes[modifier] = []; - } - classes[modifier].push({ modifier: modifier, part: part }); - } - } - } - } - } - }); - - parser.addListener("endstylesheet", function(){ - - var prop; - for (prop in classes){ - if (classes.hasOwnProperty(prop)){ - if (classes[prop].length === 1 && classes[prop][0].part.elementName){ - 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); - } - } - } - }); - } - -}); - -CSSLint.addRule({ - id: "qualified-headings", - name: "Disallow qualified headings", - desc: "Headings should not be qualified (namespaced).", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - i, j; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){ - reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule); - } - } - } - } - }); - } - -}); - -CSSLint.addRule({ - id: "regex-selectors", - name: "Disallow selectors that look like regexs", - desc: "Selectors that look like regular expressions are slow and should be avoided.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - modifier, - i, j, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - for (j=0; j < selector.parts.length; j++){ - part = selector.parts[j]; - if (part.type === parser.SELECTOR_PART_TYPE){ - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (modifier.type === "attribute"){ - if (/([\~\|\^\$\*]=)/.test(modifier)){ - reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule); - } - } - - } - } - } - } - }); - } - -}); - -CSSLint.addRule({ - id: "rules-count", - name: "Rules Count", - desc: "Track how many rules there are.", - browsers: "All", - init: function(parser, reporter){ - var count = 0; - parser.addListener("startrule", function(){ - count++; - }); - - parser.addListener("endstylesheet", function(){ - reporter.stat("rule-count", count); - }); - } - -}); - -CSSLint.addRule({ - id: "selector-max-approaching", - name: "Warn when approaching the 4095 selector limit for IE", - desc: "Will warn when selector count is >= 3800 selectors.", - browsers: "IE", - init: function(parser, reporter) { - var rule = this, count = 0; - - parser.addListener("startrule", function(event) { - count += event.selectors.length; - }); - - parser.addListener("endstylesheet", function() { - if (count >= 3800) { - reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "selector-max", - name: "Error when past the 4095 selector limit for IE", - desc: "Will error when selector count is > 4095.", - browsers: "IE", - init: function(parser, reporter){ - var rule = this, count = 0; - - parser.addListener("startrule", function(event) { - count += event.selectors.length; - }); - - parser.addListener("endstylesheet", function() { - if (count > 4095) { - reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "selector-newline", - name: "Disallow new-line characters in selectors", - desc: "New-line characters in selectors are usually a forgotten comma and not a descendant combinator.", - browsers: "All", - init: function(parser, reporter) { - var rule = this; - - function startRule(event) { - var i, len, selector, p, n, pLen, part, part2, type, currentLine, nextLine, - selectors = event.selectors; - - for (i = 0, len = selectors.length; i < len; i++) { - selector = selectors[i]; - for (p = 0, pLen = selector.parts.length; p < pLen; p++) { - for (n = p + 1; n < pLen; n++) { - part = selector.parts[p]; - part2 = selector.parts[n]; - type = part.type; - currentLine = part.line; - nextLine = part2.line; - - if (type === "descendant" && nextLine > currentLine) { - reporter.report("newline character found in selector (forgot a comma?)", currentLine, selectors[i].parts[0].col, rule); - } - } - } - - } - } - - parser.addListener("startrule", startRule); - - } -}); - -CSSLint.addRule({ - id: "shorthand", - name: "Require shorthand properties", - desc: "Use shorthand properties where possible.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - prop, i, len, - propertiesToCheck = {}, - properties, - mapping = { - "margin": [ - "margin-top", - "margin-bottom", - "margin-left", - "margin-right" - ], - "padding": [ - "padding-top", - "padding-bottom", - "padding-left", - "padding-right" - ] - }; - for (prop in mapping){ - if (mapping.hasOwnProperty(prop)){ - for (i=0, len=mapping[prop].length; i < len; i++){ - propertiesToCheck[mapping[prop][i]] = prop; - } - } - } - - function startRule(){ - properties = {}; - } - function endRule(event){ - - var prop, i, len, total; - for (prop in mapping){ - if (mapping.hasOwnProperty(prop)){ - total=0; - - for (i=0, len=mapping[prop].length; i < len; i++){ - total += properties[mapping[prop][i]] ? 1 : 0; - } - - if (total === mapping[prop].length){ - reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule); - } - } - } - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("property", function(event){ - var name = event.property.toString().toLowerCase(); - - if (propertiesToCheck[name]){ - properties[name] = 1; - } - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - - } - -}); - -CSSLint.addRule({ - id: "star-property-hack", - name: "Disallow properties with a star prefix", - desc: "Checks for the star property hack (targets IE6/7)", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - parser.addListener("property", function(event){ - var property = event.property; - - if (property.hack === "*") { - reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule); - } - }); - } -}); - -CSSLint.addRule({ - id: "text-indent", - name: "Disallow negative text-indent", - desc: "Checks for text indent less than -99px", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - textIndent, - direction; - - - function startRule(){ - textIndent = false; - direction = "inherit"; - } - function endRule(){ - if (textIndent && direction !== "ltr"){ - reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule); - } - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("property", function(event){ - var name = event.property.toString().toLowerCase(), - value = event.value; - - if (name === "text-indent" && value.parts[0].value < -99){ - textIndent = event.property; - } else if (name === "direction" && value.toString() === "ltr"){ - direction = "ltr"; - } - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - - } - -}); - -CSSLint.addRule({ - id: "underscore-property-hack", - name: "Disallow properties with an underscore prefix", - desc: "Checks for the underscore property hack (targets IE6)", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - parser.addListener("property", function(event){ - var property = event.property; - - if (property.hack === "_") { - reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule); - } - }); - } -}); - -CSSLint.addRule({ - id: "unique-headings", - name: "Headings should only be defined once", - desc: "Headings should be defined only once.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - var headings = { - h1: 0, - h2: 0, - h3: 0, - h4: 0, - h5: 0, - h6: 0 - }; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - pseudo, - i, j; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - part = selector.parts[selector.parts.length-1]; - - if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){ - - for (j=0; j < part.modifiers.length; j++){ - if (part.modifiers[j].type === "pseudo"){ - pseudo = true; - break; - } - } - - if (!pseudo){ - headings[RegExp.$1]++; - if (headings[RegExp.$1] > 1) { - reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule); - } - } - } - } - }); - - parser.addListener("endstylesheet", function(){ - var prop, - messages = []; - - for (prop in headings){ - if (headings.hasOwnProperty(prop)){ - if (headings[prop] > 1){ - messages.push(headings[prop] + " " + prop + "s"); - } - } - } - - if (messages.length){ - reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule); - } - }); - } - -}); - -CSSLint.addRule({ - id: "universal-selector", - name: "Disallow universal selector", - desc: "The universal selector (*) is known to be slow.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("startrule", function(event){ - var selectors = event.selectors, - selector, - part, - i; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - - part = selector.parts[selector.parts.length-1]; - if (part.elementName === "*"){ - reporter.report(rule.desc, part.line, part.col, rule); - } - } - }); - } - -}); - -CSSLint.addRule({ - id: "unqualified-attributes", - name: "Disallow unqualified attribute selectors", - desc: "Unqualified attribute selectors are known to be slow.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - - parser.addListener("startrule", function(event){ - - var selectors = event.selectors, - selector, - part, - modifier, - i, k; - - for (i=0; i < selectors.length; i++){ - selector = selectors[i]; - - part = selector.parts[selector.parts.length-1]; - if (part.type === parser.SELECTOR_PART_TYPE){ - for (k=0; k < part.modifiers.length; k++){ - modifier = part.modifiers[k]; - if (modifier.type === "attribute" && (!part.elementName || part.elementName === "*")){ - reporter.report(rule.desc, part.line, part.col, rule); - } - } - } - - } - }); - } - -}); - -CSSLint.addRule({ - id: "vendor-prefix", - name: "Require standard property with vendor prefix", - desc: "When using a vendor-prefixed property, make sure to include the standard one.", - browsers: "All", - init: function(parser, reporter){ - var rule = this, - properties, - num, - propertiesToCheck = { - "-webkit-border-radius": "border-radius", - "-webkit-border-top-left-radius": "border-top-left-radius", - "-webkit-border-top-right-radius": "border-top-right-radius", - "-webkit-border-bottom-left-radius": "border-bottom-left-radius", - "-webkit-border-bottom-right-radius": "border-bottom-right-radius", - - "-o-border-radius": "border-radius", - "-o-border-top-left-radius": "border-top-left-radius", - "-o-border-top-right-radius": "border-top-right-radius", - "-o-border-bottom-left-radius": "border-bottom-left-radius", - "-o-border-bottom-right-radius": "border-bottom-right-radius", - - "-moz-border-radius": "border-radius", - "-moz-border-radius-topleft": "border-top-left-radius", - "-moz-border-radius-topright": "border-top-right-radius", - "-moz-border-radius-bottomleft": "border-bottom-left-radius", - "-moz-border-radius-bottomright": "border-bottom-right-radius", - - "-moz-column-count": "column-count", - "-webkit-column-count": "column-count", - - "-moz-column-gap": "column-gap", - "-webkit-column-gap": "column-gap", - - "-moz-column-rule": "column-rule", - "-webkit-column-rule": "column-rule", - - "-moz-column-rule-style": "column-rule-style", - "-webkit-column-rule-style": "column-rule-style", - - "-moz-column-rule-color": "column-rule-color", - "-webkit-column-rule-color": "column-rule-color", - - "-moz-column-rule-width": "column-rule-width", - "-webkit-column-rule-width": "column-rule-width", - - "-moz-column-width": "column-width", - "-webkit-column-width": "column-width", - - "-webkit-column-span": "column-span", - "-webkit-columns": "columns", - - "-moz-box-shadow": "box-shadow", - "-webkit-box-shadow": "box-shadow", - - "-moz-transform" : "transform", - "-webkit-transform" : "transform", - "-o-transform" : "transform", - "-ms-transform" : "transform", - - "-moz-transform-origin" : "transform-origin", - "-webkit-transform-origin" : "transform-origin", - "-o-transform-origin" : "transform-origin", - "-ms-transform-origin" : "transform-origin", - - "-moz-box-sizing" : "box-sizing", - "-webkit-box-sizing" : "box-sizing" - }; - function startRule(){ - properties = {}; - num = 1; - } - function endRule(){ - var prop, - i, - len, - needed, - actual, - needsStandard = []; - - for (prop in properties){ - if (propertiesToCheck[prop]){ - needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]}); - } - } - - for (i=0, len=needsStandard.length; i < len; i++){ - needed = needsStandard[i].needed; - actual = needsStandard[i].actual; - - if (!properties[needed]){ - reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule); - } else { - if (properties[needed][0].pos < properties[actual][0].pos){ - reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule); - } - } - } - - } - - parser.addListener("startrule", startRule); - parser.addListener("startfontface", startRule); - parser.addListener("startpage", startRule); - parser.addListener("startpagemargin", startRule); - parser.addListener("startkeyframerule", startRule); - - parser.addListener("property", function(event){ - var name = event.property.text.toLowerCase(); - - if (!properties[name]){ - properties[name] = []; - } - - properties[name].push({ name: event.property, value : event.value, pos:num++ }); - }); - - parser.addListener("endrule", endRule); - parser.addListener("endfontface", endRule); - parser.addListener("endpage", endRule); - parser.addListener("endpagemargin", endRule); - parser.addListener("endkeyframerule", endRule); - } - -}); - -CSSLint.addRule({ - id: "zero-units", - name: "Disallow units for 0 values", - desc: "You don't need to specify units when a value is 0.", - browsers: "All", - init: function(parser, reporter){ - var rule = this; - parser.addListener("property", function(event){ - var parts = event.value.parts, - i = 0, - len = parts.length; - - while(i < len){ - if ((parts[i].units || parts[i].type === "percentage") && parts[i].value === 0 && parts[i].type !== "time"){ - reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule); - } - i++; - } - - }); - - } - -}); - -(function() { - var xmlEscape = function(str) { - if (!str || str.constructor !== String) { - return ""; - } - - return str.replace(/[\"&><]/g, function(match) { - switch (match) { - case "\"": - return "&quot;"; - case "&": - return "&amp;"; - case "<": - return "&lt;"; - case ">": - return "&gt;"; - } - }); - }; - - CSSLint.addFormatter({ - id: "checkstyle-xml", - name: "Checkstyle XML format", - startFormat: function(){ - return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>"; - }, - endFormat: function(){ - return "</checkstyle>"; - }, - readError: function(filename, message) { - return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>"; - }, - formatResults: function(results, filename/*, options*/) { - var messages = results.messages, - output = []; - var generateSource = function(rule) { - if (!rule || !("name" in rule)) { - return ""; - } - return "net.csslint." + rule.name.replace(/\s/g,""); - }; - - - - if (messages.length > 0) { - output.push("<file name=\""+filename+"\">"); - CSSLint.Util.forEach(messages, function (message) { - if (!message.rollup) { - output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" + - " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>"); - } - }); - output.push("</file>"); - } - - return output.join(""); - } - }); - -}()); - -CSSLint.addFormatter({ - id: "compact", - name: "Compact, 'porcelain' format", - startFormat: function() { - return ""; - }, - endFormat: function() { - return ""; - }, - formatResults: function(results, filename, options) { - var messages = results.messages, - output = ""; - options = options || {}; - var capitalize = function(str) { - return str.charAt(0).toUpperCase() + str.slice(1); - }; - - if (messages.length === 0) { - return options.quiet ? "" : filename + ": Lint Free!"; - } - - CSSLint.Util.forEach(messages, function(message) { - if (message.rollup) { - output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n"; - } else { - output += filename + ": " + "line " + message.line + - ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n"; - } - }); - - return output; - } -}); - -CSSLint.addFormatter({ - id: "csslint-xml", - name: "CSSLint XML format", - startFormat: function(){ - return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>"; - }, - endFormat: function(){ - return "</csslint>"; - }, - formatResults: function(results, filename/*, options*/) { - var messages = results.messages, - output = []; - var escapeSpecialCharacters = function(str) { - if (!str || str.constructor !== String) { - return ""; - } - return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); - }; - - if (messages.length > 0) { - output.push("<file name=\""+filename+"\">"); - CSSLint.Util.forEach(messages, function (message) { - if (message.rollup) { - output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); - } else { - output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" + - " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); - } - }); - output.push("</file>"); - } - - return output.join(""); - } -}); - -CSSLint.addFormatter({ - id: "junit-xml", - name: "JUNIT XML format", - startFormat: function(){ - return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>"; - }, - endFormat: function() { - return "</testsuites>"; - }, - formatResults: function(results, filename/*, options*/) { - - var messages = results.messages, - output = [], - tests = { - "error": 0, - "failure": 0 - }; - var generateSource = function(rule) { - if (!rule || !("name" in rule)) { - return ""; - } - return "net.csslint." + rule.name.replace(/\s/g,""); - }; - var escapeSpecialCharacters = function(str) { - - if (!str || str.constructor !== String) { - return ""; - } - - return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;"); - - }; - - if (messages.length > 0) { - - messages.forEach(function (message) { - var type = message.type === "warning" ? "error" : message.type; - if (!message.rollup) { - output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">"); - output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ":" + message.col + ":" + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">"); - output.push("</testcase>"); - - tests[type] += 1; - - } - - }); - - output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">"); - output.push("</testsuite>"); - - } - - return output.join(""); - - } -}); - -CSSLint.addFormatter({ - id: "lint-xml", - name: "Lint XML format", - startFormat: function(){ - return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>"; - }, - endFormat: function(){ - return "</lint>"; - }, - formatResults: function(results, filename/*, options*/) { - var messages = results.messages, - output = []; - var escapeSpecialCharacters = function(str) { - if (!str || str.constructor !== String) { - return ""; - } - return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); - }; - - if (messages.length > 0) { - - output.push("<file name=\""+filename+"\">"); - CSSLint.Util.forEach(messages, function (message) { - if (message.rollup) { - output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); - } else { - output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" + - " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); - } - }); - output.push("</file>"); - } - - return output.join(""); - } -}); - -CSSLint.addFormatter({ - id: "text", - name: "Plain Text", - startFormat: function() { - return ""; - }, - endFormat: function() { - return ""; - }, - formatResults: function(results, filename, options) { - var messages = results.messages, - output = ""; - options = options || {}; - - if (messages.length === 0) { - return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + "."; - } - - output = "\n\ncsslint: There "; - if (messages.length === 1) { - output += "is 1 problem"; - } else { - output += "are " + messages.length + " problems"; - } - output += " in " + filename + "."; - - var pos = filename.lastIndexOf("/"), - shortFilename = filename; - - if (pos === -1){ - pos = filename.lastIndexOf("\\"); - } - if (pos > -1){ - shortFilename = filename.substring(pos+1); - } - - CSSLint.Util.forEach(messages, function (message, i) { - output = output + "\n\n" + shortFilename; - if (message.rollup) { - output += "\n" + (i+1) + ": " + message.type; - output += "\n" + message.message; - } else { - output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col; - output += "\n" + message.message; - output += "\n" + message.evidence; - } - }); - - return output; - } -}); - -module.exports.CSSLint = CSSLint; - -}); - -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) { -"use strict"; - -var oop = require("../lib/oop"); -var lang = require("../lib/lang"); -var Mirror = require("../worker/mirror").Mirror; -var CSSLint = require("./css/csslint").CSSLint; - -var Worker = exports.Worker = function(sender) { - Mirror.call(this, sender); - this.setTimeout(400); - this.ruleset = null; - this.setDisabledRules("ids|order-alphabetical"); - this.setInfoRules( - "adjoining-classes|qualified-headings|zero-units|gradients|" + - "import|outline-none|vendor-prefix" - ); -}; - -oop.inherits(Worker, Mirror); - -(function() { - this.setInfoRules = function(ruleNames) { - if (typeof ruleNames == "string") - ruleNames = ruleNames.split("|"); - this.infoRules = lang.arrayToMap(ruleNames); - this.doc.getValue() && this.deferredUpdate.schedule(100); - }; - - this.setDisabledRules = function(ruleNames) { - if (!ruleNames) { - this.ruleset = null; - } else { - if (typeof ruleNames == "string") - ruleNames = ruleNames.split("|"); - var all = {}; - - CSSLint.getRules().forEach(function(x){ - all[x.id] = true; - }); - ruleNames.forEach(function(x) { - delete all[x]; - }); - - this.ruleset = all; - } - this.doc.getValue() && this.deferredUpdate.schedule(100); - }; - - this.onUpdate = function() { - var value = this.doc.getValue(); - if (!value) - return this.sender.emit("annotate", []); - var infoRules = this.infoRules; - - var result = CSSLint.verify(value, this.ruleset); - this.sender.emit("annotate", result.messages.map(function(msg) { - return { - row: msg.line - 1, - column: msg.col - 1, - text: msg.message, - type: infoRules[msg.rule.id] ? "info" : msg.type, - rule: msg.rule.name - } - })); - }; - -}).call(Worker.prototype); - -}); - -ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { - -function Empty() {} - -if (!Function.prototype.bind) { - Function.prototype.bind = function bind(that) { // .length is 1 - var target = this; - if (typeof target != "function") { - throw new TypeError("Function.prototype.bind called on incompatible " + target); - } - var args = slice.call(arguments, 1); // for normal call - var bound = function () { - - if (this instanceof bound) { - - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - - } - - }; - if(target.prototype) { - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; - } - return bound; - }; -} -var call = Function.prototype.call; -var prototypeOfArray = Array.prototype; -var prototypeOfObject = Object.prototype; -var slice = prototypeOfArray.slice; -var _toString = call.bind(prototypeOfObject.toString); -var owns = call.bind(prototypeOfObject.hasOwnProperty); -var defineGetter; -var defineSetter; -var lookupGetter; -var lookupSetter; -var supportsAccessors; -if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { - defineGetter = call.bind(prototypeOfObject.__defineGetter__); - defineSetter = call.bind(prototypeOfObject.__defineSetter__); - lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); - lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); -} -if ([1,2].splice(0).length != 2) { - if(function() { // test IE < 9 to splice bug - see issue #138 - function makeArray(l) { - var a = new Array(l+2); - a[0] = a[1] = 0; - return a; - } - var array = [], lengthBefore; - - array.splice.apply(array, makeArray(20)); - array.splice.apply(array, makeArray(26)); - - lengthBefore = array.length; //46 - array.splice(5, 0, "XXX"); // add one element - - lengthBefore + 1 == array.length - - if (lengthBefore + 1 == array.length) { - return true;// has right splice implementation without bugs - } - }()) {//IE 6/7 - var array_splice = Array.prototype.splice; - Array.prototype.splice = function(start, deleteCount) { - if (!arguments.length) { - return []; - } else { - return array_splice.apply(this, [ - start === void 0 ? 0 : start, - deleteCount === void 0 ? (this.length - start) : deleteCount - ].concat(slice.call(arguments, 2))) - } - }; - } else {//IE8 - Array.prototype.splice = function(pos, removeCount){ - var length = this.length; - if (pos > 0) { - if (pos > length) - pos = length; - } else if (pos == void 0) { - pos = 0; - } else if (pos < 0) { - pos = Math.max(length + pos, 0); - } - - if (!(pos+removeCount < length)) - removeCount = length - pos; - - var removed = this.slice(pos, pos+removeCount); - var insert = slice.call(arguments, 2); - var add = insert.length; - if (pos === length) { - if (add) { - this.push.apply(this, insert); - } - } else { - var remove = Math.min(removeCount, length - pos); - var tailOldPos = pos + remove; - var tailNewPos = tailOldPos + add - remove; - var tailCount = length - tailOldPos; - var lengthAfterRemove = length - remove; - - if (tailNewPos < tailOldPos) { // case A - for (var i = 0; i < tailCount; ++i) { - this[tailNewPos+i] = this[tailOldPos+i]; - } - } else if (tailNewPos > tailOldPos) { // case B - for (i = tailCount; i--; ) { - this[tailNewPos+i] = this[tailOldPos+i]; - } - } // else, add == remove (nothing to do) - - if (add && pos === lengthAfterRemove) { - this.length = lengthAfterRemove; // truncate array - this.push.apply(this, insert); - } else { - this.length = lengthAfterRemove + add; // reserves space - for (i = 0; i < add; ++i) { - this[pos+i] = insert[i]; - } - } - } - return removed; - }; - } -} -if (!Array.isArray) { - Array.isArray = function isArray(obj) { - return _toString(obj) == "[object Array]"; - }; -} -var boxedString = Object("a"), - splitString = boxedString[0] != "a" || !(0 in boxedString); - -if (!Array.prototype.forEach) { - Array.prototype.forEach = function forEach(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - thisp = arguments[1], - i = -1, - length = self.length >>> 0; - if (_toString(fun) != "[object Function]") { - throw new TypeError(); // TODO message - } - - while (++i < length) { - if (i in self) { - fun.call(thisp, self[i], i, object); - } - } - }; -} -if (!Array.prototype.map) { - Array.prototype.map = function map(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - result = Array(length), - thisp = arguments[1]; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self) - result[i] = fun.call(thisp, self[i], i, object); - } - return result; - }; -} -if (!Array.prototype.filter) { - Array.prototype.filter = function filter(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - result = [], - value, - thisp = arguments[1]; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self) { - value = self[i]; - if (fun.call(thisp, value, i, object)) { - result.push(value); - } - } - } - return result; - }; -} -if (!Array.prototype.every) { - Array.prototype.every = function every(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - thisp = arguments[1]; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self && !fun.call(thisp, self[i], i, object)) { - return false; - } - } - return true; - }; -} -if (!Array.prototype.some) { - Array.prototype.some = function some(fun /*, thisp */) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0, - thisp = arguments[1]; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - - for (var i = 0; i < length; i++) { - if (i in self && fun.call(thisp, self[i], i, object)) { - return true; - } - } - return false; - }; -} -if (!Array.prototype.reduce) { - Array.prototype.reduce = function reduce(fun /*, initial*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - if (!length && arguments.length == 1) { - throw new TypeError("reduce of empty array with no initial value"); - } - - var i = 0; - var result; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i++]; - break; - } - if (++i >= length) { - throw new TypeError("reduce of empty array with no initial value"); - } - } while (true); - } - - for (; i < length; i++) { - if (i in self) { - result = fun.call(void 0, result, self[i], i, object); - } - } - - return result; - }; -} -if (!Array.prototype.reduceRight) { - Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { - var object = toObject(this), - self = splitString && _toString(this) == "[object String]" ? - this.split("") : - object, - length = self.length >>> 0; - if (_toString(fun) != "[object Function]") { - throw new TypeError(fun + " is not a function"); - } - if (!length && arguments.length == 1) { - throw new TypeError("reduceRight of empty array with no initial value"); - } - - var result, i = length - 1; - if (arguments.length >= 2) { - result = arguments[1]; - } else { - do { - if (i in self) { - result = self[i--]; - break; - } - if (--i < 0) { - throw new TypeError("reduceRight of empty array with no initial value"); - } - } while (true); - } - - do { - if (i in this) { - result = fun.call(void 0, result, self[i], i, object); - } - } while (i--); - - return result; - }; -} -if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { - Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { - var self = splitString && _toString(this) == "[object String]" ? - this.split("") : - toObject(this), - length = self.length >>> 0; - - if (!length) { - return -1; - } - - var i = 0; - if (arguments.length > 1) { - i = toInteger(arguments[1]); - } - i = i >= 0 ? i : Math.max(0, length + i); - for (; i < length; i++) { - if (i in self && self[i] === sought) { - return i; - } - } - return -1; - }; -} -if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { - Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { - var self = splitString && _toString(this) == "[object String]" ? - this.split("") : - toObject(this), - length = self.length >>> 0; - - if (!length) { - return -1; - } - var i = length - 1; - if (arguments.length > 1) { - i = Math.min(i, toInteger(arguments[1])); - } - i = i >= 0 ? i : length - Math.abs(i); - for (; i >= 0; i--) { - if (i in self && sought === self[i]) { - return i; - } - } - return -1; - }; -} -if (!Object.getPrototypeOf) { - Object.getPrototypeOf = function getPrototypeOf(object) { - return object.__proto__ || ( - object.constructor ? - object.constructor.prototype : - prototypeOfObject - ); - }; -} -if (!Object.getOwnPropertyDescriptor) { - var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + - "non-object: "; - Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { - if ((typeof object != "object" && typeof object != "function") || object === null) - throw new TypeError(ERR_NON_OBJECT + object); - if (!owns(object, property)) - return; - - var descriptor, getter, setter; - descriptor = { enumerable: true, configurable: true }; - if (supportsAccessors) { - var prototype = object.__proto__; - object.__proto__ = prototypeOfObject; - - var getter = lookupGetter(object, property); - var setter = lookupSetter(object, property); - object.__proto__ = prototype; - - if (getter || setter) { - if (getter) descriptor.get = getter; - if (setter) descriptor.set = setter; - return descriptor; - } - } - descriptor.value = object[property]; - return descriptor; - }; -} -if (!Object.getOwnPropertyNames) { - Object.getOwnPropertyNames = function getOwnPropertyNames(object) { - return Object.keys(object); - }; -} -if (!Object.create) { - var createEmpty; - if (Object.prototype.__proto__ === null) { - createEmpty = function () { - return { "__proto__": null }; - }; - } else { - createEmpty = function () { - var empty = {}; - for (var i in empty) - empty[i] = null; - empty.constructor = - empty.hasOwnProperty = - empty.propertyIsEnumerable = - empty.isPrototypeOf = - empty.toLocaleString = - empty.toString = - empty.valueOf = - empty.__proto__ = null; - return empty; - } - } - - Object.create = function create(prototype, properties) { - var object; - if (prototype === null) { - object = createEmpty(); - } else { - if (typeof prototype != "object") - throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); - var Type = function () {}; - Type.prototype = prototype; - object = new Type(); - object.__proto__ = prototype; - } - if (properties !== void 0) - Object.defineProperties(object, properties); - return object; - }; -} - -function doesDefinePropertyWork(object) { - try { - Object.defineProperty(object, "sentinel", {}); - return "sentinel" in object; - } catch (exception) { - } -} -if (Object.defineProperty) { - var definePropertyWorksOnObject = doesDefinePropertyWork({}); - var definePropertyWorksOnDom = typeof document == "undefined" || - doesDefinePropertyWork(document.createElement("div")); - if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { - var definePropertyFallback = Object.defineProperty; - } -} - -if (!Object.defineProperty || definePropertyFallback) { - var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; - var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " - var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + - "on this javascript engine"; - - Object.defineProperty = function defineProperty(object, property, descriptor) { - if ((typeof object != "object" && typeof object != "function") || object === null) - throw new TypeError(ERR_NON_OBJECT_TARGET + object); - if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) - throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); - if (definePropertyFallback) { - try { - return definePropertyFallback.call(Object, object, property, descriptor); - } catch (exception) { - } - } - if (owns(descriptor, "value")) { - - if (supportsAccessors && (lookupGetter(object, property) || - lookupSetter(object, property))) - { - var prototype = object.__proto__; - object.__proto__ = prototypeOfObject; - delete object[property]; - object[property] = descriptor.value; - object.__proto__ = prototype; - } else { - object[property] = descriptor.value; - } - } else { - if (!supportsAccessors) - throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); - if (owns(descriptor, "get")) - defineGetter(object, property, descriptor.get); - if (owns(descriptor, "set")) - defineSetter(object, property, descriptor.set); - } - - return object; - }; -} -if (!Object.defineProperties) { - Object.defineProperties = function defineProperties(object, properties) { - for (var property in properties) { - if (owns(properties, property)) - Object.defineProperty(object, property, properties[property]); - } - return object; - }; -} -if (!Object.seal) { - Object.seal = function seal(object) { - return object; - }; -} -if (!Object.freeze) { - Object.freeze = function freeze(object) { - return object; - }; -} -try { - Object.freeze(function () {}); -} catch (exception) { - Object.freeze = (function freeze(freezeObject) { - return function freeze(object) { - if (typeof object == "function") { - return object; - } else { - return freezeObject(object); - } - }; - })(Object.freeze); -} -if (!Object.preventExtensions) { - Object.preventExtensions = function preventExtensions(object) { - return object; - }; -} -if (!Object.isSealed) { - Object.isSealed = function isSealed(object) { - return false; - }; -} -if (!Object.isFrozen) { - Object.isFrozen = function isFrozen(object) { - return false; - }; -} -if (!Object.isExtensible) { - Object.isExtensible = function isExtensible(object) { - if (Object(object) === object) { - throw new TypeError(); // TODO message - } - var name = ''; - while (owns(object, name)) { - name += '?'; - } - object[name] = true; - var returnValue = owns(object, name); - delete object[name]; - return returnValue; - }; -} -if (!Object.keys) { - var hasDontEnumBug = true, - dontEnums = [ - "toString", - "toLocaleString", - "valueOf", - "hasOwnProperty", - "isPrototypeOf", - "propertyIsEnumerable", - "constructor" - ], - dontEnumsLength = dontEnums.length; - - for (var key in {"toString": null}) { - hasDontEnumBug = false; - } - - Object.keys = function keys(object) { - - if ( - (typeof object != "object" && typeof object != "function") || - object === null - ) { - throw new TypeError("Object.keys called on a non-object"); - } - - var keys = []; - for (var name in object) { - if (owns(object, name)) { - keys.push(name); - } - } - - if (hasDontEnumBug) { - for (var i = 0, ii = dontEnumsLength; i < ii; i++) { - var dontEnum = dontEnums[i]; - if (owns(object, dontEnum)) { - keys.push(dontEnum); - } - } - } - return keys; - }; - -} -if (!Date.now) { - Date.now = function now() { - return new Date().getTime(); - }; -} -var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + - "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + - "\u2029\uFEFF"; -if (!String.prototype.trim || ws.trim()) { - ws = "[" + ws + "]"; - var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), - trimEndRegexp = new RegExp(ws + ws + "*$"); - String.prototype.trim = function trim() { - return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); - }; -} - -function toInteger(n) { - n = +n; - if (n !== n) { // isNaN - n = 0; - } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - return n; -} - -function isPrimitive(input) { - var type = typeof input; - return ( - input === null || - type === "undefined" || - type === "boolean" || - type === "number" || - type === "string" - ); -} - -function toPrimitive(input) { - var val, valueOf, toString; - if (isPrimitive(input)) { - return input; - } - valueOf = input.valueOf; - if (typeof valueOf === "function") { - val = valueOf.call(input); - if (isPrimitive(val)) { - return val; - } - } - toString = input.toString; - if (typeof toString === "function") { - val = toString.call(input); - if (isPrimitive(val)) { - return val; - } - } - throw new TypeError(); -} -var toObject = function (o) { - if (o == null) { // this matches both null and undefined - throw new TypeError("can't convert "+o+" to object"); - } - return Object(o); -}; - -}); +"no use strict"; +;(function(window) { +if (typeof window.window != "undefined" && window.document) { + return; +} + +window.console = function() { + var msgs = Array.prototype.slice.call(arguments, 0); + postMessage({type: "log", data: msgs}); +}; +window.console.error = +window.console.warn = +window.console.log = +window.console.trace = window.console; + +window.window = window; +window.ace = window; + +window.onerror = function(message, file, line, col, err) { + postMessage({type: "error", data: { + message: message, + file: file, + line: line, + col: col, + stack: err.stack + }}); +}; + +window.normalizeModule = function(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = (base ? base + "/" : "") + moduleName; + + while(moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + + return moduleName; +}; + +window.require = function(parentId, id) { + if (!id) { + id = parentId; + parentId = null; + } + if (!id.charAt) + throw new Error("worker.js require() accepts only (parentId, id) as arguments"); + + id = window.normalizeModule(parentId, id); + + var module = window.require.modules[id]; + if (module) { + if (!module.initialized) { + module.initialized = true; + module.exports = module.factory().exports; + } + return module.exports; + } + + var chunks = id.split("/"); + if (!window.require.tlns) + return console.log("unable to load " + id); + chunks[0] = window.require.tlns[chunks[0]] || chunks[0]; + var path = chunks.join("/") + ".js"; + + window.require.id = id; + importScripts(path); + return window.require(parentId, id); +}; +window.require.modules = {}; +window.require.tlns = {}; + +window.define = function(id, deps, factory) { + if (arguments.length == 2) { + factory = deps; + if (typeof id != "string") { + deps = id; + id = window.require.id; + } + } else if (arguments.length == 1) { + factory = id; + deps = []; + id = window.require.id; + } + + if (typeof factory != "function") { + window.require.modules[id] = { + exports: factory, + initialized: true + }; + return; + } + + if (!deps.length) + // If there is no dependencies, we inject 'require', 'exports' and + // 'module' as dependencies, to provide CommonJS compatibility. + deps = ['require', 'exports', 'module']; + + var req = function(childId) { + return window.require(id, childId); + }; + + window.require.modules[id] = { + exports: {}, + factory: function() { + var module = this; + var returnExports = factory.apply(this, deps.map(function(dep) { + switch(dep) { + // Because 'require', 'exports' and 'module' aren't actual + // dependencies, we must handle them seperately. + case 'require': return req; + case 'exports': return module.exports; + case 'module': return module; + // But for all other dependencies, we can just go ahead and + // require them. + default: return req(dep); + } + })); + if (returnExports) + module.exports = returnExports; + return module; + } + }; +}; +window.define.amd = {}; + +window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { + require.tlns = topLevelNamespaces; +}; + +window.initSender = function initSender() { + + var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter; + var oop = window.require("ace/lib/oop"); + + var Sender = function() {}; + + (function() { + + oop.implement(this, EventEmitter); + + this.callback = function(data, callbackId) { + postMessage({ + type: "call", + id: callbackId, + data: data + }); + }; + + this.emit = function(name, data) { + postMessage({ + type: "event", + name: name, + data: data + }); + }; + + }).call(Sender.prototype); + + return new Sender(); +}; + +var main = window.main = null; +var sender = window.sender = null; + +window.onmessage = function(e) { + var msg = e.data; + if (msg.command) { + if (main[msg.command]) + main[msg.command].apply(main, msg.args); + else + throw new Error("Unknown command:" + msg.command); + } + else if (msg.init) { + initBaseUrls(msg.tlns); + require("ace/lib/es5-shim"); + sender = window.sender = initSender(); + var clazz = require(msg.module)[msg.classname]; + main = window.main = new clazz(sender); + } + else if (msg.event && sender) { + sender._signal(msg.event, msg.data); + } +}; +})(this); + +ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.inherits = function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +}; + +exports.mixin = function(obj, mixin) { + for (var key in mixin) { + obj[key] = mixin[key]; + } + return obj; +}; + +exports.implement = function(proto, mixin) { + exports.mixin(proto, mixin); +}; + +}); + +ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { +"use strict"; + +exports.last = function(a) { + return a[a.length - 1]; +}; + +exports.stringReverse = function(string) { + return string.split("").reverse().join(""); +}; + +exports.stringRepeat = function (string, count) { + var result = ''; + while (count > 0) { + if (count & 1) + result += string; + + if (count >>= 1) + string += string; + } + return result; +}; + +var trimBeginRegexp = /^\s\s*/; +var trimEndRegexp = /\s\s*$/; + +exports.stringTrimLeft = function (string) { + return string.replace(trimBeginRegexp, ''); +}; + +exports.stringTrimRight = function (string) { + return string.replace(trimEndRegexp, ''); +}; + +exports.copyObject = function(obj) { + var copy = {}; + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +}; + +exports.copyArray = function(array){ + var copy = []; + for (var i=0, l=array.length; i<l; i++) { + if (array[i] && typeof array[i] == "object") + copy[i] = this.copyObject( array[i] ); + else + copy[i] = array[i]; + } + return copy; +}; + +exports.deepCopy = function (obj) { + if (typeof obj !== "object" || !obj) + return obj; + var cons = obj.constructor; + if (cons === RegExp) + return obj; + + var copy = cons(); + for (var key in obj) { + if (typeof obj[key] === "object") { + copy[key] = exports.deepCopy(obj[key]); + } else { + copy[key] = obj[key]; + } + } + return copy; +}; + +exports.arrayToMap = function(arr) { + var map = {}; + for (var i=0; i<arr.length; i++) { + map[arr[i]] = 1; + } + return map; + +}; + +exports.createMap = function(props) { + var map = Object.create(null); + for (var i in props) { + map[i] = props[i]; + } + return map; +}; +exports.arrayRemove = function(array, value) { + for (var i = 0; i <= array.length; i++) { + if (value === array[i]) { + array.splice(i, 1); + } + } +}; + +exports.escapeRegExp = function(str) { + return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); +}; + +exports.escapeHTML = function(str) { + return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;"); +}; + +exports.getMatchOffsets = function(string, regExp) { + var matches = []; + + string.replace(regExp, function(str) { + matches.push({ + offset: arguments[arguments.length-2], + length: str.length + }); + }); + + return matches; +}; +exports.deferredCall = function(fcn) { + var timer = null; + var callback = function() { + timer = null; + fcn(); + }; + + var deferred = function(timeout) { + deferred.cancel(); + timer = setTimeout(callback, timeout || 0); + return deferred; + }; + + deferred.schedule = deferred; + + deferred.call = function() { + this.cancel(); + fcn(); + return deferred; + }; + + deferred.cancel = function() { + clearTimeout(timer); + timer = null; + return deferred; + }; + + deferred.isPending = function() { + return timer; + }; + + return deferred; +}; + + +exports.delayedCall = function(fcn, defaultTimeout) { + var timer = null; + var callback = function() { + timer = null; + fcn(); + }; + + var _self = function(timeout) { + if (timer == null) + timer = setTimeout(callback, timeout || defaultTimeout); + }; + + _self.delay = function(timeout) { + timer && clearTimeout(timer); + timer = setTimeout(callback, timeout || defaultTimeout); + }; + _self.schedule = _self; + + _self.call = function() { + this.cancel(); + fcn(); + }; + + _self.cancel = function() { + timer && clearTimeout(timer); + timer = null; + }; + + _self.isPending = function() { + return timer; + }; + + return _self; +}; +}); + +ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { +"use strict"; + +var EventEmitter = {}; +var stopPropagation = function() { this.propagationStopped = true; }; +var preventDefault = function() { this.defaultPrevented = true; }; + +EventEmitter._emit = +EventEmitter._dispatchEvent = function(eventName, e) { + this._eventRegistry || (this._eventRegistry = {}); + this._defaultHandlers || (this._defaultHandlers = {}); + + var listeners = this._eventRegistry[eventName] || []; + var defaultHandler = this._defaultHandlers[eventName]; + if (!listeners.length && !defaultHandler) + return; + + if (typeof e != "object" || !e) + e = {}; + + if (!e.type) + e.type = eventName; + if (!e.stopPropagation) + e.stopPropagation = stopPropagation; + if (!e.preventDefault) + e.preventDefault = preventDefault; + + listeners = listeners.slice(); + for (var i=0; i<listeners.length; i++) { + listeners[i](e, this); + if (e.propagationStopped) + break; + } + + if (defaultHandler && !e.defaultPrevented) + return defaultHandler(e, this); +}; + + +EventEmitter._signal = function(eventName, e) { + var listeners = (this._eventRegistry || {})[eventName]; + if (!listeners) + return; + listeners = listeners.slice(); + for (var i=0; i<listeners.length; i++) + listeners[i](e, this); +}; + +EventEmitter.once = function(eventName, callback) { + var _self = this; + callback && this.addEventListener(eventName, function newCallback() { + _self.removeEventListener(eventName, newCallback); + callback.apply(null, arguments); + }); +}; + + +EventEmitter.setDefaultHandler = function(eventName, callback) { + var handlers = this._defaultHandlers + if (!handlers) + handlers = this._defaultHandlers = {_disabled_: {}}; + + if (handlers[eventName]) { + var old = handlers[eventName]; + var disabled = handlers._disabled_[eventName]; + if (!disabled) + handlers._disabled_[eventName] = disabled = []; + disabled.push(old); + var i = disabled.indexOf(callback); + if (i != -1) + disabled.splice(i, 1); + } + handlers[eventName] = callback; +}; +EventEmitter.removeDefaultHandler = function(eventName, callback) { + var handlers = this._defaultHandlers + if (!handlers) + return; + var disabled = handlers._disabled_[eventName]; + + if (handlers[eventName] == callback) { + var old = handlers[eventName]; + if (disabled) + this.setDefaultHandler(eventName, disabled.pop()); + } else if (disabled) { + var i = disabled.indexOf(callback); + if (i != -1) + disabled.splice(i, 1); + } +}; + +EventEmitter.on = +EventEmitter.addEventListener = function(eventName, callback, capturing) { + this._eventRegistry = this._eventRegistry || {}; + + var listeners = this._eventRegistry[eventName]; + if (!listeners) + listeners = this._eventRegistry[eventName] = []; + + if (listeners.indexOf(callback) == -1) + listeners[capturing ? "unshift" : "push"](callback); + return callback; +}; + +EventEmitter.off = +EventEmitter.removeListener = +EventEmitter.removeEventListener = function(eventName, callback) { + this._eventRegistry = this._eventRegistry || {}; + + var listeners = this._eventRegistry[eventName]; + if (!listeners) + return; + + var index = listeners.indexOf(callback); + if (index !== -1) + listeners.splice(index, 1); +}; + +EventEmitter.removeAllListeners = function(eventName) { + if (this._eventRegistry) this._eventRegistry[eventName] = []; +}; + +exports.EventEmitter = EventEmitter; + +}); + +ace.define("ace/range",["require","exports","module"], function(require, exports, module) { +"use strict"; +var comparePoints = function(p1, p2) { + return p1.row - p2.row || p1.column - p2.column; +}; +var Range = function(startRow, startColumn, endRow, endColumn) { + this.start = { + row: startRow, + column: startColumn + }; + + this.end = { + row: endRow, + column: endColumn + }; +}; + +(function() { + this.isEqual = function(range) { + return this.start.row === range.start.row && + this.end.row === range.end.row && + this.start.column === range.start.column && + this.end.column === range.end.column; + }; + this.toString = function() { + return ("Range: [" + this.start.row + "/" + this.start.column + + "] -> [" + this.end.row + "/" + this.end.column + "]"); + }; + + this.contains = function(row, column) { + return this.compare(row, column) == 0; + }; + this.compareRange = function(range) { + var cmp, + end = range.end, + start = range.start; + + cmp = this.compare(end.row, end.column); + if (cmp == 1) { + cmp = this.compare(start.row, start.column); + if (cmp == 1) { + return 2; + } else if (cmp == 0) { + return 1; + } else { + return 0; + } + } else if (cmp == -1) { + return -2; + } else { + cmp = this.compare(start.row, start.column); + if (cmp == -1) { + return -1; + } else if (cmp == 1) { + return 42; + } else { + return 0; + } + } + }; + this.comparePoint = function(p) { + return this.compare(p.row, p.column); + }; + this.containsRange = function(range) { + return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; + }; + this.intersects = function(range) { + var cmp = this.compareRange(range); + return (cmp == -1 || cmp == 0 || cmp == 1); + }; + this.isEnd = function(row, column) { + return this.end.row == row && this.end.column == column; + }; + this.isStart = function(row, column) { + return this.start.row == row && this.start.column == column; + }; + this.setStart = function(row, column) { + if (typeof row == "object") { + this.start.column = row.column; + this.start.row = row.row; + } else { + this.start.row = row; + this.start.column = column; + } + }; + this.setEnd = function(row, column) { + if (typeof row == "object") { + this.end.column = row.column; + this.end.row = row.row; + } else { + this.end.row = row; + this.end.column = column; + } + }; + this.inside = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column) || this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideStart = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isEnd(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.insideEnd = function(row, column) { + if (this.compare(row, column) == 0) { + if (this.isStart(row, column)) { + return false; + } else { + return true; + } + } + return false; + }; + this.compare = function(row, column) { + if (!this.isMultiLine()) { + if (row === this.start.row) { + return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); + }; + } + + if (row < this.start.row) + return -1; + + if (row > this.end.row) + return 1; + + if (this.start.row === row) + return column >= this.start.column ? 0 : -1; + + if (this.end.row === row) + return column <= this.end.column ? 0 : 1; + + return 0; + }; + this.compareStart = function(row, column) { + if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.compareEnd = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else { + return this.compare(row, column); + } + }; + this.compareInside = function(row, column) { + if (this.end.row == row && this.end.column == column) { + return 1; + } else if (this.start.row == row && this.start.column == column) { + return -1; + } else { + return this.compare(row, column); + } + }; + this.clipRows = function(firstRow, lastRow) { + if (this.end.row > lastRow) + var end = {row: lastRow + 1, column: 0}; + else if (this.end.row < firstRow) + var end = {row: firstRow, column: 0}; + + if (this.start.row > lastRow) + var start = {row: lastRow + 1, column: 0}; + else if (this.start.row < firstRow) + var start = {row: firstRow, column: 0}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + this.extend = function(row, column) { + var cmp = this.compare(row, column); + + if (cmp == 0) + return this; + else if (cmp == -1) + var start = {row: row, column: column}; + else + var end = {row: row, column: column}; + + return Range.fromPoints(start || this.start, end || this.end); + }; + + this.isEmpty = function() { + return (this.start.row === this.end.row && this.start.column === this.end.column); + }; + this.isMultiLine = function() { + return (this.start.row !== this.end.row); + }; + this.clone = function() { + return Range.fromPoints(this.start, this.end); + }; + this.collapseRows = function() { + if (this.end.column == 0) + return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) + else + return new Range(this.start.row, 0, this.end.row, 0) + }; + this.toScreenRange = function(session) { + var screenPosStart = session.documentToScreenPosition(this.start); + var screenPosEnd = session.documentToScreenPosition(this.end); + + return new Range( + screenPosStart.row, screenPosStart.column, + screenPosEnd.row, screenPosEnd.column + ); + }; + this.moveBy = function(row, column) { + this.start.row += row; + this.start.column += column; + this.end.row += row; + this.end.column += column; + }; + +}).call(Range.prototype); +Range.fromPoints = function(start, end) { + return new Range(start.row, start.column, end.row, end.column); +}; +Range.comparePoints = comparePoints; + +Range.comparePoints = function(p1, p2) { + return p1.row - p2.row || p1.column - p2.column; +}; + + +exports.Range = Range; +}); + +ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +var Anchor = exports.Anchor = function(doc, row, column) { + this.$onChange = this.onChange.bind(this); + this.attach(doc); + + if (typeof column == "undefined") + this.setPosition(row.row, row.column); + else + this.setPosition(row, column); +}; + +(function() { + + oop.implement(this, EventEmitter); + this.getPosition = function() { + return this.$clipPositionToDocument(this.row, this.column); + }; + this.getDocument = function() { + return this.document; + }; + this.$insertRight = false; + this.onChange = function(e) { + var delta = e.data; + var range = delta.range; + + if (range.start.row == range.end.row && range.start.row != this.row) + return; + + if (range.start.row > this.row) + return; + + if (range.start.row == this.row && range.start.column > this.column) + return; + + var row = this.row; + var column = this.column; + var start = range.start; + var end = range.end; + + if (delta.action === "insertText") { + if (start.row === row && start.column <= column) { + if (start.column === column && this.$insertRight) { + } else if (start.row === end.row) { + column += end.column - start.column; + } else { + column -= start.column; + row += end.row - start.row; + } + } else if (start.row !== end.row && start.row < row) { + row += end.row - start.row; + } + } else if (delta.action === "insertLines") { + if (start.row === row && column === 0 && this.$insertRight) { + } + else if (start.row <= row) { + row += end.row - start.row; + } + } else if (delta.action === "removeText") { + if (start.row === row && start.column < column) { + if (end.column >= column) + column = start.column; + else + column = Math.max(0, column - (end.column - start.column)); + + } else if (start.row !== end.row && start.row < row) { + if (end.row === row) + column = Math.max(0, column - end.column) + start.column; + row -= (end.row - start.row); + } else if (end.row === row) { + row -= end.row - start.row; + column = Math.max(0, column - end.column) + start.column; + } + } else if (delta.action == "removeLines") { + if (start.row <= row) { + if (end.row <= row) + row -= end.row - start.row; + else { + row = start.row; + column = 0; + } + } + } + + this.setPosition(row, column, true); + }; + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._signal("change", { + old: old, + value: pos + }); + }; + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); + +ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Anchor = require("./anchor").Anchor; + +var Document = function(text) { + this.$lines = []; + if (text.length === 0) { + this.$lines = [""]; + } else if (Array.isArray(text)) { + this._insertLines(0, text); + } else { + this.insert({row: 0, column:0}, text); + } +}; + +(function() { + + oop.implement(this, EventEmitter); + this.setValue = function(text) { + var len = this.getLength(); + this.remove(new Range(0, 0, len, this.getLine(len-1).length)); + this.insert({row: 0, column:0}, text); + }; + this.getValue = function() { + return this.getAllLines().join(this.getNewLineCharacter()); + }; + this.createAnchor = function(row, column) { + return new Anchor(this, row, column); + }; + if ("aaa".split(/a/).length === 0) + this.$split = function(text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); + }; + else + this.$split = function(text) { + return text.split(/\r\n|\r|\n/); + }; + + + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r\n|\r|\n)/m); + this.$autoNewLine = match ? match[1] : "\n"; + this._signal("changeNewLineMode"); + }; + this.getNewLineCharacter = function() { + switch (this.$newLineMode) { + case "windows": + return "\r\n"; + case "unix": + return "\n"; + default: + return this.$autoNewLine || "\n"; + } + }; + + this.$autoNewLine = ""; + this.$newLineMode = "auto"; + this.setNewLineMode = function(newLineMode) { + if (this.$newLineMode === newLineMode) + return; + + this.$newLineMode = newLineMode; + this._signal("changeNewLineMode"); + }; + this.getNewLineMode = function() { + return this.$newLineMode; + }; + this.isNewLine = function(text) { + return (text == "\r\n" || text == "\r" || text == "\n"); + }; + this.getLine = function(row) { + return this.$lines[row] || ""; + }; + this.getLines = function(firstRow, lastRow) { + return this.$lines.slice(firstRow, lastRow + 1); + }; + this.getAllLines = function() { + return this.getLines(0, this.getLength()); + }; + this.getLength = function() { + return this.$lines.length; + }; + this.getTextRange = function(range) { + if (range.start.row == range.end.row) { + return this.getLine(range.start.row) + .substring(range.start.column, range.end.column); + } + var lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); + return lines.join(this.getNewLineCharacter()); + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length-1).length; + } else if (position.row < 0) + position.row = 0; + return position; + }; + this.insert = function(position, text) { + if (!text || text.length === 0) + return position; + + position = this.$clipPosition(position); + if (this.getLength() <= 1) + this.$detectNewLine(text); + + var lines = this.$split(text); + var firstLine = lines.splice(0, 1)[0]; + var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; + + position = this.insertInLine(position, firstLine); + if (lastLine !== null) { + position = this.insertNewLine(position); // terminate first line + position = this._insertLines(position.row, lines); + position = this.insertInLine(position, lastLine || ""); + } + return position; + }; + this.insertLines = function(row, lines) { + if (row >= this.getLength()) + return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); + return this._insertLines(Math.max(row, 0), lines); + }; + this._insertLines = function(row, lines) { + if (lines.length == 0) + return {row: row, column: 0}; + while (lines.length > 20000) { + var end = this._insertLines(row, lines.slice(0, 20000)); + lines = lines.slice(20000); + row = end.row; + } + + var args = [row, 0]; + args.push.apply(args, lines); + this.$lines.splice.apply(this.$lines, args); + + var range = new Range(row, 0, row + lines.length, 0); + var delta = { + action: "insertLines", + range: range, + lines: lines + }; + this._signal("change", { data: delta }); + return range.end; + }; + this.insertNewLine = function(position) { + position = this.$clipPosition(position); + var line = this.$lines[position.row] || ""; + + this.$lines[position.row] = line.substring(0, position.column); + this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); + + var end = { + row : position.row + 1, + column : 0 + }; + + var delta = { + action: "insertText", + range: Range.fromPoints(position, end), + text: this.getNewLineCharacter() + }; + this._signal("change", { data: delta }); + + return end; + }; + this.insertInLine = function(position, text) { + if (text.length == 0) + return position; + + var line = this.$lines[position.row] || ""; + + this.$lines[position.row] = line.substring(0, position.column) + text + + line.substring(position.column); + + var end = { + row : position.row, + column : position.column + text.length + }; + + var delta = { + action: "insertText", + range: Range.fromPoints(position, end), + text: text + }; + this._signal("change", { data: delta }); + + return end; + }; + this.remove = function(range) { + if (!(range instanceof Range)) + range = Range.fromPoints(range.start, range.end); + range.start = this.$clipPosition(range.start); + range.end = this.$clipPosition(range.end); + + if (range.isEmpty()) + return range.start; + + var firstRow = range.start.row; + var lastRow = range.end.row; + + if (range.isMultiLine()) { + var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; + var lastFullRow = lastRow - 1; + + if (range.end.column > 0) + this.removeInLine(lastRow, 0, range.end.column); + + if (lastFullRow >= firstFullRow) + this._removeLines(firstFullRow, lastFullRow); + + if (firstFullRow != firstRow) { + this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); + this.removeNewLine(range.start.row); + } + } + else { + this.removeInLine(firstRow, range.start.column, range.end.column); + } + return range.start; + }; + this.removeInLine = function(row, startColumn, endColumn) { + if (startColumn == endColumn) + return; + + var range = new Range(row, startColumn, row, endColumn); + var line = this.getLine(row); + var removed = line.substring(startColumn, endColumn); + var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); + this.$lines.splice(row, 1, newLine); + + var delta = { + action: "removeText", + range: range, + text: removed + }; + this._signal("change", { data: delta }); + return range.start; + }; + this.removeLines = function(firstRow, lastRow) { + if (firstRow < 0 || lastRow >= this.getLength()) + return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); + return this._removeLines(firstRow, lastRow); + }; + + this._removeLines = function(firstRow, lastRow) { + var range = new Range(firstRow, 0, lastRow + 1, 0); + var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); + + var delta = { + action: "removeLines", + range: range, + nl: this.getNewLineCharacter(), + lines: removed + }; + this._signal("change", { data: delta }); + return removed; + }; + this.removeNewLine = function(row) { + var firstLine = this.getLine(row); + var secondLine = this.getLine(row+1); + + var range = new Range(row, firstLine.length, row+1, 0); + var line = firstLine + secondLine; + + this.$lines.splice(row, 2, line); + + var delta = { + action: "removeText", + range: range, + text: this.getNewLineCharacter() + }; + this._signal("change", { data: delta }); + }; + this.replace = function(range, text) { + if (!(range instanceof Range)) + range = Range.fromPoints(range.start, range.end); + if (text.length == 0 && range.isEmpty()) + return range.start; + if (text == this.getTextRange(range)) + return range.end; + + this.remove(range); + if (text) { + var end = this.insert(range.start, text); + } + else { + end = range.start; + } + + return end; + }; + this.applyDeltas = function(deltas) { + for (var i=0; i<deltas.length; i++) { + var delta = deltas[i]; + var range = Range.fromPoints(delta.range.start, delta.range.end); + + if (delta.action == "insertLines") + this.insertLines(range.start.row, delta.lines); + else if (delta.action == "insertText") + this.insert(range.start, delta.text); + else if (delta.action == "removeLines") + this._removeLines(range.start.row, range.end.row - 1); + else if (delta.action == "removeText") + this.remove(range); + } + }; + this.revertDeltas = function(deltas) { + for (var i=deltas.length-1; i>=0; i--) { + var delta = deltas[i]; + + var range = Range.fromPoints(delta.range.start, delta.range.end); + + if (delta.action == "insertLines") + this._removeLines(range.start.row, range.end.row - 1); + else if (delta.action == "insertText") + this.remove(range); + else if (delta.action == "removeLines") + this._insertLines(range.start.row, delta.lines); + else if (delta.action == "removeText") + this.insert(range.start, delta.text); + } + }; + this.indexToPosition = function(index, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + for (var i = startRow || 0, l = lines.length; i < l; i++) { + index -= lines[i].length + newlineLength; + if (index < 0) + return {row: i, column: index + lines[i].length + newlineLength}; + } + return {row: l-1, column: lines[l-1].length}; + }; + this.positionToIndex = function(pos, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + var index = 0; + var row = Math.min(pos.row, lines.length); + for (var i = startRow || 0; i < row; ++i) + index += lines[i].length + newlineLength; + + return index + pos.column; + }; + +}).call(Document.prototype); + +exports.Document = Document; +}); + +ace.define("ace/worker/mirror",["require","exports","module","ace/document","ace/lib/lang"], function(require, exports, module) { +"use strict"; + +var Document = require("../document").Document; +var lang = require("../lib/lang"); + +var Mirror = exports.Mirror = function(sender) { + this.sender = sender; + var doc = this.doc = new Document(""); + + var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this)); + + var _self = this; + sender.on("change", function(e) { + doc.applyDeltas(e.data); + if (_self.$timeout) + return deferredUpdate.schedule(_self.$timeout); + _self.onUpdate(); + }); +}; + +(function() { + + this.$timeout = 500; + + this.setTimeout = function(timeout) { + this.$timeout = timeout; + }; + + this.setValue = function(value) { + this.doc.setValue(value); + this.deferredUpdate.schedule(this.$timeout); + }; + + this.getValue = function(callbackId) { + this.sender.callback(this.doc.getValue(), callbackId); + }; + + this.onUpdate = function() { + }; + + this.isPending = function() { + return this.deferredUpdate.isPending(); + }; + +}).call(Mirror.prototype); + +}); + +ace.define("ace/mode/css/csslint",["require","exports","module"], function(require, exports, module) { +var parserlib = {}; +(function(){ +function EventTarget(){ + this._listeners = {}; +} + +EventTarget.prototype = { + constructor: EventTarget, + addListener: function(type, listener){ + if (!this._listeners[type]){ + this._listeners[type] = []; + } + + this._listeners[type].push(listener); + }, + fire: function(event){ + if (typeof event == "string"){ + event = { type: event }; + } + if (typeof event.target != "undefined"){ + event.target = this; + } + + if (typeof event.type == "undefined"){ + throw new Error("Event object missing 'type' property."); + } + + if (this._listeners[event.type]){ + var listeners = this._listeners[event.type].concat(); + for (var i=0, len=listeners.length; i < len; i++){ + listeners[i].call(this, event); + } + } + }, + removeListener: function(type, listener){ + if (this._listeners[type]){ + var listeners = this._listeners[type]; + for (var i=0, len=listeners.length; i < len; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + break; + } + } + + + } + } +}; +function StringReader(text){ + this._input = text.replace(/\n\r?/g, "\n"); + this._line = 1; + this._col = 1; + this._cursor = 0; +} + +StringReader.prototype = { + constructor: StringReader, + getCol: function(){ + return this._col; + }, + getLine: function(){ + return this._line ; + }, + eof: function(){ + return (this._cursor == this._input.length); + }, + peek: function(count){ + var c = null; + count = (typeof count == "undefined" ? 1 : count); + if (this._cursor < this._input.length){ + c = this._input.charAt(this._cursor + count - 1); + } + + return c; + }, + read: function(){ + var c = null; + if (this._cursor < this._input.length){ + if (this._input.charAt(this._cursor) == "\n"){ + this._line++; + this._col=1; + } else { + this._col++; + } + c = this._input.charAt(this._cursor++); + } + + return c; + }, + mark: function(){ + this._bookmark = { + cursor: this._cursor, + line: this._line, + col: this._col + }; + }, + + reset: function(){ + if (this._bookmark){ + this._cursor = this._bookmark.cursor; + this._line = this._bookmark.line; + this._col = this._bookmark.col; + delete this._bookmark; + } + }, + readTo: function(pattern){ + + var buffer = "", + c; + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ + c = this.read(); + if (c){ + buffer += c; + } else { + throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); + } + } + + return buffer; + + }, + readWhile: function(filter){ + + var buffer = "", + c = this.read(); + + while(c !== null && filter(c)){ + buffer += c; + c = this.read(); + } + + return buffer; + + }, + readMatch: function(matcher){ + + var source = this._input.substring(this._cursor), + value = null; + if (typeof matcher == "string"){ + if (source.indexOf(matcher) === 0){ + value = this.readCount(matcher.length); + } + } else if (matcher instanceof RegExp){ + if (matcher.test(source)){ + value = this.readCount(RegExp.lastMatch.length); + } + } + + return value; + }, + readCount: function(count){ + var buffer = ""; + + while(count--){ + buffer += this.read(); + } + + return buffer; + } + +}; +function SyntaxError(message, line, col){ + this.col = col; + this.line = line; + this.message = message; + +} +SyntaxError.prototype = new Error(); +function SyntaxUnit(text, line, col, type){ + this.col = col; + this.line = line; + this.text = text; + this.type = type; +} +SyntaxUnit.fromToken = function(token){ + return new SyntaxUnit(token.value, token.startLine, token.startCol); +}; + +SyntaxUnit.prototype = { + constructor: SyntaxUnit, + valueOf: function(){ + return this.text; + }, + toString: function(){ + return this.text; + } + +}; +function TokenStreamBase(input, tokenData){ + this._reader = input ? new StringReader(input.toString()) : null; + this._token = null; + this._tokenData = tokenData; + this._lt = []; + this._ltIndex = 0; + + this._ltIndexCache = []; +} +TokenStreamBase.createTokenData = function(tokens){ + + var nameMap = [], + typeMap = {}, + tokenData = tokens.concat([]), + i = 0, + len = tokenData.length+1; + + tokenData.UNKNOWN = -1; + tokenData.unshift({name:"EOF"}); + + for (; i < len; i++){ + nameMap.push(tokenData[i].name); + tokenData[tokenData[i].name] = i; + if (tokenData[i].text){ + typeMap[tokenData[i].text] = i; + } + } + + tokenData.name = function(tt){ + return nameMap[tt]; + }; + + tokenData.type = function(c){ + return typeMap[c]; + }; + + return tokenData; +}; + +TokenStreamBase.prototype = { + constructor: TokenStreamBase, + match: function(tokenTypes, channel){ + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + var tt = this.get(channel), + i = 0, + len = tokenTypes.length; + + while(i < len){ + if (tt == tokenTypes[i++]){ + return true; + } + } + this.unget(); + return false; + }, + mustMatch: function(tokenTypes, channel){ + + var token; + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + if (!this.match.apply(this, arguments)){ + token = this.LT(1); + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + }, + advance: function(tokenTypes, channel){ + + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ + this.get(); + } + + return this.LA(0); + }, + get: function(channel){ + + var tokenInfo = this._tokenData, + reader = this._reader, + value, + i =0, + len = tokenInfo.length, + found = false, + token, + info; + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + + i++; + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + while((info.channel !== undefined && channel !== info.channel) && + this._ltIndex < this._lt.length){ + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + i++; + } + if ((info.channel === undefined || channel === info.channel) && + this._ltIndex <= this._lt.length){ + this._ltIndexCache.push(i); + return this._token.type; + } + } + token = this._getToken(); + if (token.type > -1 && !tokenInfo[token.type].hide){ + token.channel = tokenInfo[token.type].channel; + this._token = token; + this._lt.push(token); + this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + if (this._lt.length > 5){ + this._lt.shift(); + } + if (this._ltIndexCache.length > 5){ + this._ltIndexCache.shift(); + } + this._ltIndex = this._lt.length; + } + info = tokenInfo[token.type]; + if (info && + (info.hide || + (info.channel !== undefined && channel !== info.channel))){ + return this.get(channel); + } else { + return token.type; + } + }, + LA: function(index){ + var total = index, + tt; + if (index > 0){ + if (index > 5){ + throw new Error("Too much lookahead."); + } + while(total){ + tt = this.get(); + total--; + } + while(total < index){ + this.unget(); + total++; + } + } else if (index < 0){ + + if(this._lt[this._ltIndex+index]){ + tt = this._lt[this._ltIndex+index].type; + } else { + throw new Error("Too much lookbehind."); + } + + } else { + tt = this._token.type; + } + + return tt; + + }, + LT: function(index){ + this.LA(index); + return this._lt[this._ltIndex+index-1]; + }, + peek: function(){ + return this.LA(1); + }, + token: function(){ + return this._token; + }, + tokenName: function(tokenType){ + if (tokenType < 0 || tokenType > this._tokenData.length){ + return "UNKNOWN_TOKEN"; + } else { + return this._tokenData[tokenType].name; + } + }, + tokenType: function(tokenName){ + return this._tokenData[tokenName] || -1; + }, + unget: function(){ + if (this._ltIndexCache.length){ + this._ltIndex -= this._ltIndexCache.pop();//--; + this._token = this._lt[this._ltIndex - 1]; + } else { + throw new Error("Too much lookahead."); + } + } + +}; + + +parserlib.util = { +StringReader: StringReader, +SyntaxError : SyntaxError, +SyntaxUnit : SyntaxUnit, +EventTarget : EventTarget, +TokenStreamBase : TokenStreamBase +}; +})(); +(function(){ +var EventTarget = parserlib.util.EventTarget, +TokenStreamBase = parserlib.util.TokenStreamBase, +StringReader = parserlib.util.StringReader, +SyntaxError = parserlib.util.SyntaxError, +SyntaxUnit = parserlib.util.SyntaxUnit; + +var Colors = { + aliceblue :"#f0f8ff", + antiquewhite :"#faebd7", + aqua :"#00ffff", + aquamarine :"#7fffd4", + azure :"#f0ffff", + beige :"#f5f5dc", + bisque :"#ffe4c4", + black :"#000000", + blanchedalmond :"#ffebcd", + blue :"#0000ff", + blueviolet :"#8a2be2", + brown :"#a52a2a", + burlywood :"#deb887", + cadetblue :"#5f9ea0", + chartreuse :"#7fff00", + chocolate :"#d2691e", + coral :"#ff7f50", + cornflowerblue :"#6495ed", + cornsilk :"#fff8dc", + crimson :"#dc143c", + cyan :"#00ffff", + darkblue :"#00008b", + darkcyan :"#008b8b", + darkgoldenrod :"#b8860b", + darkgray :"#a9a9a9", + darkgrey :"#a9a9a9", + darkgreen :"#006400", + darkkhaki :"#bdb76b", + darkmagenta :"#8b008b", + darkolivegreen :"#556b2f", + darkorange :"#ff8c00", + darkorchid :"#9932cc", + darkred :"#8b0000", + darksalmon :"#e9967a", + darkseagreen :"#8fbc8f", + darkslateblue :"#483d8b", + darkslategray :"#2f4f4f", + darkslategrey :"#2f4f4f", + darkturquoise :"#00ced1", + darkviolet :"#9400d3", + deeppink :"#ff1493", + deepskyblue :"#00bfff", + dimgray :"#696969", + dimgrey :"#696969", + dodgerblue :"#1e90ff", + firebrick :"#b22222", + floralwhite :"#fffaf0", + forestgreen :"#228b22", + fuchsia :"#ff00ff", + gainsboro :"#dcdcdc", + ghostwhite :"#f8f8ff", + gold :"#ffd700", + goldenrod :"#daa520", + gray :"#808080", + grey :"#808080", + green :"#008000", + greenyellow :"#adff2f", + honeydew :"#f0fff0", + hotpink :"#ff69b4", + indianred :"#cd5c5c", + indigo :"#4b0082", + ivory :"#fffff0", + khaki :"#f0e68c", + lavender :"#e6e6fa", + lavenderblush :"#fff0f5", + lawngreen :"#7cfc00", + lemonchiffon :"#fffacd", + lightblue :"#add8e6", + lightcoral :"#f08080", + lightcyan :"#e0ffff", + lightgoldenrodyellow :"#fafad2", + lightgray :"#d3d3d3", + lightgrey :"#d3d3d3", + lightgreen :"#90ee90", + lightpink :"#ffb6c1", + lightsalmon :"#ffa07a", + lightseagreen :"#20b2aa", + lightskyblue :"#87cefa", + lightslategray :"#778899", + lightslategrey :"#778899", + lightsteelblue :"#b0c4de", + lightyellow :"#ffffe0", + lime :"#00ff00", + limegreen :"#32cd32", + linen :"#faf0e6", + magenta :"#ff00ff", + maroon :"#800000", + mediumaquamarine:"#66cdaa", + mediumblue :"#0000cd", + mediumorchid :"#ba55d3", + mediumpurple :"#9370d8", + mediumseagreen :"#3cb371", + mediumslateblue :"#7b68ee", + mediumspringgreen :"#00fa9a", + mediumturquoise :"#48d1cc", + mediumvioletred :"#c71585", + midnightblue :"#191970", + mintcream :"#f5fffa", + mistyrose :"#ffe4e1", + moccasin :"#ffe4b5", + navajowhite :"#ffdead", + navy :"#000080", + oldlace :"#fdf5e6", + olive :"#808000", + olivedrab :"#6b8e23", + orange :"#ffa500", + orangered :"#ff4500", + orchid :"#da70d6", + palegoldenrod :"#eee8aa", + palegreen :"#98fb98", + paleturquoise :"#afeeee", + palevioletred :"#d87093", + papayawhip :"#ffefd5", + peachpuff :"#ffdab9", + peru :"#cd853f", + pink :"#ffc0cb", + plum :"#dda0dd", + powderblue :"#b0e0e6", + purple :"#800080", + red :"#ff0000", + rosybrown :"#bc8f8f", + royalblue :"#4169e1", + saddlebrown :"#8b4513", + salmon :"#fa8072", + sandybrown :"#f4a460", + seagreen :"#2e8b57", + seashell :"#fff5ee", + sienna :"#a0522d", + silver :"#c0c0c0", + skyblue :"#87ceeb", + slateblue :"#6a5acd", + slategray :"#708090", + slategrey :"#708090", + snow :"#fffafa", + springgreen :"#00ff7f", + steelblue :"#4682b4", + tan :"#d2b48c", + teal :"#008080", + thistle :"#d8bfd8", + tomato :"#ff6347", + turquoise :"#40e0d0", + violet :"#ee82ee", + wheat :"#f5deb3", + white :"#ffffff", + whitesmoke :"#f5f5f5", + yellow :"#ffff00", + yellowgreen :"#9acd32", + activeBorder :"Active window border.", + activecaption :"Active window caption.", + appworkspace :"Background color of multiple document interface.", + background :"Desktop background.", + buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttontext :"Text on push buttons.", + captiontext :"Text in caption, size box, and scrollbar arrow box.", + graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", + greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", + highlight :"Item(s) selected in a control.", + highlighttext :"Text of item(s) selected in a control.", + inactiveborder :"Inactive window border.", + inactivecaption :"Inactive window caption.", + inactivecaptiontext :"Color of text in an inactive caption.", + infobackground :"Background color for tooltip controls.", + infotext :"Text color for tooltip controls.", + menu :"Menu background.", + menutext :"Text in menus.", + scrollbar :"Scroll bar gray area.", + threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + window :"Window background.", + windowframe :"Window frame.", + windowtext :"Text in windows." +}; +function Combinator(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + this.type = "unknown"; + if (/^\s+$/.test(text)){ + this.type = "descendant"; + } else if (text == ">"){ + this.type = "child"; + } else if (text == "+"){ + this.type = "adjacent-sibling"; + } else if (text == "~"){ + this.type = "sibling"; + } + +} + +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; +function MediaFeature(name, value){ + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + this.name = name; + this.value = value; +} + +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; +function MediaQuery(modifier, mediaType, features, line, col){ + + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + this.modifier = modifier; + this.mediaType = mediaType; + this.features = features; + +} + +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; +function Parser(options){ + EventTarget.call(this); + + + this.options = options || {}; + + this._tokenStream = null; +} +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; + +Parser.prototype = function(){ + + var proto = new EventTarget(), //new prototype + prop, + additions = { + constructor: Parser, + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, + + _stylesheet: function(){ + + var tokenStream = this._tokenStream, + charset = null, + count, + token, + tt; + + this.fire("startstylesheet"); + this._charset(); + + this._skipCruft(); + while (tokenStream.peek() == Tokens.IMPORT_SYM){ + this._import(); + this._skipCruft(); + } + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ + this._namespace(); + this._skipCruft(); + } + tt = tokenStream.peek(); + while(tt > Tokens.EOF){ + + try { + + switch(tt){ + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: //unknown @ rule + tokenStream.get(); + if (!this.options.strict){ + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); + count=0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ + count++; //keep track of nesting depth + } + + while(count){ + tokenStream.advance([Tokens.RBRACE]); + count--; + } + + } else { + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if(!this._ruleset()){ + switch(tt){ + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); //get the last token + this._unexpectedToken(tokenStream.token()); + } + + } + } + } catch(ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + + tt = tokenStream.peek(); + } + + if (tt != Tokens.EOF){ + this._unexpectedToken(tokenStream.token()); + } + + this.fire("endstylesheet"); + }, + + _charset: function(emit){ + var tokenStream = this._tokenStream, + charset, + token, + line, + col; + + if (tokenStream.match(Tokens.CHARSET_SYM)){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); + + token = tokenStream.token(); + charset = token.value; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + + if (emit !== false){ + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, + + _import: function(emit){ + + var tokenStream = this._tokenStream, + tt, + uri, + importToken, + mediaList = []; + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); + + this._readWhitespace(); + + mediaList = this._media_query_list(); + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } + + }, + + _namespace: function(emit){ + + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); + if (tokenStream.match(Tokens.IDENT)){ + prefix = tokenStream.token().value; + this._readWhitespace(); + } + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } + + }, + + _media: function(){ + var tokenStream = this._tokenStream, + line, + col, + mediaList;// = []; + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); + + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); + + while(true) { + if (tokenStream.peek() == Tokens.PAGE_SYM){ + this._page(); + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ + this._font_face(); + } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ + this._viewport(); + } else if (!this._ruleset()){ + break; + } + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, + _media_query_list: function(){ + var tokenStream = this._tokenStream, + mediaList = []; + + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ + mediaList.push(this._media_query()); + } + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + mediaList.push(this._media_query()); + } + + return mediaList; + }, + _media_query: function(){ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; + + if (tokenStream.match(Tokens.IDENT)){ + ident = tokenStream.token().value.toLowerCase(); + if (ident != "only" && ident != "not"){ + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT){ + type = this._media_type(); + if (token === null){ + token = tokenStream.token(); + } + } else if (tokenStream.peek() == Tokens.LPAREN){ + if (token === null){ + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } + + if (type === null && expressions.length === 0){ + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)){ + if (tokenStream.token().value.toLowerCase() != "and"){ + this._unexpectedToken(tokenStream.token()); + } + + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } + + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + _media_type: function(){ + return this._media_feature(); + }, + _media_expression: function(){ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; + + tokenStream.mustMatch(Tokens.LPAREN); + + feature = this._media_feature(); + this._readWhitespace(); + + if (tokenStream.match(Tokens.COLON)){ + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } + + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); + + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + }, + _media_feature: function(){ + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.IDENT); + + return SyntaxUnit.fromToken(tokenStream.token()); + }, + _page: function(){ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + if (tokenStream.match(Tokens.IDENT)){ + identifier = tokenStream.token().value; + if (identifier.toLowerCase() === "auto"){ + this._unexpectedToken(tokenStream.token()); + } + } + if (tokenStream.peek() == Tokens.COLON){ + pseudoPage = this._pseudo_page(); + } + + this._readWhitespace(); + + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + this._readDeclarations(true, true); + + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + }, + _margin: function(){ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); + + if (marginSym){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, + _margin_sym: function(){ + + var tokenStream = this._tokenStream; + + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) + { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } + + }, + + _pseudo_page: function(){ + + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); + + return tokenStream.token().value; + }, + + _font_face: function(){ + var tokenStream = this._tokenStream, + line, + col; + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startfontface", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, + + _viewport: function(){ + var tokenStream = this._tokenStream, + line, + col; + + tokenStream.mustMatch(Tokens.VIEWPORT_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startviewport", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endviewport", + line: line, + col: col + }); + + }, + + _operator: function(inFunction){ + + var tokenStream = this._tokenStream, + token = null; + + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || + (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ + token = tokenStream.token(); + this._readWhitespace(); + } + return token ? PropertyValuePart.fromToken(token) : null; + + }, + + _combinator: function(){ + + var tokenStream = this._tokenStream, + value = null, + token; + + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); + } + + return value; + }, + + _unary_operator: function(){ + + var tokenStream = this._tokenStream; + + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ + return tokenStream.token().value; + } else { + return null; + } + }, + + _property: function(){ + + var tokenStream = this._tokenStream, + value = null, + hack = null, + tokenValue, + token, + line, + col; + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } + + if(tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + tokenValue = token.value; + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ + hack = "_"; + tokenValue = tokenValue.substring(1); + } + + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); + this._readWhitespace(); + } + + return value; + }, + _ruleset: function(){ + + var tokenStream = this._tokenStream, + tt, + selectors; + try { + selectors = this._selectors_group(); + } catch (ex){ + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt == Tokens.RBRACE){ + } else { + throw ex; + } + + } else { + throw ex; + } + return true; + } + if (selectors){ + + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + } + + return selectors; + + }, + _selectors_group: function(){ + var tokenStream = this._tokenStream, + selectors = [], + selector; + + selector = this._selector(); + if (selector !== null){ + + selectors.push(selector); + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + selector = this._selector(); + if (selector !== null){ + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } + } + + return selectors.length ? selectors : null; + }, + _selector: function(){ + + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + return null; + } + + selector.push(nextSelector); + + do { + combinator = this._combinator(); + + if (combinator !== null){ + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + this._unexpectedToken(tokenStream.LT(1)); + } else { + selector.push(nextSelector); + } + } else { + if (this._readWhitespace()){ + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); + combinator = this._combinator(); + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + if (combinator !== null){ + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + + if (combinator !== null){ + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while(true); + + return new Selector(selector, selector[0].line, selector[0].col); + }, + _simple_selector_sequence: function(){ + + var tokenStream = this._tokenStream, + elementName = null, + modifiers = [], + selectorText= "", + components = [ + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, + found = false, + line, + col; + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + elementName = this._type_selector(); + if (!elementName){ + elementName = this._universal(); + } + + if (elementName !== null){ + selectorText += elementName; + } + + while(true){ + if (tokenStream.peek() === Tokens.S){ + break; + } + while(i < len && component === null){ + component = components[i++].call(this); + } + + if (component === null){ + if (selectorText === ""){ + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } + } + + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; + }, + _type_selector: function(){ + + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); + + if (!elementName){ + if (ns){ + tokenStream.unget(); + if (ns.length > 1){ + tokenStream.unget(); + } + } + + return null; + } else { + if (ns){ + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } + }, + _class: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.DOT)){ + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } + + }, + _element_name: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } + }, + _namespace_prefix: function(){ + var tokenStream = this._tokenStream, + value = ""; + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ + value += tokenStream.token().value; + } + + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; + + } + + return value.length ? value : null; + }, + _universal: function(){ + var tokenStream = this._tokenStream, + value = "", + ns; + + ns = this._namespace_prefix(); + if(ns){ + value += ns; + } + + if(tokenStream.match(Tokens.STAR)){ + value += "*"; + } + + return value.length ? value : null; + + }, + _attrib: function(){ + + var tokenStream = this._tokenStream, + value = null, + ns, + token; + + if (tokenStream.match(Tokens.LBRACKET)){ + token = tokenStream.token(); + value = token.value; + value += this._readWhitespace(); + + ns = this._namespace_prefix(); + + if (ns){ + value += ns; + } + + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); + + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); + } else { + return null; + } + }, + _pseudo: function(){ + + var tokenStream = this._tokenStream, + pseudo = null, + colons = ":", + line, + col; + + if (tokenStream.match(Tokens.COLON)){ + + if (tokenStream.match(Tokens.COLON)){ + colons += ":"; + } + + if (tokenStream.match(Tokens.IDENT)){ + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() == Tokens.FUNCTION){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); + } + + if (pseudo){ + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } + } + + return pseudo; + }, + _functional_pseudo: function(){ + + var tokenStream = this._tokenStream, + value = null; + + if(tokenStream.match(Tokens.FUNCTION)){ + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + + return value; + }, + _expression: function(){ + + var tokenStream = this._tokenStream, + value = ""; + + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION, Tokens.SLASH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + return value.length ? value : null; + + }, + _negation: function(){ + + var tokenStream = this._tokenStream, + line, + col, + value = "", + arg, + subpart = null; + + if (tokenStream.match(Tokens.NOT)){ + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; + + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } + + return subpart; + }, + _negation_arg: function(){ + + var tokenStream = this._tokenStream, + args = [ + this._type_selector, + this._universal, + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo + ], + arg = null, + i = 0, + len = args.length, + elementName, + line, + col, + part; + + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + while(i < len && arg === null){ + + arg = args[i].call(this); + i++; + } + if (arg === null){ + this._unexpectedToken(tokenStream.LT(1)); + } + if (arg.type == "elementName"){ + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } + + return part; + }, + + _declaration: function(){ + + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + error = null, + invalid = null, + propertyName= ""; + + property = this._property(); + if (property !== null){ + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + if (!expr || expr.length === 0){ + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); + propertyName = property.toString(); + if (this.options.starHack && property.hack == "*" || + this.options.underscoreHack && property.hack == "_") { + + propertyName = property.text; + } + + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; + } + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; + } + }, + + _prio: function(){ + + var tokenStream = this._tokenStream, + result = tokenStream.match(Tokens.IMPORTANT_SYM); + + this._readWhitespace(); + return result; + }, + + _expr: function(inFunction){ + + var tokenStream = this._tokenStream, + values = [], + value = null, + operator = null; + + value = this._term(inFunction); + if (value !== null){ + + values.push(value); + + do { + operator = this._operator(inFunction); + if (operator){ + values.push(operator); + } /*else { + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ + + value = this._term(inFunction); + + if (value === null){ + break; + } else { + values.push(value); + } + } while(true); + } + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; + }, + + _term: function(inFunction){ + + var tokenStream = this._tokenStream, + unary = null, + value = null, + endChar = null, + token, + line, + col; + unary = this._unary_operator(); + if (unary !== null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + + value = this._ie_function(); + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ + + token = tokenStream.token(); + endChar = token.endChar; + value = token.value + this._expr(inFunction).text; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + tokenStream.mustMatch(Tokens.type(endChar)); + value += endChar; + this._readWhitespace(); + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ + + value = tokenStream.token().value; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + this._readWhitespace(); + } else { + token = this._hexcolor(); + if (token === null){ + if (unary === null){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } + if (value === null){ + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ + value = this._ie_function(); + } else { + value = this._function(); + } + } + + } else { + value = token.value; + if (unary === null){ + line = token.startLine; + col = token.startCol; + } + } + + } + + return value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + + }, + + _function: function(){ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + if (tokenStream.match(Tokens.FUNCTION)){ + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(true); + functionText += expr; + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + } + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _ie_function: function(){ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ + functionText = tokenStream.token().value; + + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _hexcolor: function(){ + + var tokenStream = this._tokenStream, + token = null, + color; + + if(tokenStream.match(Tokens.HASH)){ + + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)){ + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); + } + + return token; + }, + + _keyframes: function(){ + var tokenStream = this._tokenStream, + token, + tt, + name, + prefix = ""; + + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@\-([^\-]+)\-/.test(token.value)) { + prefix = RegExp.$1; + } + + this._readWhitespace(); + name = this._keyframe_name(); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); + + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tt = tokenStream.peek(); + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } + + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + + }, + + _keyframe_name: function(){ + var tokenStream = this._tokenStream, + token; + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + _keyframe_rule: function(){ + var tokenStream = this._tokenStream, + token, + keyList = this._key_list(); + + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + }, + + _key_list: function(){ + var tokenStream = this._tokenStream, + token, + key, + keyList = []; + keyList.push(this._key()); + + this._readWhitespace(); + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } + + return keyList; + }, + + _key: function(){ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.PERCENTAGE)){ + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + + if (/from|to/i.test(token.value)){ + return SyntaxUnit.fromToken(token); + } + + tokenStream.unget(); + } + this._unexpectedToken(tokenStream.LT(1)); + }, + _skipCruft: function(){ + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ + } + }, + _readDeclarations: function(checkStart, readMargins){ + var tokenStream = this._tokenStream, + tt; + + + this._readWhitespace(); + + if (checkStart){ + tokenStream.mustMatch(Tokens.LBRACE); + } + + this._readWhitespace(); + + try { + + while(true){ + + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ + } else if (this._declaration()){ + if (!tokenStream.match(Tokens.SEMICOLON)){ + break; + } + } else { + break; + } + this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt == Tokens.SEMICOLON){ + this._readDeclarations(false, readMargins); + } else if (tt != Tokens.RBRACE){ + throw ex; + } + + } else { + throw ex; + } + } + + }, + _readWhitespace: function(){ + + var tokenStream = this._tokenStream, + ws = ""; + + while(tokenStream.match(Tokens.S)){ + ws += tokenStream.token().value; + } + + return ws; + }, + _unexpectedToken: function(token){ + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, + _verifyEnd: function(){ + if (this._tokenStream.LA(1) != Tokens.EOF){ + this._unexpectedToken(this._tokenStream.LT(1)); + } + }, + _validateProperty: function(property, value){ + Validation.validate(property, value); + }, + + parse: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, + + parseStyleSheet: function(input){ + return this.parse(input); + }, + + parseMediaQuery: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); + this._verifyEnd(); + return result; + }, + parsePropertyValue: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._expr(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseRule: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._ruleset(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseSelector: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._selector(); + this._readWhitespace(); + this._verifyEnd(); + return result; + }, + parseStyleAttribute: function(input){ + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; + for (prop in additions){ + if (additions.hasOwnProperty(prop)){ + proto[prop] = additions[prop]; + } + } + + return proto; +}(); +var Properties = { + "align-items" : "flex-start | flex-end | center | baseline | stretch", + "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", + "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>", + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : { multi: "<time>", comma: true }, + "animation-direction" : { multi: "normal | alternate", comma: true }, + "animation-duration" : { multi: "<time>", comma: true }, + "animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true }, + "animation-iteration-count" : { multi: "<number> | infinite", comma: true }, + "animation-name" : { multi: "none | <ident>", comma: true }, + "animation-play-state" : { multi: "running | paused", comma: true }, + "animation-timing-function" : 1, + "-moz-animation-delay" : { multi: "<time>", comma: true }, + "-moz-animation-direction" : { multi: "normal | alternate", comma: true }, + "-moz-animation-duration" : { multi: "<time>", comma: true }, + "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, + "-moz-animation-name" : { multi: "none | <ident>", comma: true }, + "-moz-animation-play-state" : { multi: "running | paused", comma: true }, + + "-ms-animation-delay" : { multi: "<time>", comma: true }, + "-ms-animation-direction" : { multi: "normal | alternate", comma: true }, + "-ms-animation-duration" : { multi: "<time>", comma: true }, + "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, + "-ms-animation-name" : { multi: "none | <ident>", comma: true }, + "-ms-animation-play-state" : { multi: "running | paused", comma: true }, + + "-webkit-animation-delay" : { multi: "<time>", comma: true }, + "-webkit-animation-direction" : { multi: "normal | alternate", comma: true }, + "-webkit-animation-duration" : { multi: "<time>", comma: true }, + "-webkit-animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true }, + "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, + "-webkit-animation-name" : { multi: "none | <ident>", comma: true }, + "-webkit-animation-play-state" : { multi: "running | paused", comma: true }, + + "-o-animation-delay" : { multi: "<time>", comma: true }, + "-o-animation-direction" : { multi: "normal | alternate", comma: true }, + "-o-animation-duration" : { multi: "<time>", comma: true }, + "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true }, + "-o-animation-name" : { multi: "none | <ident>", comma: true }, + "-o-animation-play-state" : { multi: "running | paused", comma: true }, + + "appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit", + "azimuth" : function (expression) { + var simple = "<angle> | leftwards | rightwards | inherit", + direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side", + behind = false, + valid = false, + part; + + if (!ValidationTypes.isAny(expression, simple)) { + if (ValidationTypes.isAny(expression, "behind")) { + behind = true; + valid = true; + } + + if (ValidationTypes.isAny(expression, direction)) { + valid = true; + if (!behind) { + ValidationTypes.isAny(expression, "behind"); + } + } + } + + if (expression.hasNext()) { + part = expression.next(); + if (valid) { + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col); + } + } + }, + "backface-visibility" : "visible | hidden", + "background" : 1, + "background-attachment" : { multi: "<attachment>", comma: true }, + "background-clip" : { multi: "<box>", comma: true }, + "background-color" : "<color> | inherit", + "background-image" : { multi: "<bg-image>", comma: true }, + "background-origin" : { multi: "<box>", comma: true }, + "background-position" : { multi: "<bg-position>", comma: true }, + "background-repeat" : { multi: "<repeat-style>" }, + "background-size" : { multi: "<bg-size>", comma: true }, + "baseline-shift" : "baseline | sub | super | <percentage> | <length>", + "behavior" : 1, + "binding" : 1, + "bleed" : "<length>", + "bookmark-label" : "<content> | <attr> | <string>", + "bookmark-level" : "none | <integer>", + "bookmark-state" : "open | closed", + "bookmark-target" : "none | <uri> | <attr>", + "border" : "<border-width> || <border-style> || <color>", + "border-bottom" : "<border-width> || <border-style> || <color>", + "border-bottom-color" : "<color> | inherit", + "border-bottom-left-radius" : "<x-one-radius>", + "border-bottom-right-radius" : "<x-one-radius>", + "border-bottom-style" : "<border-style>", + "border-bottom-width" : "<border-width>", + "border-collapse" : "collapse | separate | inherit", + "border-color" : { multi: "<color> | inherit", max: 4 }, + "border-image" : 1, + "border-image-outset" : { multi: "<length> | <number>", max: 4 }, + "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 }, + "border-image-slice" : function(expression) { + + var valid = false, + numeric = "<number> | <percentage>", + fill = false, + count = 0, + max = 4, + part; + + if (ValidationTypes.isAny(expression, "fill")) { + fill = true; + valid = true; + } + + while (expression.hasNext() && count < max) { + valid = ValidationTypes.isAny(expression, numeric); + if (!valid) { + break; + } + count++; + } + + + if (!fill) { + ValidationTypes.isAny(expression, "fill"); + } else { + valid = true; + } + + if (expression.hasNext()) { + part = expression.next(); + if (valid) { + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col); + } + } + }, + "border-image-source" : "<image> | none", + "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 }, + "border-left" : "<border-width> || <border-style> || <color>", + "border-left-color" : "<color> | inherit", + "border-left-style" : "<border-style>", + "border-left-width" : "<border-width>", + "border-radius" : function(expression) { + + var valid = false, + simple = "<length> | <percentage> | inherit", + slash = false, + fill = false, + count = 0, + max = 8, + part; + + while (expression.hasNext() && count < max) { + valid = ValidationTypes.isAny(expression, simple); + if (!valid) { + + if (expression.peek() == "/" && count > 0 && !slash) { + slash = true; + max = count + 5; + expression.next(); + } else { + break; + } + } + count++; + } + + if (expression.hasNext()) { + part = expression.next(); + if (valid) { + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col); + } + } + }, + "border-right" : "<border-width> || <border-style> || <color>", + "border-right-color" : "<color> | inherit", + "border-right-style" : "<border-style>", + "border-right-width" : "<border-width>", + "border-spacing" : { multi: "<length> | inherit", max: 2 }, + "border-style" : { multi: "<border-style>", max: 4 }, + "border-top" : "<border-width> || <border-style> || <color>", + "border-top-color" : "<color> | inherit", + "border-top-left-radius" : "<x-one-radius>", + "border-top-right-radius" : "<x-one-radius>", + "border-top-style" : "<border-style>", + "border-top-width" : "<border-width>", + "border-width" : { multi: "<border-width>", max: 4 }, + "bottom" : "<margin-width> | inherit", + "-moz-box-align" : "start | end | center | baseline | stretch", + "-moz-box-decoration-break" : "slice |clone", + "-moz-box-direction" : "normal | reverse | inherit", + "-moz-box-flex" : "<number>", + "-moz-box-flex-group" : "<integer>", + "-moz-box-lines" : "single | multiple", + "-moz-box-ordinal-group" : "<integer>", + "-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit", + "-moz-box-pack" : "start | end | center | justify", + "-webkit-box-align" : "start | end | center | baseline | stretch", + "-webkit-box-decoration-break" : "slice |clone", + "-webkit-box-direction" : "normal | reverse | inherit", + "-webkit-box-flex" : "<number>", + "-webkit-box-flex-group" : "<integer>", + "-webkit-box-lines" : "single | multiple", + "-webkit-box-ordinal-group" : "<integer>", + "-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit", + "-webkit-box-pack" : "start | end | center | justify", + "box-shadow" : function (expression) { + var result = false, + part; + + if (!ValidationTypes.isAny(expression, "none")) { + Validation.multiProperty("<shadow>", expression, true, Infinity); + } else { + if (expression.hasNext()) { + part = expression.next(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } + } + }, + "box-sizing" : "content-box | border-box | inherit", + "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column", + "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column", + "break-inside" : "auto | avoid | avoid-page | avoid-column", + "caption-side" : "top | bottom | inherit", + "clear" : "none | right | left | both | inherit", + "clip" : 1, + "color" : "<color> | inherit", + "color-profile" : 1, + "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/ + "column-fill" : "auto | balance", + "column-gap" : "<length> | normal", + "column-rule" : "<border-width> || <border-style> || <color>", + "column-rule-color" : "<color>", + "column-rule-style" : "<border-style>", + "column-rule-width" : "<border-width>", + "column-span" : "none | all", + "column-width" : "<length> | auto", + "columns" : 1, + "content" : 1, + "counter-increment" : 1, + "counter-reset" : 1, + "crop" : "<shape> | auto", + "cue" : "cue-after | cue-before | inherit", + "cue-after" : 1, + "cue-before" : 1, + "cursor" : 1, + "direction" : "ltr | rtl | inherit", + "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", + "dominant-baseline" : 1, + "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>", + "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>", + "drop-initial-before-align" : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "drop-initial-size" : "auto | line | <length> | <percentage>", + "drop-initial-value" : "initial | <integer>", + "elevation" : "<angle> | below | level | above | higher | lower | inherit", + "empty-cells" : "show | hide | inherit", + "filter" : 1, + "fit" : "fill | hidden | meet | slice", + "fit-position" : 1, + "flex" : "<flex>", + "flex-basis" : "<width>", + "flex-direction" : "row | row-reverse | column | column-reverse", + "flex-flow" : "<flex-direction> || <flex-wrap>", + "flex-grow" : "<number>", + "flex-shrink" : "<number>", + "flex-wrap" : "nowrap | wrap | wrap-reverse", + "-webkit-flex" : "<flex>", + "-webkit-flex-basis" : "<width>", + "-webkit-flex-direction" : "row | row-reverse | column | column-reverse", + "-webkit-flex-flow" : "<flex-direction> || <flex-wrap>", + "-webkit-flex-grow" : "<number>", + "-webkit-flex-shrink" : "<number>", + "-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse", + "-ms-flex" : "<flex>", + "-ms-flex-align" : "start | end | center | stretch | baseline", + "-ms-flex-direction" : "row | row-reverse | column | column-reverse | inherit", + "-ms-flex-order" : "<number>", + "-ms-flex-pack" : "start | end | center | justify", + "-ms-flex-wrap" : "nowrap | wrap | wrap-reverse", + "float" : "left | right | none | inherit", + "float-offset" : 1, + "font" : 1, + "font-family" : 1, + "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit", + "font-size-adjust" : "<number> | none | inherit", + "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit", + "font-style" : "normal | italic | oblique | inherit", + "font-variant" : "normal | small-caps | inherit", + "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit", + "grid-cell-stacking" : "columns | rows | layer", + "grid-column" : 1, + "grid-columns" : 1, + "grid-column-align" : "start | end | center | stretch", + "grid-column-sizing" : 1, + "grid-column-span" : "<integer>", + "grid-flow" : "none | rows | columns", + "grid-layer" : "<integer>", + "grid-row" : 1, + "grid-rows" : 1, + "grid-row-align" : "start | end | center | stretch", + "grid-row-span" : "<integer>", + "grid-row-sizing" : 1, + "hanging-punctuation" : 1, + "height" : "<margin-width> | <content-sizing> | inherit", + "hyphenate-after" : "<integer> | auto", + "hyphenate-before" : "<integer> | auto", + "hyphenate-character" : "<string> | auto", + "hyphenate-lines" : "no-limit | <integer>", + "hyphenate-resource" : 1, + "hyphens" : "none | manual | auto", + "icon" : 1, + "image-orientation" : "angle | auto", + "image-rendering" : 1, + "image-resolution" : 1, + "inline-box-align" : "initial | last | <integer>", + "justify-content" : "flex-start | flex-end | center | space-between | space-around", + "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around", + "left" : "<margin-width> | inherit", + "letter-spacing" : "<length> | normal | inherit", + "line-height" : "<number> | <length> | <percentage> | normal | inherit", + "line-break" : "auto | loose | normal | strict", + "line-stacking" : 1, + "line-stacking-ruby" : "exclude-ruby | include-ruby", + "line-stacking-shift" : "consider-shifts | disregard-shifts", + "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height", + "list-style" : 1, + "list-style-image" : "<uri> | none | inherit", + "list-style-position" : "inside | outside | inherit", + "list-style-type" : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit", + "margin" : { multi: "<margin-width> | inherit", max: 4 }, + "margin-bottom" : "<margin-width> | inherit", + "margin-left" : "<margin-width> | inherit", + "margin-right" : "<margin-width> | inherit", + "margin-top" : "<margin-width> | inherit", + "mark" : 1, + "mark-after" : 1, + "mark-before" : 1, + "marks" : 1, + "marquee-direction" : 1, + "marquee-play-count" : 1, + "marquee-speed" : 1, + "marquee-style" : 1, + "max-height" : "<length> | <percentage> | <content-sizing> | none | inherit", + "max-width" : "<length> | <percentage> | <content-sizing> | none | inherit", + "min-height" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit", + "min-width" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit", + "move-to" : 1, + "nav-down" : 1, + "nav-index" : 1, + "nav-left" : 1, + "nav-right" : 1, + "nav-up" : 1, + "opacity" : "<number> | inherit", + "order" : "<integer>", + "-webkit-order" : "<integer>", + "orphans" : "<integer> | inherit", + "outline" : 1, + "outline-color" : "<color> | invert | inherit", + "outline-offset" : 1, + "outline-style" : "<border-style> | inherit", + "outline-width" : "<border-width> | inherit", + "overflow" : "visible | hidden | scroll | auto | inherit", + "overflow-style" : 1, + "overflow-wrap" : "normal | break-word", + "overflow-x" : 1, + "overflow-y" : 1, + "padding" : { multi: "<padding-width> | inherit", max: 4 }, + "padding-bottom" : "<padding-width> | inherit", + "padding-left" : "<padding-width> | inherit", + "padding-right" : "<padding-width> | inherit", + "padding-top" : "<padding-width> | inherit", + "page" : 1, + "page-break-after" : "auto | always | avoid | left | right | inherit", + "page-break-before" : "auto | always | avoid | left | right | inherit", + "page-break-inside" : "auto | avoid | inherit", + "page-policy" : 1, + "pause" : 1, + "pause-after" : 1, + "pause-before" : 1, + "perspective" : 1, + "perspective-origin" : 1, + "phonemes" : 1, + "pitch" : 1, + "pitch-range" : 1, + "play-during" : 1, + "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit", + "position" : "static | relative | absolute | fixed | inherit", + "presentation-level" : 1, + "punctuation-trim" : 1, + "quotes" : 1, + "rendering-intent" : 1, + "resize" : 1, + "rest" : 1, + "rest-after" : 1, + "rest-before" : 1, + "richness" : 1, + "right" : "<margin-width> | inherit", + "rotation" : 1, + "rotation-point" : 1, + "ruby-align" : 1, + "ruby-overhang" : 1, + "ruby-position" : 1, + "ruby-span" : 1, + "size" : 1, + "speak" : "normal | none | spell-out | inherit", + "speak-header" : "once | always | inherit", + "speak-numeral" : "digits | continuous | inherit", + "speak-punctuation" : "code | none | inherit", + "speech-rate" : 1, + "src" : 1, + "stress" : 1, + "string-set" : 1, + + "table-layout" : "auto | fixed | inherit", + "tab-size" : "<integer> | <length>", + "target" : 1, + "target-name" : 1, + "target-new" : 1, + "target-position" : 1, + "text-align" : "left | right | center | justify | inherit" , + "text-align-last" : 1, + "text-decoration" : 1, + "text-emphasis" : 1, + "text-height" : 1, + "text-indent" : "<length> | <percentage> | inherit", + "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida", + "text-outline" : 1, + "text-overflow" : 1, + "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit", + "text-shadow" : 1, + "text-transform" : "capitalize | uppercase | lowercase | none | inherit", + "text-wrap" : "normal | none | avoid", + "top" : "<margin-width> | inherit", + "-ms-touch-action" : "auto | none | pan-x | pan-y", + "touch-action" : "auto | none | pan-x | pan-y", + "transform" : 1, + "transform-origin" : 1, + "transform-style" : 1, + "transition" : 1, + "transition-delay" : 1, + "transition-duration" : 1, + "transition-property" : 1, + "transition-timing-function" : 1, + "unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit", + "user-modify" : "read-only | read-write | write-only | inherit", + "user-select" : "none | text | toggle | element | elements | all | inherit", + "vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>", + "visibility" : "visible | hidden | collapse | inherit", + "voice-balance" : 1, + "voice-duration" : 1, + "voice-family" : 1, + "voice-pitch" : 1, + "voice-pitch-range" : 1, + "voice-rate" : 1, + "voice-stress" : 1, + "voice-volume" : 1, + "volume" : 1, + "white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap", //http://perishablepress.com/wrapping-content/ + "white-space-collapse" : 1, + "widows" : "<integer> | inherit", + "width" : "<length> | <percentage> | <content-sizing> | auto | inherit", + "word-break" : "normal | keep-all | break-all", + "word-spacing" : "<length> | normal | inherit", + "word-wrap" : "normal | break-word", + "writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit", + "z-index" : "<integer> | auto | inherit", + "zoom" : "<number> | <percentage> | normal" +}; +function PropertyName(text, hack, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE); + this.hack = hack; + +} + +PropertyName.prototype = new SyntaxUnit(); +PropertyName.prototype.constructor = PropertyName; +PropertyName.prototype.toString = function(){ + return (this.hack ? this.hack : "") + this.text; +}; +function PropertyValue(parts, line, col){ + + SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE); + this.parts = parts; + +} + +PropertyValue.prototype = new SyntaxUnit(); +PropertyValue.prototype.constructor = PropertyValue; +function PropertyValueIterator(value){ + this._i = 0; + this._parts = value.parts; + this._marks = []; + this.value = value; + +} +PropertyValueIterator.prototype.count = function(){ + return this._parts.length; +}; +PropertyValueIterator.prototype.isFirst = function(){ + return this._i === 0; +}; +PropertyValueIterator.prototype.hasNext = function(){ + return (this._i < this._parts.length); +}; +PropertyValueIterator.prototype.mark = function(){ + this._marks.push(this._i); +}; +PropertyValueIterator.prototype.peek = function(count){ + return this.hasNext() ? this._parts[this._i + (count || 0)] : null; +}; +PropertyValueIterator.prototype.next = function(){ + return this.hasNext() ? this._parts[this._i++] : null; +}; +PropertyValueIterator.prototype.previous = function(){ + return this._i > 0 ? this._parts[--this._i] : null; +}; +PropertyValueIterator.prototype.restore = function(){ + if (this._marks.length){ + this._i = this._marks.pop(); + } +}; +function PropertyValuePart(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE); + this.type = "unknown"; + + var temp; + if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension + this.type = "dimension"; + this.value = +RegExp.$1; + this.units = RegExp.$2; + switch(this.units.toLowerCase()){ + + case "em": + case "rem": + case "ex": + case "px": + case "cm": + case "mm": + case "in": + case "pt": + case "pc": + case "ch": + case "vh": + case "vw": + case "vmax": + case "vmin": + this.type = "length"; + break; + + case "deg": + case "rad": + case "grad": + this.type = "angle"; + break; + + case "ms": + case "s": + this.type = "time"; + break; + + case "hz": + case "khz": + this.type = "frequency"; + break; + + case "dpi": + case "dpcm": + this.type = "resolution"; + break; + + } + + } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage + this.type = "percentage"; + this.value = +RegExp.$1; + } else if (/^([+\-]?\d+)$/i.test(text)){ //integer + this.type = "integer"; + this.value = +RegExp.$1; + } else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number + this.type = "number"; + this.value = +RegExp.$1; + + } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor + this.type = "color"; + temp = RegExp.$1; + if (temp.length == 3){ + this.red = parseInt(temp.charAt(0)+temp.charAt(0),16); + this.green = parseInt(temp.charAt(1)+temp.charAt(1),16); + this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16); + } else { + this.red = parseInt(temp.substring(0,2),16); + this.green = parseInt(temp.substring(2,4),16); + this.blue = parseInt(temp.substring(4,6),16); + } + } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers + this.type = "color"; + this.red = +RegExp.$1; + this.green = +RegExp.$2; + this.blue = +RegExp.$3; + } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages + this.type = "color"; + this.red = +RegExp.$1 * 255 / 100; + this.green = +RegExp.$2 * 255 / 100; + this.blue = +RegExp.$3 * 255 / 100; + } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers + this.type = "color"; + this.red = +RegExp.$1; + this.green = +RegExp.$2; + this.blue = +RegExp.$3; + this.alpha = +RegExp.$4; + } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages + this.type = "color"; + this.red = +RegExp.$1 * 255 / 100; + this.green = +RegExp.$2 * 255 / 100; + this.blue = +RegExp.$3 * 255 / 100; + this.alpha = +RegExp.$4; + } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl() + this.type = "color"; + this.hue = +RegExp.$1; + this.saturation = +RegExp.$2 / 100; + this.lightness = +RegExp.$3 / 100; + } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages + this.type = "color"; + this.hue = +RegExp.$1; + this.saturation = +RegExp.$2 / 100; + this.lightness = +RegExp.$3 / 100; + this.alpha = +RegExp.$4; + } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI + this.type = "uri"; + this.uri = RegExp.$1; + } else if (/^([^\(]+)\(/i.test(text)){ + this.type = "function"; + this.name = RegExp.$1; + this.value = text; + } else if (/^["'][^"']*["']/.test(text)){ //string + this.type = "string"; + this.value = eval(text); + } else if (Colors[text.toLowerCase()]){ //named color + this.type = "color"; + temp = Colors[text.toLowerCase()].substring(1); + this.red = parseInt(temp.substring(0,2),16); + this.green = parseInt(temp.substring(2,4),16); + this.blue = parseInt(temp.substring(4,6),16); + } else if (/^[\,\/]$/.test(text)){ + this.type = "operator"; + this.value = text; + } else if (/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)){ + this.type = "identifier"; + this.value = text; + } + +} + +PropertyValuePart.prototype = new SyntaxUnit(); +PropertyValuePart.prototype.constructor = PropertyValuePart; +PropertyValuePart.fromToken = function(token){ + return new PropertyValuePart(token.value, token.startLine, token.startCol); +}; +var Pseudos = { + ":first-letter": 1, + ":first-line": 1, + ":before": 1, + ":after": 1 +}; + +Pseudos.ELEMENT = 1; +Pseudos.CLASS = 2; + +Pseudos.isElement = function(pseudo){ + return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT; +}; +function Selector(parts, line, col){ + + SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE); + this.parts = parts; + this.specificity = Specificity.calculate(this); + +} + +Selector.prototype = new SyntaxUnit(); +Selector.prototype.constructor = Selector; +function SelectorPart(elementName, modifiers, text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE); + this.elementName = elementName; + this.modifiers = modifiers; + +} + +SelectorPart.prototype = new SyntaxUnit(); +SelectorPart.prototype.constructor = SelectorPart; +function SelectorSubPart(text, type, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE); + this.type = type; + this.args = []; + +} + +SelectorSubPart.prototype = new SyntaxUnit(); +SelectorSubPart.prototype.constructor = SelectorSubPart; +function Specificity(a, b, c, d){ + this.a = a; + this.b = b; + this.c = c; + this.d = d; +} + +Specificity.prototype = { + constructor: Specificity, + compare: function(other){ + var comps = ["a", "b", "c", "d"], + i, len; + + for (i=0, len=comps.length; i < len; i++){ + if (this[comps[i]] < other[comps[i]]){ + return -1; + } else if (this[comps[i]] > other[comps[i]]){ + return 1; + } + } + + return 0; + }, + valueOf: function(){ + return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d; + }, + toString: function(){ + return this.a + "," + this.b + "," + this.c + "," + this.d; + } + +}; +Specificity.calculate = function(selector){ + + var i, len, + part, + b=0, c=0, d=0; + + function updateValues(part){ + + var i, j, len, num, + elementName = part.elementName ? part.elementName.text : "", + modifier; + + if (elementName && elementName.charAt(elementName.length-1) != "*") { + d++; + } + + for (i=0, len=part.modifiers.length; i < len; i++){ + modifier = part.modifiers[i]; + switch(modifier.type){ + case "class": + case "attribute": + c++; + break; + + case "id": + b++; + break; + + case "pseudo": + if (Pseudos.isElement(modifier.text)){ + d++; + } else { + c++; + } + break; + + case "not": + for (j=0, num=modifier.args.length; j < num; j++){ + updateValues(modifier.args[j]); + } + } + } + } + + for (i=0, len=selector.parts.length; i < len; i++){ + part = selector.parts[i]; + + if (part instanceof SelectorPart){ + updateValues(part); + } + } + + return new Specificity(0, b, c, d); +}; + +var h = /^[0-9a-fA-F]$/, + nonascii = /^[\u0080-\uFFFF]$/, + nl = /\n|\r\n|\r|\f/; + + +function isHexDigit(c){ + return c !== null && h.test(c); +} + +function isDigit(c){ + return c !== null && /\d/.test(c); +} + +function isWhitespace(c){ + return c !== null && /\s/.test(c); +} + +function isNewLine(c){ + return c !== null && nl.test(c); +} + +function isNameStart(c){ + return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c)); +} + +function isNameChar(c){ + return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c)); +} + +function isIdentStart(c){ + return c !== null && (isNameStart(c) || /\-\\/.test(c)); +} + +function mix(receiver, supplier){ + for (var prop in supplier){ + if (supplier.hasOwnProperty(prop)){ + receiver[prop] = supplier[prop]; + } + } + return receiver; +} +function TokenStream(input){ + TokenStreamBase.call(this, input, Tokens); +} + +TokenStream.prototype = mix(new TokenStreamBase(), { + _getToken: function(channel){ + + var c, + reader = this._reader, + token = null, + startLine = reader.getLine(), + startCol = reader.getCol(); + + c = reader.read(); + + + while(c){ + switch(c){ + case "/": + + if(reader.peek() == "*"){ + token = this.commentToken(c, startLine, startCol); + } else { + token = this.charToken(c, startLine, startCol); + } + break; + case "|": + case "~": + case "^": + case "$": + case "*": + if(reader.peek() == "="){ + token = this.comparisonToken(c, startLine, startCol); + } else { + token = this.charToken(c, startLine, startCol); + } + break; + case "\"": + case "'": + token = this.stringToken(c, startLine, startCol); + break; + case "#": + if (isNameChar(reader.peek())){ + token = this.hashToken(c, startLine, startCol); + } else { + token = this.charToken(c, startLine, startCol); + } + break; + case ".": + if (isDigit(reader.peek())){ + token = this.numberToken(c, startLine, startCol); + } else { + token = this.charToken(c, startLine, startCol); + } + break; + case "-": + if (reader.peek() == "-"){ //could be closing HTML-style comment + token = this.htmlCommentEndToken(c, startLine, startCol); + } else if (isNameStart(reader.peek())){ + token = this.identOrFunctionToken(c, startLine, startCol); + } else { + token = this.charToken(c, startLine, startCol); + } + break; + case "!": + token = this.importantToken(c, startLine, startCol); + break; + case "@": + token = this.atRuleToken(c, startLine, startCol); + break; + case ":": + token = this.notToken(c, startLine, startCol); + break; + case "<": + token = this.htmlCommentStartToken(c, startLine, startCol); + break; + case "U": + case "u": + if (reader.peek() == "+"){ + token = this.unicodeRangeToken(c, startLine, startCol); + break; + } + default: + if (isDigit(c)){ + token = this.numberToken(c, startLine, startCol); + } else + if (isWhitespace(c)){ + token = this.whitespaceToken(c, startLine, startCol); + } else + if (isIdentStart(c)){ + token = this.identOrFunctionToken(c, startLine, startCol); + } else + { + token = this.charToken(c, startLine, startCol); + } + + + + + + + } + break; + } + + if (!token && c === null){ + token = this.createToken(Tokens.EOF,null,startLine,startCol); + } + + return token; + }, + createToken: function(tt, value, startLine, startCol, options){ + var reader = this._reader; + options = options || {}; + + return { + value: value, + type: tt, + channel: options.channel, + endChar: options.endChar, + hide: options.hide || false, + startLine: startLine, + startCol: startCol, + endLine: reader.getLine(), + endCol: reader.getCol() + }; + }, + atRuleToken: function(first, startLine, startCol){ + var rule = first, + reader = this._reader, + tt = Tokens.CHAR, + valid = false, + ident, + c; + reader.mark(); + ident = this.readName(); + rule = first + ident; + tt = Tokens.type(rule.toLowerCase()); + if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){ + if (rule.length > 1){ + tt = Tokens.UNKNOWN_SYM; + } else { + tt = Tokens.CHAR; + rule = first; + reader.reset(); + } + } + + return this.createToken(tt, rule, startLine, startCol); + }, + charToken: function(c, startLine, startCol){ + var tt = Tokens.type(c); + var opts = {}; + + if (tt == -1){ + tt = Tokens.CHAR; + } else { + opts.endChar = Tokens[tt].endChar; + } + + return this.createToken(tt, c, startLine, startCol, opts); + }, + commentToken: function(first, startLine, startCol){ + var reader = this._reader, + comment = this.readComment(first); + + return this.createToken(Tokens.COMMENT, comment, startLine, startCol); + }, + comparisonToken: function(c, startLine, startCol){ + var reader = this._reader, + comparison = c + reader.read(), + tt = Tokens.type(comparison) || Tokens.CHAR; + + return this.createToken(tt, comparison, startLine, startCol); + }, + hashToken: function(first, startLine, startCol){ + var reader = this._reader, + name = this.readName(first); + + return this.createToken(Tokens.HASH, name, startLine, startCol); + }, + htmlCommentStartToken: function(first, startLine, startCol){ + var reader = this._reader, + text = first; + + reader.mark(); + text += reader.readCount(3); + + if (text == "<!--"){ + return this.createToken(Tokens.CDO, text, startLine, startCol); + } else { + reader.reset(); + return this.charToken(first, startLine, startCol); + } + }, + htmlCommentEndToken: function(first, startLine, startCol){ + var reader = this._reader, + text = first; + + reader.mark(); + text += reader.readCount(2); + + if (text == "-->"){ + return this.createToken(Tokens.CDC, text, startLine, startCol); + } else { + reader.reset(); + return this.charToken(first, startLine, startCol); + } + }, + identOrFunctionToken: function(first, startLine, startCol){ + var reader = this._reader, + ident = this.readName(first), + tt = Tokens.IDENT; + if (reader.peek() == "("){ + ident += reader.read(); + if (ident.toLowerCase() == "url("){ + tt = Tokens.URI; + ident = this.readURI(ident); + if (ident.toLowerCase() == "url("){ + tt = Tokens.FUNCTION; + } + } else { + tt = Tokens.FUNCTION; + } + } else if (reader.peek() == ":"){ //might be an IE function + if (ident.toLowerCase() == "progid"){ + ident += reader.readTo("("); + tt = Tokens.IE_FUNCTION; + } + } + + return this.createToken(tt, ident, startLine, startCol); + }, + importantToken: function(first, startLine, startCol){ + var reader = this._reader, + important = first, + tt = Tokens.CHAR, + temp, + c; + + reader.mark(); + c = reader.read(); + + while(c){ + if (c == "/"){ + if (reader.peek() != "*"){ + break; + } else { + temp = this.readComment(c); + if (temp === ""){ //broken! + break; + } + } + } else if (isWhitespace(c)){ + important += c + this.readWhitespace(); + } else if (/i/i.test(c)){ + temp = reader.readCount(8); + if (/mportant/i.test(temp)){ + important += c + temp; + tt = Tokens.IMPORTANT_SYM; + + } + break; //we're done + } else { + break; + } + + c = reader.read(); + } + + if (tt == Tokens.CHAR){ + reader.reset(); + return this.charToken(first, startLine, startCol); + } else { + return this.createToken(tt, important, startLine, startCol); + } + + + }, + notToken: function(first, startLine, startCol){ + var reader = this._reader, + text = first; + + reader.mark(); + text += reader.readCount(4); + + if (text.toLowerCase() == ":not("){ + return this.createToken(Tokens.NOT, text, startLine, startCol); + } else { + reader.reset(); + return this.charToken(first, startLine, startCol); + } + }, + numberToken: function(first, startLine, startCol){ + var reader = this._reader, + value = this.readNumber(first), + ident, + tt = Tokens.NUMBER, + c = reader.peek(); + + if (isIdentStart(c)){ + ident = this.readName(reader.read()); + value += ident; + + if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){ + tt = Tokens.LENGTH; + } else if (/^deg|^rad$|^grad$/i.test(ident)){ + tt = Tokens.ANGLE; + } else if (/^ms$|^s$/i.test(ident)){ + tt = Tokens.TIME; + } else if (/^hz$|^khz$/i.test(ident)){ + tt = Tokens.FREQ; + } else if (/^dpi$|^dpcm$/i.test(ident)){ + tt = Tokens.RESOLUTION; + } else { + tt = Tokens.DIMENSION; + } + + } else if (c == "%"){ + value += reader.read(); + tt = Tokens.PERCENTAGE; + } + + return this.createToken(tt, value, startLine, startCol); + }, + stringToken: function(first, startLine, startCol){ + var delim = first, + string = first, + reader = this._reader, + prev = first, + tt = Tokens.STRING, + c = reader.read(); + + while(c){ + string += c; + if (c == delim && prev != "\\"){ + break; + } + if (isNewLine(reader.peek()) && c != "\\"){ + tt = Tokens.INVALID; + break; + } + prev = c; + c = reader.read(); + } + if (c === null){ + tt = Tokens.INVALID; + } + + return this.createToken(tt, string, startLine, startCol); + }, + + unicodeRangeToken: function(first, startLine, startCol){ + var reader = this._reader, + value = first, + temp, + tt = Tokens.CHAR; + if (reader.peek() == "+"){ + reader.mark(); + value += reader.read(); + value += this.readUnicodeRangePart(true); + if (value.length == 2){ + reader.reset(); + } else { + + tt = Tokens.UNICODE_RANGE; + if (value.indexOf("?") == -1){ + + if (reader.peek() == "-"){ + reader.mark(); + temp = reader.read(); + temp += this.readUnicodeRangePart(false); + if (temp.length == 1){ + reader.reset(); + } else { + value += temp; + } + } + + } + } + } + + return this.createToken(tt, value, startLine, startCol); + }, + whitespaceToken: function(first, startLine, startCol){ + var reader = this._reader, + value = first + this.readWhitespace(); + return this.createToken(Tokens.S, value, startLine, startCol); + }, + + readUnicodeRangePart: function(allowQuestionMark){ + var reader = this._reader, + part = "", + c = reader.peek(); + while(isHexDigit(c) && part.length < 6){ + reader.read(); + part += c; + c = reader.peek(); + } + if (allowQuestionMark){ + while(c == "?" && part.length < 6){ + reader.read(); + part += c; + c = reader.peek(); + } + } + + return part; + }, + + readWhitespace: function(){ + var reader = this._reader, + whitespace = "", + c = reader.peek(); + + while(isWhitespace(c)){ + reader.read(); + whitespace += c; + c = reader.peek(); + } + + return whitespace; + }, + readNumber: function(first){ + var reader = this._reader, + number = first, + hasDot = (first == "."), + c = reader.peek(); + + + while(c){ + if (isDigit(c)){ + number += reader.read(); + } else if (c == "."){ + if (hasDot){ + break; + } else { + hasDot = true; + number += reader.read(); + } + } else { + break; + } + + c = reader.peek(); + } + + return number; + }, + readString: function(){ + var reader = this._reader, + delim = reader.read(), + string = delim, + prev = delim, + c = reader.peek(); + + while(c){ + c = reader.read(); + string += c; + if (c == delim && prev != "\\"){ + break; + } + if (isNewLine(reader.peek()) && c != "\\"){ + string = ""; + break; + } + prev = c; + c = reader.peek(); + } + if (c === null){ + string = ""; + } + + return string; + }, + readURI: function(first){ + var reader = this._reader, + uri = first, + inner = "", + c = reader.peek(); + + reader.mark(); + while(c && isWhitespace(c)){ + reader.read(); + c = reader.peek(); + } + if (c == "'" || c == "\""){ + inner = this.readString(); + } else { + inner = this.readURL(); + } + + c = reader.peek(); + while(c && isWhitespace(c)){ + reader.read(); + c = reader.peek(); + } + if (inner === "" || c != ")"){ + uri = first; + reader.reset(); + } else { + uri += inner + reader.read(); + } + + return uri; + }, + readURL: function(){ + var reader = this._reader, + url = "", + c = reader.peek(); + while (/^[!#$%&\\*-~]$/.test(c)){ + url += reader.read(); + c = reader.peek(); + } + + return url; + + }, + readName: function(first){ + var reader = this._reader, + ident = first || "", + c = reader.peek(); + + while(true){ + if (c == "\\"){ + ident += this.readEscape(reader.read()); + c = reader.peek(); + } else if(c && isNameChar(c)){ + ident += reader.read(); + c = reader.peek(); + } else { + break; + } + } + + return ident; + }, + + readEscape: function(first){ + var reader = this._reader, + cssEscape = first || "", + i = 0, + c = reader.peek(); + + if (isHexDigit(c)){ + do { + cssEscape += reader.read(); + c = reader.peek(); + } while(c && isHexDigit(c) && ++i < 6); + } + + if (cssEscape.length == 3 && /\s/.test(c) || + cssEscape.length == 7 || cssEscape.length == 1){ + reader.read(); + } else { + c = ""; + } + + return cssEscape + c; + }, + + readComment: function(first){ + var reader = this._reader, + comment = first || "", + c = reader.read(); + + if (c == "*"){ + while(c){ + comment += c; + if (comment.length > 2 && c == "*" && reader.peek() == "/"){ + comment += reader.read(); + break; + } + + c = reader.read(); + } + + return comment; + } else { + return ""; + } + + } +}); + +var Tokens = [ + { name: "CDO"}, + { name: "CDC"}, + { name: "S", whitespace: true/*, channel: "ws"*/}, + { name: "COMMENT", comment: true, hide: true, channel: "comment" }, + { name: "INCLUDES", text: "~="}, + { name: "DASHMATCH", text: "|="}, + { name: "PREFIXMATCH", text: "^="}, + { name: "SUFFIXMATCH", text: "$="}, + { name: "SUBSTRINGMATCH", text: "*="}, + { name: "STRING"}, + { name: "IDENT"}, + { name: "HASH"}, + { name: "IMPORT_SYM", text: "@import"}, + { name: "PAGE_SYM", text: "@page"}, + { name: "MEDIA_SYM", text: "@media"}, + { name: "FONT_FACE_SYM", text: "@font-face"}, + { name: "CHARSET_SYM", text: "@charset"}, + { name: "NAMESPACE_SYM", text: "@namespace"}, + { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]}, + { name: "UNKNOWN_SYM" }, + { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] }, + { name: "IMPORTANT_SYM"}, + { name: "LENGTH"}, + { name: "ANGLE"}, + { name: "TIME"}, + { name: "FREQ"}, + { name: "DIMENSION"}, + { name: "PERCENTAGE"}, + { name: "NUMBER"}, + { name: "URI"}, + { name: "FUNCTION"}, + { name: "UNICODE_RANGE"}, + { name: "INVALID"}, + { name: "PLUS", text: "+" }, + { name: "GREATER", text: ">"}, + { name: "COMMA", text: ","}, + { name: "TILDE", text: "~"}, + { name: "NOT"}, + { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"}, + { name: "TOPLEFT_SYM", text: "@top-left"}, + { name: "TOPCENTER_SYM", text: "@top-center"}, + { name: "TOPRIGHT_SYM", text: "@top-right"}, + { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"}, + { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"}, + { name: "BOTTOMLEFT_SYM", text: "@bottom-left"}, + { name: "BOTTOMCENTER_SYM", text: "@bottom-center"}, + { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"}, + { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"}, + { name: "LEFTTOP_SYM", text: "@left-top"}, + { name: "LEFTMIDDLE_SYM", text: "@left-middle"}, + { name: "LEFTBOTTOM_SYM", text: "@left-bottom"}, + { name: "RIGHTTOP_SYM", text: "@right-top"}, + { name: "RIGHTMIDDLE_SYM", text: "@right-middle"}, + { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"}, + { name: "RESOLUTION", state: "media"}, + { name: "IE_FUNCTION" }, + { name: "CHAR" }, + { + name: "PIPE", + text: "|" + }, + { + name: "SLASH", + text: "/" + }, + { + name: "MINUS", + text: "-" + }, + { + name: "STAR", + text: "*" + }, + + { + name: "LBRACE", + endChar: "}", + text: "{" + }, + { + name: "RBRACE", + text: "}" + }, + { + name: "LBRACKET", + endChar: "]", + text: "[" + }, + { + name: "RBRACKET", + text: "]" + }, + { + name: "EQUALS", + text: "=" + }, + { + name: "COLON", + text: ":" + }, + { + name: "SEMICOLON", + text: ";" + }, + + { + name: "LPAREN", + endChar: ")", + text: "(" + }, + { + name: "RPAREN", + text: ")" + }, + { + name: "DOT", + text: "." + } +]; + +(function(){ + + var nameMap = [], + typeMap = {}; + + Tokens.UNKNOWN = -1; + Tokens.unshift({name:"EOF"}); + for (var i=0, len = Tokens.length; i < len; i++){ + nameMap.push(Tokens[i].name); + Tokens[Tokens[i].name] = i; + if (Tokens[i].text){ + if (Tokens[i].text instanceof Array){ + for (var j=0; j < Tokens[i].text.length; j++){ + typeMap[Tokens[i].text[j]] = i; + } + } else { + typeMap[Tokens[i].text] = i; + } + } + } + + Tokens.name = function(tt){ + return nameMap[tt]; + }; + + Tokens.type = function(c){ + return typeMap[c] || -1; + }; + +})(); +var Validation = { + + validate: function(property, value){ + var name = property.toString().toLowerCase(), + parts = value.parts, + expression = new PropertyValueIterator(value), + spec = Properties[name], + part, + valid, + j, count, + msg, + types, + last, + literals, + max, multi, group; + + if (!spec) { + if (name.indexOf("-") !== 0){ //vendor prefixed are ok + throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col); + } + } else if (typeof spec != "number"){ + if (typeof spec == "string"){ + if (spec.indexOf("||") > -1) { + this.groupProperty(spec, expression); + } else { + this.singleProperty(spec, expression, 1); + } + + } else if (spec.multi) { + this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity); + } else if (typeof spec == "function") { + spec(expression); + } + + } + + }, + + singleProperty: function(types, expression, max, partial) { + + var result = false, + value = expression.value, + count = 0, + part; + + while (expression.hasNext() && count < max) { + result = ValidationTypes.isAny(expression, types); + if (!result) { + break; + } + count++; + } + + if (!result) { + if (expression.hasNext() && !expression.isFirst()) { + part = expression.peek(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); + } + } else if (expression.hasNext()) { + part = expression.next(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } + + }, + + multiProperty: function (types, expression, comma, max) { + + var result = false, + value = expression.value, + count = 0, + sep = false, + part; + + while(expression.hasNext() && !result && count < max) { + if (ValidationTypes.isAny(expression, types)) { + count++; + if (!expression.hasNext()) { + result = true; + + } else if (comma) { + if (expression.peek() == ",") { + part = expression.next(); + } else { + break; + } + } + } else { + break; + + } + } + + if (!result) { + if (expression.hasNext() && !expression.isFirst()) { + part = expression.peek(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + part = expression.previous(); + if (comma && part == ",") { + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); + } + } + + } else if (expression.hasNext()) { + part = expression.next(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } + + }, + + groupProperty: function (types, expression, comma) { + + var result = false, + value = expression.value, + typeCount = types.split("||").length, + groups = { count: 0 }, + partial = false, + name, + part; + + while(expression.hasNext() && !result) { + name = ValidationTypes.isAnyOfGroup(expression, types); + if (name) { + if (groups[name]) { + break; + } else { + groups[name] = 1; + groups.count++; + partial = true; + + if (groups.count == typeCount || !expression.hasNext()) { + result = true; + } + } + } else { + break; + } + } + + if (!result) { + if (partial && expression.hasNext()) { + part = expression.peek(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } else { + throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col); + } + } else if (expression.hasNext()) { + part = expression.next(); + throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col); + } + } + + + +}; +function ValidationError(message, line, col){ + this.col = col; + this.line = line; + this.message = message; + +} +ValidationError.prototype = new Error(); +var ValidationTypes = { + + isLiteral: function (part, literals) { + var text = part.text.toString().toLowerCase(), + args = literals.split(" | "), + i, len, found = false; + + for (i=0,len=args.length; i < len && !found; i++){ + if (text == args[i].toLowerCase()){ + found = true; + } + } + + return found; + }, + + isSimple: function(type) { + return !!this.simple[type]; + }, + + isComplex: function(type) { + return !!this.complex[type]; + }, + isAny: function (expression, types) { + var args = types.split(" | "), + i, len, found = false; + + for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){ + found = this.isType(expression, args[i]); + } + + return found; + }, + isAnyOfGroup: function(expression, types) { + var args = types.split(" || "), + i, len, found = false; + + for (i=0,len=args.length; i < len && !found; i++){ + found = this.isType(expression, args[i]); + } + + return found ? args[i-1] : false; + }, + isType: function (expression, type) { + var part = expression.peek(), + result = false; + + if (type.charAt(0) != "<") { + result = this.isLiteral(part, type); + if (result) { + expression.next(); + } + } else if (this.simple[type]) { + result = this.simple[type](part); + if (result) { + expression.next(); + } + } else { + result = this.complex[type](expression); + } + + return result; + }, + + + + simple: { + + "<absolute-size>": function(part){ + return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large"); + }, + + "<attachment>": function(part){ + return ValidationTypes.isLiteral(part, "scroll | fixed | local"); + }, + + "<attr>": function(part){ + return part.type == "function" && part.name == "attr"; + }, + + "<bg-image>": function(part){ + return this["<image>"](part) || this["<gradient>"](part) || part == "none"; + }, + + "<gradient>": function(part) { + return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part); + }, + + "<box>": function(part){ + return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box"); + }, + + "<content>": function(part){ + return part.type == "function" && part.name == "content"; + }, + + "<relative-size>": function(part){ + return ValidationTypes.isLiteral(part, "smaller | larger"); + }, + "<ident>": function(part){ + return part.type == "identifier"; + }, + + "<length>": function(part){ + if (part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)){ + return true; + }else{ + return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0"; + } + }, + + "<color>": function(part){ + return part.type == "color" || part == "transparent"; + }, + + "<number>": function(part){ + return part.type == "number" || this["<integer>"](part); + }, + + "<integer>": function(part){ + return part.type == "integer"; + }, + + "<line>": function(part){ + return part.type == "integer"; + }, + + "<angle>": function(part){ + return part.type == "angle"; + }, + + "<uri>": function(part){ + return part.type == "uri"; + }, + + "<image>": function(part){ + return this["<uri>"](part); + }, + + "<percentage>": function(part){ + return part.type == "percentage" || part == "0"; + }, + + "<border-width>": function(part){ + return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick"); + }, + + "<border-style>": function(part){ + return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset"); + }, + + "<content-sizing>": function(part){ // http://www.w3.org/TR/css3-sizing/#width-height-keywords + return ValidationTypes.isLiteral(part, "fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content"); + }, + + "<margin-width>": function(part){ + return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto"); + }, + + "<padding-width>": function(part){ + return this["<length>"](part) || this["<percentage>"](part); + }, + + "<shape>": function(part){ + return part.type == "function" && (part.name == "rect" || part.name == "inset-rect"); + }, + + "<time>": function(part) { + return part.type == "time"; + }, + + "<flex-grow>": function(part){ + return this["<number>"](part); + }, + + "<flex-shrink>": function(part){ + return this["<number>"](part); + }, + + "<width>": function(part){ + return this["<margin-width>"](part); + }, + + "<flex-basis>": function(part){ + return this["<width>"](part); + }, + + "<flex-direction>": function(part){ + return ValidationTypes.isLiteral(part, "row | row-reverse | column | column-reverse"); + }, + + "<flex-wrap>": function(part){ + return ValidationTypes.isLiteral(part, "nowrap | wrap | wrap-reverse"); + } + }, + + complex: { + + "<bg-position>": function(expression){ + var types = this, + result = false, + numeric = "<percentage> | <length>", + xDir = "left | right", + yDir = "top | bottom", + count = 0, + hasNext = function() { + return expression.hasNext() && expression.peek() != ","; + }; + + while (expression.peek(count) && expression.peek(count) != ",") { + count++; + } + + if (count < 3) { + if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) { + result = true; + ValidationTypes.isAny(expression, yDir + " | center | " + numeric); + } else if (ValidationTypes.isAny(expression, yDir)) { + result = true; + ValidationTypes.isAny(expression, xDir + " | center"); + } + } else { + if (ValidationTypes.isAny(expression, xDir)) { + if (ValidationTypes.isAny(expression, yDir)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } else if (ValidationTypes.isAny(expression, numeric)) { + if (ValidationTypes.isAny(expression, yDir)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } else if (ValidationTypes.isAny(expression, "center")) { + result = true; + } + } + } else if (ValidationTypes.isAny(expression, yDir)) { + if (ValidationTypes.isAny(expression, xDir)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } else if (ValidationTypes.isAny(expression, numeric)) { + if (ValidationTypes.isAny(expression, xDir)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } else if (ValidationTypes.isAny(expression, "center")) { + result = true; + } + } + } else if (ValidationTypes.isAny(expression, "center")) { + if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } + } + } + + return result; + }, + + "<bg-size>": function(expression){ + var types = this, + result = false, + numeric = "<percentage> | <length> | auto", + part, + i, len; + + if (ValidationTypes.isAny(expression, "cover | contain")) { + result = true; + } else if (ValidationTypes.isAny(expression, numeric)) { + result = true; + ValidationTypes.isAny(expression, numeric); + } + + return result; + }, + + "<repeat-style>": function(expression){ + var result = false, + values = "repeat | space | round | no-repeat", + part; + + if (expression.hasNext()){ + part = expression.next(); + + if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) { + result = true; + } else if (ValidationTypes.isLiteral(part, values)) { + result = true; + + if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) { + expression.next(); + } + } + } + + return result; + + }, + + "<shadow>": function(expression) { + var result = false, + count = 0, + inset = false, + color = false, + part; + + if (expression.hasNext()) { + + if (ValidationTypes.isAny(expression, "inset")){ + inset = true; + } + + if (ValidationTypes.isAny(expression, "<color>")) { + color = true; + } + + while (ValidationTypes.isAny(expression, "<length>") && count < 4) { + count++; + } + + + if (expression.hasNext()) { + if (!color) { + ValidationTypes.isAny(expression, "<color>"); + } + + if (!inset) { + ValidationTypes.isAny(expression, "inset"); + } + + } + + result = (count >= 2 && count <= 4); + + } + + return result; + }, + + "<x-one-radius>": function(expression) { + var result = false, + simple = "<length> | <percentage> | inherit"; + + if (ValidationTypes.isAny(expression, simple)){ + result = true; + ValidationTypes.isAny(expression, simple); + } + + return result; + }, + + "<flex>": function(expression) { + var part, + result = false; + if (ValidationTypes.isAny(expression, "none | inherit")) { + result = true; + } else { + if (ValidationTypes.isType(expression, "<flex-grow>")) { + if (expression.peek()) { + if (ValidationTypes.isType(expression, "<flex-shrink>")) { + if (expression.peek()) { + result = ValidationTypes.isType(expression, "<flex-basis>"); + } else { + result = true; + } + } else if (ValidationTypes.isType(expression, "<flex-basis>")) { + result = expression.peek() === null; + } + } else { + result = true; + } + } else if (ValidationTypes.isType(expression, "<flex-basis>")) { + result = true; + } + } + + if (!result) { + part = expression.peek(); + throw new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression.value.text + "'.", part.line, part.col); + } + + return result; + } + } +}; + +parserlib.css = { +Colors :Colors, +Combinator :Combinator, +Parser :Parser, +PropertyName :PropertyName, +PropertyValue :PropertyValue, +PropertyValuePart :PropertyValuePart, +MediaFeature :MediaFeature, +MediaQuery :MediaQuery, +Selector :Selector, +SelectorPart :SelectorPart, +SelectorSubPart :SelectorSubPart, +Specificity :Specificity, +TokenStream :TokenStream, +Tokens :Tokens, +ValidationError :ValidationError +}; +})(); + +(function(){ +for(var prop in parserlib){ +exports[prop] = parserlib[prop]; +} +})(); + + +function objectToString(o) { + return Object.prototype.toString.call(o); +} +var util = { + isArray: function (ar) { + return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]'); + }, + isDate: function (d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; + }, + isRegExp: function (re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; + }, + getRegExpFlags: function (re) { + var flags = ''; + re.global && (flags += 'g'); + re.ignoreCase && (flags += 'i'); + re.multiline && (flags += 'm'); + return flags; + } +}; + + +if (typeof module === 'object') + module.exports = clone; + +function clone(parent, circular, depth, prototype) { + var allParents = []; + var allChildren = []; + + var useBuffer = typeof Buffer != 'undefined'; + + if (typeof circular == 'undefined') + circular = true; + + if (typeof depth == 'undefined') + depth = Infinity; + function _clone(parent, depth) { + if (parent === null) + return null; + + if (depth == 0) + return parent; + + var child; + if (typeof parent != 'object') { + return parent; + } + + if (util.isArray(parent)) { + child = []; + } else if (util.isRegExp(parent)) { + child = new RegExp(parent.source, util.getRegExpFlags(parent)); + if (parent.lastIndex) child.lastIndex = parent.lastIndex; + } else if (util.isDate(parent)) { + child = new Date(parent.getTime()); + } else if (useBuffer && Buffer.isBuffer(parent)) { + child = new Buffer(parent.length); + parent.copy(child); + return child; + } else { + if (typeof prototype == 'undefined') child = Object.create(Object.getPrototypeOf(parent)); + else child = Object.create(prototype); + } + + if (circular) { + var index = allParents.indexOf(parent); + + if (index != -1) { + return allChildren[index]; + } + allParents.push(parent); + allChildren.push(child); + } + + for (var i in parent) { + child[i] = _clone(parent[i], depth - 1); + } + + return child; + } + + return _clone(parent, depth); +} +clone.clonePrototype = function(parent) { + if (parent === null) + return null; + + var c = function () {}; + c.prototype = parent; + return new c(); +}; + +var CSSLint = (function(){ + + var rules = [], + formatters = [], + embeddedRuleset = /\/\*csslint([^\*]*)\*\//, + api = new parserlib.util.EventTarget(); + + api.version = "@VERSION@"; + api.addRule = function(rule){ + rules.push(rule); + rules[rule.id] = rule; + }; + api.clearRules = function(){ + rules = []; + }; + api.getRules = function(){ + return [].concat(rules).sort(function(a,b){ + return a.id > b.id ? 1 : 0; + }); + }; + api.getRuleset = function() { + var ruleset = {}, + i = 0, + len = rules.length; + + while (i < len){ + ruleset[rules[i++].id] = 1; //by default, everything is a warning + } + + return ruleset; + }; + function applyEmbeddedRuleset(text, ruleset){ + var valueMap, + embedded = text && text.match(embeddedRuleset), + rules = embedded && embedded[1]; + + if (rules) { + valueMap = { + "true": 2, // true is error + "": 1, // blank is warning + "false": 0, // false is ignore + + "2": 2, // explicit error + "1": 1, // explicit warning + "0": 0 // explicit ignore + }; + + rules.toLowerCase().split(",").forEach(function(rule){ + var pair = rule.split(":"), + property = pair[0] || "", + value = pair[1] || ""; + + ruleset[property.trim()] = valueMap[value.trim()]; + }); + } + + return ruleset; + } + api.addFormatter = function(formatter) { + formatters[formatter.id] = formatter; + }; + api.getFormatter = function(formatId){ + return formatters[formatId]; + }; + api.format = function(results, filename, formatId, options) { + var formatter = this.getFormatter(formatId), + result = null; + + if (formatter){ + result = formatter.startFormat(); + result += formatter.formatResults(results, filename, options || {}); + result += formatter.endFormat(); + } + + return result; + }; + api.hasFormat = function(formatId){ + return formatters.hasOwnProperty(formatId); + }; + api.verify = function(text, ruleset){ + + var i = 0, + reporter, + lines, + report, + parser = new parserlib.css.Parser({ starHack: true, ieFilters: true, + underscoreHack: true, strict: false }); + lines = text.replace(/\n\r?/g, "$split$").split("$split$"); + + if (!ruleset){ + ruleset = this.getRuleset(); + } + + if (embeddedRuleset.test(text)){ + ruleset = clone(ruleset); + ruleset = applyEmbeddedRuleset(text, ruleset); + } + + reporter = new Reporter(lines, ruleset); + + ruleset.errors = 2; //always report parsing errors as errors + for (i in ruleset){ + if(ruleset.hasOwnProperty(i) && ruleset[i]){ + if (rules[i]){ + rules[i].init(parser, reporter); + } + } + } + try { + parser.parse(text); + } catch (ex) { + reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {}); + } + + report = { + messages : reporter.messages, + stats : reporter.stats, + ruleset : reporter.ruleset + }; + report.messages.sort(function (a, b){ + if (a.rollup && !b.rollup){ + return 1; + } else if (!a.rollup && b.rollup){ + return -1; + } else { + return a.line - b.line; + } + }); + + return report; + }; + + return api; + +})(); +function Reporter(lines, ruleset){ + this.messages = []; + this.stats = []; + this.lines = lines; + this.ruleset = ruleset; +} + +Reporter.prototype = { + constructor: Reporter, + error: function(message, line, col, rule){ + this.messages.push({ + type : "error", + line : line, + col : col, + message : message, + evidence: this.lines[line-1], + rule : rule || {} + }); + }, + warn: function(message, line, col, rule){ + this.report(message, line, col, rule); + }, + report: function(message, line, col, rule){ + this.messages.push({ + type : this.ruleset[rule.id] === 2 ? "error" : "warning", + line : line, + col : col, + message : message, + evidence: this.lines[line-1], + rule : rule + }); + }, + info: function(message, line, col, rule){ + this.messages.push({ + type : "info", + line : line, + col : col, + message : message, + evidence: this.lines[line-1], + rule : rule + }); + }, + rollupError: function(message, rule){ + this.messages.push({ + type : "error", + rollup : true, + message : message, + rule : rule + }); + }, + rollupWarn: function(message, rule){ + this.messages.push({ + type : "warning", + rollup : true, + message : message, + rule : rule + }); + }, + stat: function(name, value){ + this.stats[name] = value; + } +}; +CSSLint._Reporter = Reporter; +CSSLint.Util = { + mix: function(receiver, supplier){ + var prop; + + for (prop in supplier){ + if (supplier.hasOwnProperty(prop)){ + receiver[prop] = supplier[prop]; + } + } + + return prop; + }, + indexOf: function(values, value){ + if (values.indexOf){ + return values.indexOf(value); + } else { + for (var i=0, len=values.length; i < len; i++){ + if (values[i] === value){ + return i; + } + } + return -1; + } + }, + forEach: function(values, func) { + if (values.forEach){ + return values.forEach(func); + } else { + for (var i=0, len=values.length; i < len; i++){ + func(values[i], i, values); + } + } + } +}; + +CSSLint.addRule({ + id: "adjoining-classes", + name: "Disallow adjoining classes", + desc: "Don't use adjoining classes.", + browsers: "IE6", + init: function(parser, reporter){ + var rule = this; + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + modifier, + classCount, + i, j, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + for (j=0; j < selector.parts.length; j++){ + part = selector.parts[j]; + if (part.type === parser.SELECTOR_PART_TYPE){ + classCount = 0; + for (k=0; k < part.modifiers.length; k++){ + modifier = part.modifiers[k]; + if (modifier.type === "class"){ + classCount++; + } + if (classCount > 1){ + reporter.report("Don't use adjoining classes.", part.line, part.col, rule); + } + } + } + } + } + }); + } + +}); +CSSLint.addRule({ + id: "box-model", + name: "Beware of broken box size", + desc: "Don't use width or height when using padding or border.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + widthProperties = { + border: 1, + "border-left": 1, + "border-right": 1, + padding: 1, + "padding-left": 1, + "padding-right": 1 + }, + heightProperties = { + border: 1, + "border-bottom": 1, + "border-top": 1, + padding: 1, + "padding-bottom": 1, + "padding-top": 1 + }, + properties, + boxSizing = false; + + function startRule(){ + properties = {}; + boxSizing = false; + } + + function endRule(){ + var prop, value; + + if (!boxSizing) { + if (properties.height){ + for (prop in heightProperties){ + if (heightProperties.hasOwnProperty(prop) && properties[prop]){ + value = properties[prop].value; + if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)){ + reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule); + } + } + } + } + + if (properties.width){ + for (prop in widthProperties){ + if (widthProperties.hasOwnProperty(prop) && properties[prop]){ + value = properties[prop].value; + + if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)){ + reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule); + } + } + } + } + } + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var name = event.property.text.toLowerCase(); + + if (heightProperties[name] || widthProperties[name]){ + if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")){ + properties[name] = { line: event.property.line, col: event.property.col, value: event.value }; + } + } else { + if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){ + properties[name] = 1; + } else if (name === "box-sizing") { + boxSizing = true; + } + } + + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + parser.addListener("endpage", endRule); + parser.addListener("endpagemargin", endRule); + parser.addListener("endkeyframerule", endRule); + } + +}); + +CSSLint.addRule({ + id: "box-sizing", + name: "Disallow use of box-sizing", + desc: "The box-sizing properties isn't supported in IE6 and IE7.", + browsers: "IE6, IE7", + tags: ["Compatibility"], + init: function(parser, reporter){ + var rule = this; + + parser.addListener("property", function(event){ + var name = event.property.text.toLowerCase(); + + if (name === "box-sizing"){ + reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "bulletproof-font-face", + name: "Use the bulletproof @font-face syntax", + desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + fontFaceRule = false, + firstSrc = true, + ruleFailed = false, + line, col; + parser.addListener("startfontface", function(){ + fontFaceRule = true; + }); + + parser.addListener("property", function(event){ + if (!fontFaceRule) { + return; + } + + var propertyName = event.property.toString().toLowerCase(), + value = event.value.toString(); + line = event.line; + col = event.col; + if (propertyName === "src") { + var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i; + if (!value.match(regex) && firstSrc) { + ruleFailed = true; + firstSrc = false; + } else if (value.match(regex) && !firstSrc) { + ruleFailed = false; + } + } + + + }); + parser.addListener("endfontface", function(){ + fontFaceRule = false; + + if (ruleFailed) { + reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule); + } + }); + } +}); + +CSSLint.addRule({ + id: "compatible-vendor-prefixes", + name: "Require compatible vendor prefixes", + desc: "Include all compatible vendor prefixes to reach a wider range of users.", + browsers: "All", + init: function (parser, reporter) { + var rule = this, + compatiblePrefixes, + properties, + prop, + variations, + prefixed, + i, + len, + inKeyFrame = false, + arrayPush = Array.prototype.push, + applyTo = []; + compatiblePrefixes = { + "animation" : "webkit moz", + "animation-delay" : "webkit moz", + "animation-direction" : "webkit moz", + "animation-duration" : "webkit moz", + "animation-fill-mode" : "webkit moz", + "animation-iteration-count" : "webkit moz", + "animation-name" : "webkit moz", + "animation-play-state" : "webkit moz", + "animation-timing-function" : "webkit moz", + "appearance" : "webkit moz", + "border-end" : "webkit moz", + "border-end-color" : "webkit moz", + "border-end-style" : "webkit moz", + "border-end-width" : "webkit moz", + "border-image" : "webkit moz o", + "border-radius" : "webkit", + "border-start" : "webkit moz", + "border-start-color" : "webkit moz", + "border-start-style" : "webkit moz", + "border-start-width" : "webkit moz", + "box-align" : "webkit moz ms", + "box-direction" : "webkit moz ms", + "box-flex" : "webkit moz ms", + "box-lines" : "webkit ms", + "box-ordinal-group" : "webkit moz ms", + "box-orient" : "webkit moz ms", + "box-pack" : "webkit moz ms", + "box-sizing" : "webkit moz", + "box-shadow" : "webkit moz", + "column-count" : "webkit moz ms", + "column-gap" : "webkit moz ms", + "column-rule" : "webkit moz ms", + "column-rule-color" : "webkit moz ms", + "column-rule-style" : "webkit moz ms", + "column-rule-width" : "webkit moz ms", + "column-width" : "webkit moz ms", + "hyphens" : "epub moz", + "line-break" : "webkit ms", + "margin-end" : "webkit moz", + "margin-start" : "webkit moz", + "marquee-speed" : "webkit wap", + "marquee-style" : "webkit wap", + "padding-end" : "webkit moz", + "padding-start" : "webkit moz", + "tab-size" : "moz o", + "text-size-adjust" : "webkit ms", + "transform" : "webkit moz ms o", + "transform-origin" : "webkit moz ms o", + "transition" : "webkit moz o", + "transition-delay" : "webkit moz o", + "transition-duration" : "webkit moz o", + "transition-property" : "webkit moz o", + "transition-timing-function" : "webkit moz o", + "user-modify" : "webkit moz", + "user-select" : "webkit moz ms", + "word-break" : "epub ms", + "writing-mode" : "epub ms" + }; + + + for (prop in compatiblePrefixes) { + if (compatiblePrefixes.hasOwnProperty(prop)) { + variations = []; + prefixed = compatiblePrefixes[prop].split(" "); + for (i = 0, len = prefixed.length; i < len; i++) { + variations.push("-" + prefixed[i] + "-" + prop); + } + compatiblePrefixes[prop] = variations; + arrayPush.apply(applyTo, variations); + } + } + + parser.addListener("startrule", function () { + properties = []; + }); + + parser.addListener("startkeyframes", function (event) { + inKeyFrame = event.prefix || true; + }); + + parser.addListener("endkeyframes", function () { + inKeyFrame = false; + }); + + parser.addListener("property", function (event) { + var name = event.property; + if (CSSLint.Util.indexOf(applyTo, name.text) > -1) { + if (!inKeyFrame || typeof inKeyFrame !== "string" || + name.text.indexOf("-" + inKeyFrame + "-") !== 0) { + properties.push(name); + } + } + }); + + parser.addListener("endrule", function () { + if (!properties.length) { + return; + } + + var propertyGroups = {}, + i, + len, + name, + prop, + variations, + value, + full, + actual, + item, + propertiesSpecified; + + for (i = 0, len = properties.length; i < len; i++) { + name = properties[i]; + + for (prop in compatiblePrefixes) { + if (compatiblePrefixes.hasOwnProperty(prop)) { + variations = compatiblePrefixes[prop]; + if (CSSLint.Util.indexOf(variations, name.text) > -1) { + if (!propertyGroups[prop]) { + propertyGroups[prop] = { + full : variations.slice(0), + actual : [], + actualNodes: [] + }; + } + if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) { + propertyGroups[prop].actual.push(name.text); + propertyGroups[prop].actualNodes.push(name); + } + } + } + } + } + + for (prop in propertyGroups) { + if (propertyGroups.hasOwnProperty(prop)) { + value = propertyGroups[prop]; + full = value.full; + actual = value.actual; + + if (full.length > actual.length) { + for (i = 0, len = full.length; i < len; i++) { + item = full[i]; + if (CSSLint.Util.indexOf(actual, item) === -1) { + propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length === 2) ? actual.join(" and ") : actual.join(", "); + reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule); + } + } + + } + } + } + }); + } +}); + +CSSLint.addRule({ + id: "display-property-grouping", + name: "Require properties appropriate for display", + desc: "Certain properties shouldn't be used with certain display property values.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + var propertiesToCheck = { + display: 1, + "float": "none", + height: 1, + width: 1, + margin: 1, + "margin-left": 1, + "margin-right": 1, + "margin-bottom": 1, + "margin-top": 1, + padding: 1, + "padding-left": 1, + "padding-right": 1, + "padding-bottom": 1, + "padding-top": 1, + "vertical-align": 1 + }, + properties; + + function reportProperty(name, display, msg){ + if (properties[name]){ + if (typeof propertiesToCheck[name] !== "string" || properties[name].value.toLowerCase() !== propertiesToCheck[name]){ + reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule); + } + } + } + + function startRule(){ + properties = {}; + } + + function endRule(){ + + var display = properties.display ? properties.display.value : null; + if (display){ + switch(display){ + + case "inline": + reportProperty("height", display); + reportProperty("width", display); + reportProperty("margin", display); + reportProperty("margin-top", display); + reportProperty("margin-bottom", display); + reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug)."); + break; + + case "block": + reportProperty("vertical-align", display); + break; + + case "inline-block": + reportProperty("float", display); + break; + + default: + if (display.indexOf("table-") === 0){ + reportProperty("margin", display); + reportProperty("margin-left", display); + reportProperty("margin-right", display); + reportProperty("margin-top", display); + reportProperty("margin-bottom", display); + reportProperty("float", display); + } + } + } + + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startkeyframerule", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startpage", startRule); + + parser.addListener("property", function(event){ + var name = event.property.text.toLowerCase(); + + if (propertiesToCheck[name]){ + properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col }; + } + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + parser.addListener("endkeyframerule", endRule); + parser.addListener("endpagemargin", endRule); + parser.addListener("endpage", endRule); + + } + +}); + +CSSLint.addRule({ + id: "duplicate-background-images", + name: "Disallow duplicate background images", + desc: "Every background-image should be unique. Use a common class for e.g. sprites.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + stack = {}; + + parser.addListener("property", function(event){ + var name = event.property.text, + value = event.value, + i, len; + + if (name.match(/background/i)) { + for (i=0, len=value.parts.length; i < len; i++) { + if (value.parts[i].type === "uri") { + if (typeof stack[value.parts[i].uri] === "undefined") { + stack[value.parts[i].uri] = event; + } + else { + reporter.report("Background image '" + value.parts[i].uri + "' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule); + } + } + } + } + }); + } +}); + +CSSLint.addRule({ + id: "duplicate-properties", + name: "Disallow duplicate properties", + desc: "Duplicate properties must appear one after the other.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + properties, + lastProperty; + + function startRule(){ + properties = {}; + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var property = event.property, + name = property.text.toLowerCase(); + + if (properties[name] && (lastProperty !== name || properties[name] === event.value.text)){ + reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule); + } + + properties[name] = event.value.text; + lastProperty = name; + + }); + + + } + +}); + +CSSLint.addRule({ + id: "empty-rules", + name: "Disallow empty rules", + desc: "Rules without any properties specified should be removed.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + count = 0; + + parser.addListener("startrule", function(){ + count=0; + }); + + parser.addListener("property", function(){ + count++; + }); + + parser.addListener("endrule", function(event){ + var selectors = event.selectors; + if (count === 0){ + reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "errors", + name: "Parsing Errors", + desc: "This rule looks for recoverable syntax errors.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("error", function(event){ + reporter.error(event.message, event.line, event.col, rule); + }); + + } + +}); + +CSSLint.addRule({ + id: "fallback-colors", + name: "Require fallback colors", + desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.", + browsers: "IE6,IE7,IE8", + init: function(parser, reporter){ + var rule = this, + lastProperty, + propertiesToCheck = { + color: 1, + background: 1, + "border-color": 1, + "border-top-color": 1, + "border-right-color": 1, + "border-bottom-color": 1, + "border-left-color": 1, + border: 1, + "border-top": 1, + "border-right": 1, + "border-bottom": 1, + "border-left": 1, + "background-color": 1 + }, + properties; + + function startRule(){ + properties = {}; + lastProperty = null; + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var property = event.property, + name = property.text.toLowerCase(), + parts = event.value.parts, + i = 0, + colorType = "", + len = parts.length; + + if(propertiesToCheck[name]){ + while(i < len){ + if (parts[i].type === "color"){ + if ("alpha" in parts[i] || "hue" in parts[i]){ + + if (/([^\)]+)\(/.test(parts[i])){ + colorType = RegExp.$1.toUpperCase(); + } + + if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){ + reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule); + } + } else { + event.colorType = "compat"; + } + } + + i++; + } + } + + lastProperty = event; + }); + + } + +}); + +CSSLint.addRule({ + id: "floats", + name: "Disallow too many floats", + desc: "This rule tests if the float property is used too many times", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + var count = 0; + parser.addListener("property", function(event){ + if (event.property.text.toLowerCase() === "float" && + event.value.text.toLowerCase() !== "none"){ + count++; + } + }); + parser.addListener("endstylesheet", function(){ + reporter.stat("floats", count); + if (count >= 10){ + reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "font-faces", + name: "Don't use too many web fonts", + desc: "Too many different web fonts in the same stylesheet.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + count = 0; + + + parser.addListener("startfontface", function(){ + count++; + }); + + parser.addListener("endstylesheet", function(){ + if (count > 5){ + reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "font-sizes", + name: "Disallow too many font sizes", + desc: "Checks the number of font-size declarations.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + count = 0; + parser.addListener("property", function(event){ + if (event.property.toString() === "font-size"){ + count++; + } + }); + parser.addListener("endstylesheet", function(){ + reporter.stat("font-sizes", count); + if (count >= 10){ + reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "gradients", + name: "Require all gradient definitions", + desc: "When using a vendor-prefixed gradient, make sure to use them all.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + gradients; + + parser.addListener("startrule", function(){ + gradients = { + moz: 0, + webkit: 0, + oldWebkit: 0, + o: 0 + }; + }); + + parser.addListener("property", function(event){ + + if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){ + gradients[RegExp.$1] = 1; + } else if (/\-webkit\-gradient/i.test(event.value)){ + gradients.oldWebkit = 1; + } + + }); + + parser.addListener("endrule", function(event){ + var missing = []; + + if (!gradients.moz){ + missing.push("Firefox 3.6+"); + } + + if (!gradients.webkit){ + missing.push("Webkit (Safari 5+, Chrome)"); + } + + if (!gradients.oldWebkit){ + missing.push("Old Webkit (Safari 4+, Chrome)"); + } + + if (!gradients.o){ + missing.push("Opera 11.1+"); + } + + if (missing.length && missing.length < 4){ + reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule); + } + + }); + + } + +}); + +CSSLint.addRule({ + id: "ids", + name: "Disallow IDs in selectors", + desc: "Selectors should not contain IDs.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + modifier, + idCount, + i, j, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + idCount = 0; + + for (j=0; j < selector.parts.length; j++){ + part = selector.parts[j]; + if (part.type === parser.SELECTOR_PART_TYPE){ + for (k=0; k < part.modifiers.length; k++){ + modifier = part.modifiers[k]; + if (modifier.type === "id"){ + idCount++; + } + } + } + } + + if (idCount === 1){ + reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule); + } else if (idCount > 1){ + reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule); + } + } + + }); + } + +}); + +CSSLint.addRule({ + id: "import", + name: "Disallow @import", + desc: "Don't use @import, use <link> instead.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("import", function(event){ + reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule); + }); + + } + +}); + +CSSLint.addRule({ + id: "important", + name: "Disallow !important", + desc: "Be careful when using !important declaration", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + count = 0; + parser.addListener("property", function(event){ + if (event.important === true){ + count++; + reporter.report("Use of !important", event.line, event.col, rule); + } + }); + parser.addListener("endstylesheet", function(){ + reporter.stat("important", count); + if (count >= 10){ + reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "known-properties", + name: "Require use of known properties", + desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("property", function(event){ + if (event.invalid) { + reporter.report(event.invalid.message, event.line, event.col, rule); + } + + }); + } + +}); +CSSLint.addRule({ + id: "order-alphabetical", + name: "Alphabetical order", + desc: "Assure properties are in alphabetical order", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + properties; + + var startRule = function () { + properties = []; + }; + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var name = event.property.text, + lowerCasePrefixLessName = name.toLowerCase().replace(/^-.*?-/, ""); + + properties.push(lowerCasePrefixLessName); + }); + + parser.addListener("endrule", function(event){ + var currentProperties = properties.join(","), + expectedProperties = properties.sort().join(","); + + if (currentProperties !== expectedProperties){ + reporter.report("Rule doesn't have all its properties in alphabetical ordered.", event.line, event.col, rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "outline-none", + name: "Disallow outline: none", + desc: "Use of outline: none or outline: 0 should be limited to :focus rules.", + browsers: "All", + tags: ["Accessibility"], + init: function(parser, reporter){ + var rule = this, + lastRule; + + function startRule(event){ + if (event.selectors){ + lastRule = { + line: event.line, + col: event.col, + selectors: event.selectors, + propCount: 0, + outline: false + }; + } else { + lastRule = null; + } + } + + function endRule(){ + if (lastRule){ + if (lastRule.outline){ + if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") === -1){ + reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule); + } else if (lastRule.propCount === 1) { + reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule); + } + } + } + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var name = event.property.text.toLowerCase(), + value = event.value; + + if (lastRule){ + lastRule.propCount++; + if (name === "outline" && (value.toString() === "none" || value.toString() === "0")){ + lastRule.outline = true; + } + } + + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + parser.addListener("endpage", endRule); + parser.addListener("endpagemargin", endRule); + parser.addListener("endkeyframerule", endRule); + + } + +}); + +CSSLint.addRule({ + id: "overqualified-elements", + name: "Disallow overqualified elements", + desc: "Don't use classes or IDs with elements (a.foo or a#foo).", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + classes = {}; + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + modifier, + i, j, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + + for (j=0; j < selector.parts.length; j++){ + part = selector.parts[j]; + if (part.type === parser.SELECTOR_PART_TYPE){ + for (k=0; k < part.modifiers.length; k++){ + modifier = part.modifiers[k]; + if (part.elementName && modifier.type === "id"){ + reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule); + } else if (modifier.type === "class"){ + + if (!classes[modifier]){ + classes[modifier] = []; + } + classes[modifier].push({ modifier: modifier, part: part }); + } + } + } + } + } + }); + + parser.addListener("endstylesheet", function(){ + + var prop; + for (prop in classes){ + if (classes.hasOwnProperty(prop)){ + if (classes[prop].length === 1 && classes[prop][0].part.elementName){ + 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); + } + } + } + }); + } + +}); + +CSSLint.addRule({ + id: "qualified-headings", + name: "Disallow qualified headings", + desc: "Headings should not be qualified (namespaced).", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + i, j; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + + for (j=0; j < selector.parts.length; j++){ + part = selector.parts[j]; + if (part.type === parser.SELECTOR_PART_TYPE){ + if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){ + reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule); + } + } + } + } + }); + } + +}); + +CSSLint.addRule({ + id: "regex-selectors", + name: "Disallow selectors that look like regexs", + desc: "Selectors that look like regular expressions are slow and should be avoided.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + modifier, + i, j, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + for (j=0; j < selector.parts.length; j++){ + part = selector.parts[j]; + if (part.type === parser.SELECTOR_PART_TYPE){ + for (k=0; k < part.modifiers.length; k++){ + modifier = part.modifiers[k]; + if (modifier.type === "attribute"){ + if (/([\~\|\^\$\*]=)/.test(modifier)){ + reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule); + } + } + + } + } + } + } + }); + } + +}); + +CSSLint.addRule({ + id: "rules-count", + name: "Rules Count", + desc: "Track how many rules there are.", + browsers: "All", + init: function(parser, reporter){ + var count = 0; + parser.addListener("startrule", function(){ + count++; + }); + + parser.addListener("endstylesheet", function(){ + reporter.stat("rule-count", count); + }); + } + +}); + +CSSLint.addRule({ + id: "selector-max-approaching", + name: "Warn when approaching the 4095 selector limit for IE", + desc: "Will warn when selector count is >= 3800 selectors.", + browsers: "IE", + init: function(parser, reporter) { + var rule = this, count = 0; + + parser.addListener("startrule", function(event) { + count += event.selectors.length; + }); + + parser.addListener("endstylesheet", function() { + if (count >= 3800) { + reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "selector-max", + name: "Error when past the 4095 selector limit for IE", + desc: "Will error when selector count is > 4095.", + browsers: "IE", + init: function(parser, reporter){ + var rule = this, count = 0; + + parser.addListener("startrule", function(event) { + count += event.selectors.length; + }); + + parser.addListener("endstylesheet", function() { + if (count > 4095) { + reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "selector-newline", + name: "Disallow new-line characters in selectors", + desc: "New-line characters in selectors are usually a forgotten comma and not a descendant combinator.", + browsers: "All", + init: function(parser, reporter) { + var rule = this; + + function startRule(event) { + var i, len, selector, p, n, pLen, part, part2, type, currentLine, nextLine, + selectors = event.selectors; + + for (i = 0, len = selectors.length; i < len; i++) { + selector = selectors[i]; + for (p = 0, pLen = selector.parts.length; p < pLen; p++) { + for (n = p + 1; n < pLen; n++) { + part = selector.parts[p]; + part2 = selector.parts[n]; + type = part.type; + currentLine = part.line; + nextLine = part2.line; + + if (type === "descendant" && nextLine > currentLine) { + reporter.report("newline character found in selector (forgot a comma?)", currentLine, selectors[i].parts[0].col, rule); + } + } + } + + } + } + + parser.addListener("startrule", startRule); + + } +}); + +CSSLint.addRule({ + id: "shorthand", + name: "Require shorthand properties", + desc: "Use shorthand properties where possible.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + prop, i, len, + propertiesToCheck = {}, + properties, + mapping = { + "margin": [ + "margin-top", + "margin-bottom", + "margin-left", + "margin-right" + ], + "padding": [ + "padding-top", + "padding-bottom", + "padding-left", + "padding-right" + ] + }; + for (prop in mapping){ + if (mapping.hasOwnProperty(prop)){ + for (i=0, len=mapping[prop].length; i < len; i++){ + propertiesToCheck[mapping[prop][i]] = prop; + } + } + } + + function startRule(){ + properties = {}; + } + function endRule(event){ + + var prop, i, len, total; + for (prop in mapping){ + if (mapping.hasOwnProperty(prop)){ + total=0; + + for (i=0, len=mapping[prop].length; i < len; i++){ + total += properties[mapping[prop][i]] ? 1 : 0; + } + + if (total === mapping[prop].length){ + reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule); + } + } + } + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("property", function(event){ + var name = event.property.toString().toLowerCase(); + + if (propertiesToCheck[name]){ + properties[name] = 1; + } + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + + } + +}); + +CSSLint.addRule({ + id: "star-property-hack", + name: "Disallow properties with a star prefix", + desc: "Checks for the star property hack (targets IE6/7)", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + parser.addListener("property", function(event){ + var property = event.property; + + if (property.hack === "*") { + reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule); + } + }); + } +}); + +CSSLint.addRule({ + id: "text-indent", + name: "Disallow negative text-indent", + desc: "Checks for text indent less than -99px", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + textIndent, + direction; + + + function startRule(){ + textIndent = false; + direction = "inherit"; + } + function endRule(){ + if (textIndent && direction !== "ltr"){ + reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule); + } + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("property", function(event){ + var name = event.property.toString().toLowerCase(), + value = event.value; + + if (name === "text-indent" && value.parts[0].value < -99){ + textIndent = event.property; + } else if (name === "direction" && value.toString() === "ltr"){ + direction = "ltr"; + } + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + + } + +}); + +CSSLint.addRule({ + id: "underscore-property-hack", + name: "Disallow properties with an underscore prefix", + desc: "Checks for the underscore property hack (targets IE6)", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + parser.addListener("property", function(event){ + var property = event.property; + + if (property.hack === "_") { + reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule); + } + }); + } +}); + +CSSLint.addRule({ + id: "unique-headings", + name: "Headings should only be defined once", + desc: "Headings should be defined only once.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + var headings = { + h1: 0, + h2: 0, + h3: 0, + h4: 0, + h5: 0, + h6: 0 + }; + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + pseudo, + i, j; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + part = selector.parts[selector.parts.length-1]; + + if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){ + + for (j=0; j < part.modifiers.length; j++){ + if (part.modifiers[j].type === "pseudo"){ + pseudo = true; + break; + } + } + + if (!pseudo){ + headings[RegExp.$1]++; + if (headings[RegExp.$1] > 1) { + reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule); + } + } + } + } + }); + + parser.addListener("endstylesheet", function(){ + var prop, + messages = []; + + for (prop in headings){ + if (headings.hasOwnProperty(prop)){ + if (headings[prop] > 1){ + messages.push(headings[prop] + " " + prop + "s"); + } + } + } + + if (messages.length){ + reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule); + } + }); + } + +}); + +CSSLint.addRule({ + id: "universal-selector", + name: "Disallow universal selector", + desc: "The universal selector (*) is known to be slow.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("startrule", function(event){ + var selectors = event.selectors, + selector, + part, + i; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + + part = selector.parts[selector.parts.length-1]; + if (part.elementName === "*"){ + reporter.report(rule.desc, part.line, part.col, rule); + } + } + }); + } + +}); + +CSSLint.addRule({ + id: "unqualified-attributes", + name: "Disallow unqualified attribute selectors", + desc: "Unqualified attribute selectors are known to be slow.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + + parser.addListener("startrule", function(event){ + + var selectors = event.selectors, + selector, + part, + modifier, + i, k; + + for (i=0; i < selectors.length; i++){ + selector = selectors[i]; + + part = selector.parts[selector.parts.length-1]; + if (part.type === parser.SELECTOR_PART_TYPE){ + for (k=0; k < part.modifiers.length; k++){ + modifier = part.modifiers[k]; + if (modifier.type === "attribute" && (!part.elementName || part.elementName === "*")){ + reporter.report(rule.desc, part.line, part.col, rule); + } + } + } + + } + }); + } + +}); + +CSSLint.addRule({ + id: "vendor-prefix", + name: "Require standard property with vendor prefix", + desc: "When using a vendor-prefixed property, make sure to include the standard one.", + browsers: "All", + init: function(parser, reporter){ + var rule = this, + properties, + num, + propertiesToCheck = { + "-webkit-border-radius": "border-radius", + "-webkit-border-top-left-radius": "border-top-left-radius", + "-webkit-border-top-right-radius": "border-top-right-radius", + "-webkit-border-bottom-left-radius": "border-bottom-left-radius", + "-webkit-border-bottom-right-radius": "border-bottom-right-radius", + + "-o-border-radius": "border-radius", + "-o-border-top-left-radius": "border-top-left-radius", + "-o-border-top-right-radius": "border-top-right-radius", + "-o-border-bottom-left-radius": "border-bottom-left-radius", + "-o-border-bottom-right-radius": "border-bottom-right-radius", + + "-moz-border-radius": "border-radius", + "-moz-border-radius-topleft": "border-top-left-radius", + "-moz-border-radius-topright": "border-top-right-radius", + "-moz-border-radius-bottomleft": "border-bottom-left-radius", + "-moz-border-radius-bottomright": "border-bottom-right-radius", + + "-moz-column-count": "column-count", + "-webkit-column-count": "column-count", + + "-moz-column-gap": "column-gap", + "-webkit-column-gap": "column-gap", + + "-moz-column-rule": "column-rule", + "-webkit-column-rule": "column-rule", + + "-moz-column-rule-style": "column-rule-style", + "-webkit-column-rule-style": "column-rule-style", + + "-moz-column-rule-color": "column-rule-color", + "-webkit-column-rule-color": "column-rule-color", + + "-moz-column-rule-width": "column-rule-width", + "-webkit-column-rule-width": "column-rule-width", + + "-moz-column-width": "column-width", + "-webkit-column-width": "column-width", + + "-webkit-column-span": "column-span", + "-webkit-columns": "columns", + + "-moz-box-shadow": "box-shadow", + "-webkit-box-shadow": "box-shadow", + + "-moz-transform" : "transform", + "-webkit-transform" : "transform", + "-o-transform" : "transform", + "-ms-transform" : "transform", + + "-moz-transform-origin" : "transform-origin", + "-webkit-transform-origin" : "transform-origin", + "-o-transform-origin" : "transform-origin", + "-ms-transform-origin" : "transform-origin", + + "-moz-box-sizing" : "box-sizing", + "-webkit-box-sizing" : "box-sizing" + }; + function startRule(){ + properties = {}; + num = 1; + } + function endRule(){ + var prop, + i, + len, + needed, + actual, + needsStandard = []; + + for (prop in properties){ + if (propertiesToCheck[prop]){ + needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]}); + } + } + + for (i=0, len=needsStandard.length; i < len; i++){ + needed = needsStandard[i].needed; + actual = needsStandard[i].actual; + + if (!properties[needed]){ + reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule); + } else { + if (properties[needed][0].pos < properties[actual][0].pos){ + reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule); + } + } + } + + } + + parser.addListener("startrule", startRule); + parser.addListener("startfontface", startRule); + parser.addListener("startpage", startRule); + parser.addListener("startpagemargin", startRule); + parser.addListener("startkeyframerule", startRule); + + parser.addListener("property", function(event){ + var name = event.property.text.toLowerCase(); + + if (!properties[name]){ + properties[name] = []; + } + + properties[name].push({ name: event.property, value : event.value, pos:num++ }); + }); + + parser.addListener("endrule", endRule); + parser.addListener("endfontface", endRule); + parser.addListener("endpage", endRule); + parser.addListener("endpagemargin", endRule); + parser.addListener("endkeyframerule", endRule); + } + +}); + +CSSLint.addRule({ + id: "zero-units", + name: "Disallow units for 0 values", + desc: "You don't need to specify units when a value is 0.", + browsers: "All", + init: function(parser, reporter){ + var rule = this; + parser.addListener("property", function(event){ + var parts = event.value.parts, + i = 0, + len = parts.length; + + while(i < len){ + if ((parts[i].units || parts[i].type === "percentage") && parts[i].value === 0 && parts[i].type !== "time"){ + reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule); + } + i++; + } + + }); + + } + +}); + +(function() { + var xmlEscape = function(str) { + if (!str || str.constructor !== String) { + return ""; + } + + return str.replace(/[\"&><]/g, function(match) { + switch (match) { + case "\"": + return "&quot;"; + case "&": + return "&amp;"; + case "<": + return "&lt;"; + case ">": + return "&gt;"; + } + }); + }; + + CSSLint.addFormatter({ + id: "checkstyle-xml", + name: "Checkstyle XML format", + startFormat: function(){ + return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>"; + }, + endFormat: function(){ + return "</checkstyle>"; + }, + readError: function(filename, message) { + return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>"; + }, + formatResults: function(results, filename/*, options*/) { + var messages = results.messages, + output = []; + var generateSource = function(rule) { + if (!rule || !("name" in rule)) { + return ""; + } + return "net.csslint." + rule.name.replace(/\s/g,""); + }; + + + + if (messages.length > 0) { + output.push("<file name=\""+filename+"\">"); + CSSLint.Util.forEach(messages, function (message) { + if (!message.rollup) { + output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" + + " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>"); + } + }); + output.push("</file>"); + } + + return output.join(""); + } + }); + +}()); + +CSSLint.addFormatter({ + id: "compact", + name: "Compact, 'porcelain' format", + startFormat: function() { + return ""; + }, + endFormat: function() { + return ""; + }, + formatResults: function(results, filename, options) { + var messages = results.messages, + output = ""; + options = options || {}; + var capitalize = function(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + }; + + if (messages.length === 0) { + return options.quiet ? "" : filename + ": Lint Free!"; + } + + CSSLint.Util.forEach(messages, function(message) { + if (message.rollup) { + output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n"; + } else { + output += filename + ": " + "line " + message.line + + ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n"; + } + }); + + return output; + } +}); + +CSSLint.addFormatter({ + id: "csslint-xml", + name: "CSSLint XML format", + startFormat: function(){ + return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>"; + }, + endFormat: function(){ + return "</csslint>"; + }, + formatResults: function(results, filename/*, options*/) { + var messages = results.messages, + output = []; + var escapeSpecialCharacters = function(str) { + if (!str || str.constructor !== String) { + return ""; + } + return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); + }; + + if (messages.length > 0) { + output.push("<file name=\""+filename+"\">"); + CSSLint.Util.forEach(messages, function (message) { + if (message.rollup) { + output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); + } else { + output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" + + " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); + } + }); + output.push("</file>"); + } + + return output.join(""); + } +}); + +CSSLint.addFormatter({ + id: "junit-xml", + name: "JUNIT XML format", + startFormat: function(){ + return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>"; + }, + endFormat: function() { + return "</testsuites>"; + }, + formatResults: function(results, filename/*, options*/) { + + var messages = results.messages, + output = [], + tests = { + "error": 0, + "failure": 0 + }; + var generateSource = function(rule) { + if (!rule || !("name" in rule)) { + return ""; + } + return "net.csslint." + rule.name.replace(/\s/g,""); + }; + var escapeSpecialCharacters = function(str) { + + if (!str || str.constructor !== String) { + return ""; + } + + return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;"); + + }; + + if (messages.length > 0) { + + messages.forEach(function (message) { + var type = message.type === "warning" ? "error" : message.type; + if (!message.rollup) { + output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">"); + output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ":" + message.col + ":" + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">"); + output.push("</testcase>"); + + tests[type] += 1; + + } + + }); + + output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">"); + output.push("</testsuite>"); + + } + + return output.join(""); + + } +}); + +CSSLint.addFormatter({ + id: "lint-xml", + name: "Lint XML format", + startFormat: function(){ + return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>"; + }, + endFormat: function(){ + return "</lint>"; + }, + formatResults: function(results, filename/*, options*/) { + var messages = results.messages, + output = []; + var escapeSpecialCharacters = function(str) { + if (!str || str.constructor !== String) { + return ""; + } + return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); + }; + + if (messages.length > 0) { + + output.push("<file name=\""+filename+"\">"); + CSSLint.Util.forEach(messages, function (message) { + if (message.rollup) { + output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); + } else { + output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" + + " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); + } + }); + output.push("</file>"); + } + + return output.join(""); + } +}); + +CSSLint.addFormatter({ + id: "text", + name: "Plain Text", + startFormat: function() { + return ""; + }, + endFormat: function() { + return ""; + }, + formatResults: function(results, filename, options) { + var messages = results.messages, + output = ""; + options = options || {}; + + if (messages.length === 0) { + return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + "."; + } + + output = "\n\ncsslint: There "; + if (messages.length === 1) { + output += "is 1 problem"; + } else { + output += "are " + messages.length + " problems"; + } + output += " in " + filename + "."; + + var pos = filename.lastIndexOf("/"), + shortFilename = filename; + + if (pos === -1){ + pos = filename.lastIndexOf("\\"); + } + if (pos > -1){ + shortFilename = filename.substring(pos+1); + } + + CSSLint.Util.forEach(messages, function (message, i) { + output = output + "\n\n" + shortFilename; + if (message.rollup) { + output += "\n" + (i+1) + ": " + message.type; + output += "\n" + message.message; + } else { + output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col; + output += "\n" + message.message; + output += "\n" + message.evidence; + } + }); + + return output; + } +}); + +module.exports.CSSLint = CSSLint; + +}); + +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) { +"use strict"; + +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var Mirror = require("../worker/mirror").Mirror; +var CSSLint = require("./css/csslint").CSSLint; + +var Worker = exports.Worker = function(sender) { + Mirror.call(this, sender); + this.setTimeout(400); + this.ruleset = null; + this.setDisabledRules("ids|order-alphabetical"); + this.setInfoRules( + "adjoining-classes|qualified-headings|zero-units|gradients|" + + "import|outline-none|vendor-prefix" + ); +}; + +oop.inherits(Worker, Mirror); + +(function() { + this.setInfoRules = function(ruleNames) { + if (typeof ruleNames == "string") + ruleNames = ruleNames.split("|"); + this.infoRules = lang.arrayToMap(ruleNames); + this.doc.getValue() && this.deferredUpdate.schedule(100); + }; + + this.setDisabledRules = function(ruleNames) { + if (!ruleNames) { + this.ruleset = null; + } else { + if (typeof ruleNames == "string") + ruleNames = ruleNames.split("|"); + var all = {}; + + CSSLint.getRules().forEach(function(x){ + all[x.id] = true; + }); + ruleNames.forEach(function(x) { + delete all[x]; + }); + + this.ruleset = all; + } + this.doc.getValue() && this.deferredUpdate.schedule(100); + }; + + this.onUpdate = function() { + var value = this.doc.getValue(); + if (!value) + return this.sender.emit("annotate", []); + var infoRules = this.infoRules; + + var result = CSSLint.verify(value, this.ruleset); + this.sender.emit("annotate", result.messages.map(function(msg) { + return { + row: msg.line - 1, + column: msg.col - 1, + text: msg.message, + type: infoRules[msg.rule.id] ? "info" : msg.type, + rule: msg.rule.name + } + })); + }; + +}).call(Worker.prototype); + +}); + +ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { + +function Empty() {} + +if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { // .length is 1 + var target = this; + if (typeof target != "function") { + throw new TypeError("Function.prototype.bind called on incompatible " + target); + } + var args = slice.call(arguments, 1); // for normal call + var bound = function () { + + if (this instanceof bound) { + + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + + } else { + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + if(target.prototype) { + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } + return bound; + }; +} +var call = Function.prototype.call; +var prototypeOfArray = Array.prototype; +var prototypeOfObject = Object.prototype; +var slice = prototypeOfArray.slice; +var _toString = call.bind(prototypeOfObject.toString); +var owns = call.bind(prototypeOfObject.hasOwnProperty); +var defineGetter; +var defineSetter; +var lookupGetter; +var lookupSetter; +var supportsAccessors; +if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { + defineGetter = call.bind(prototypeOfObject.__defineGetter__); + defineSetter = call.bind(prototypeOfObject.__defineSetter__); + lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); + lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); +} +if ([1,2].splice(0).length != 2) { + if(function() { // test IE < 9 to splice bug - see issue #138 + function makeArray(l) { + var a = new Array(l+2); + a[0] = a[1] = 0; + return a; + } + var array = [], lengthBefore; + + array.splice.apply(array, makeArray(20)); + array.splice.apply(array, makeArray(26)); + + lengthBefore = array.length; //46 + array.splice(5, 0, "XXX"); // add one element + + lengthBefore + 1 == array.length + + if (lengthBefore + 1 == array.length) { + return true;// has right splice implementation without bugs + } + }()) {//IE 6/7 + var array_splice = Array.prototype.splice; + Array.prototype.splice = function(start, deleteCount) { + if (!arguments.length) { + return []; + } else { + return array_splice.apply(this, [ + start === void 0 ? 0 : start, + deleteCount === void 0 ? (this.length - start) : deleteCount + ].concat(slice.call(arguments, 2))) + } + }; + } else {//IE8 + Array.prototype.splice = function(pos, removeCount){ + var length = this.length; + if (pos > 0) { + if (pos > length) + pos = length; + } else if (pos == void 0) { + pos = 0; + } else if (pos < 0) { + pos = Math.max(length + pos, 0); + } + + if (!(pos+removeCount < length)) + removeCount = length - pos; + + var removed = this.slice(pos, pos+removeCount); + var insert = slice.call(arguments, 2); + var add = insert.length; + if (pos === length) { + if (add) { + this.push.apply(this, insert); + } + } else { + var remove = Math.min(removeCount, length - pos); + var tailOldPos = pos + remove; + var tailNewPos = tailOldPos + add - remove; + var tailCount = length - tailOldPos; + var lengthAfterRemove = length - remove; + + if (tailNewPos < tailOldPos) { // case A + for (var i = 0; i < tailCount; ++i) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } else if (tailNewPos > tailOldPos) { // case B + for (i = tailCount; i--; ) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } // else, add == remove (nothing to do) + + if (add && pos === lengthAfterRemove) { + this.length = lengthAfterRemove; // truncate array + this.push.apply(this, insert); + } else { + this.length = lengthAfterRemove + add; // reserves space + for (i = 0; i < add; ++i) { + this[pos+i] = insert[i]; + } + } + } + return removed; + }; + } +} +if (!Array.isArray) { + Array.isArray = function isArray(obj) { + return _toString(obj) == "[object Array]"; + }; +} +var boxedString = Object("a"), + splitString = boxedString[0] != "a" || !(0 in boxedString); + +if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + thisp = arguments[1], + i = -1, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + while (++i < length) { + if (i in self) { + fun.call(thisp, self[i], i, object); + } + } + }; +} +if (!Array.prototype.map) { + Array.prototype.map = function map(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = Array(length), + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) + result[i] = fun.call(thisp, self[i], i, object); + } + return result; + }; +} +if (!Array.prototype.filter) { + Array.prototype.filter = function filter(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = [], + value, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) { + value = self[i]; + if (fun.call(thisp, value, i, object)) { + result.push(value); + } + } + } + return result; + }; +} +if (!Array.prototype.every) { + Array.prototype.every = function every(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && !fun.call(thisp, self[i], i, object)) { + return false; + } + } + return true; + }; +} +if (!Array.prototype.some) { + Array.prototype.some = function some(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && fun.call(thisp, self[i], i, object)) { + return true; + } + } + return false; + }; +} +if (!Array.prototype.reduce) { + Array.prototype.reduce = function reduce(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + if (!length && arguments.length == 1) { + throw new TypeError("reduce of empty array with no initial value"); + } + + var i = 0; + var result; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i++]; + break; + } + if (++i >= length) { + throw new TypeError("reduce of empty array with no initial value"); + } + } while (true); + } + + for (; i < length; i++) { + if (i in self) { + result = fun.call(void 0, result, self[i], i, object); + } + } + + return result; + }; +} +if (!Array.prototype.reduceRight) { + Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + if (!length && arguments.length == 1) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + + var result, i = length - 1; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i--]; + break; + } + if (--i < 0) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + } while (true); + } + + do { + if (i in this) { + result = fun.call(void 0, result, self[i], i, object); + } + } while (i--); + + return result; + }; +} +if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { + Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + + var i = 0; + if (arguments.length > 1) { + i = toInteger(arguments[1]); + } + i = i >= 0 ? i : Math.max(0, length + i); + for (; i < length; i++) { + if (i in self && self[i] === sought) { + return i; + } + } + return -1; + }; +} +if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { + Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + var i = length - 1; + if (arguments.length > 1) { + i = Math.min(i, toInteger(arguments[1])); + } + i = i >= 0 ? i : length - Math.abs(i); + for (; i >= 0; i--) { + if (i in self && sought === self[i]) { + return i; + } + } + return -1; + }; +} +if (!Object.getPrototypeOf) { + Object.getPrototypeOf = function getPrototypeOf(object) { + return object.__proto__ || ( + object.constructor ? + object.constructor.prototype : + prototypeOfObject + ); + }; +} +if (!Object.getOwnPropertyDescriptor) { + var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + + "non-object: "; + Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT + object); + if (!owns(object, property)) + return; + + var descriptor, getter, setter; + descriptor = { enumerable: true, configurable: true }; + if (supportsAccessors) { + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + + var getter = lookupGetter(object, property); + var setter = lookupSetter(object, property); + object.__proto__ = prototype; + + if (getter || setter) { + if (getter) descriptor.get = getter; + if (setter) descriptor.set = setter; + return descriptor; + } + } + descriptor.value = object[property]; + return descriptor; + }; +} +if (!Object.getOwnPropertyNames) { + Object.getOwnPropertyNames = function getOwnPropertyNames(object) { + return Object.keys(object); + }; +} +if (!Object.create) { + var createEmpty; + if (Object.prototype.__proto__ === null) { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + createEmpty = function () { + var empty = {}; + for (var i in empty) + empty[i] = null; + empty.constructor = + empty.hasOwnProperty = + empty.propertyIsEnumerable = + empty.isPrototypeOf = + empty.toLocaleString = + empty.toString = + empty.valueOf = + empty.__proto__ = null; + return empty; + } + } + + Object.create = function create(prototype, properties) { + var object; + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype != "object") + throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); + var Type = function () {}; + Type.prototype = prototype; + object = new Type(); + object.__proto__ = prototype; + } + if (properties !== void 0) + Object.defineProperties(object, properties); + return object; + }; +} + +function doesDefinePropertyWork(object) { + try { + Object.defineProperty(object, "sentinel", {}); + return "sentinel" in object; + } catch (exception) { + } +} +if (Object.defineProperty) { + var definePropertyWorksOnObject = doesDefinePropertyWork({}); + var definePropertyWorksOnDom = typeof document == "undefined" || + doesDefinePropertyWork(document.createElement("div")); + if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { + var definePropertyFallback = Object.defineProperty; + } +} + +if (!Object.defineProperty || definePropertyFallback) { + var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; + var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " + var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + + "on this javascript engine"; + + Object.defineProperty = function defineProperty(object, property, descriptor) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT_TARGET + object); + if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) + throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); + if (definePropertyFallback) { + try { + return definePropertyFallback.call(Object, object, property, descriptor); + } catch (exception) { + } + } + if (owns(descriptor, "value")) { + + if (supportsAccessors && (lookupGetter(object, property) || + lookupSetter(object, property))) + { + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + delete object[property]; + object[property] = descriptor.value; + object.__proto__ = prototype; + } else { + object[property] = descriptor.value; + } + } else { + if (!supportsAccessors) + throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); + if (owns(descriptor, "get")) + defineGetter(object, property, descriptor.get); + if (owns(descriptor, "set")) + defineSetter(object, property, descriptor.set); + } + + return object; + }; +} +if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (owns(properties, property)) + Object.defineProperty(object, property, properties[property]); + } + return object; + }; +} +if (!Object.seal) { + Object.seal = function seal(object) { + return object; + }; +} +if (!Object.freeze) { + Object.freeze = function freeze(object) { + return object; + }; +} +try { + Object.freeze(function () {}); +} catch (exception) { + Object.freeze = (function freeze(freezeObject) { + return function freeze(object) { + if (typeof object == "function") { + return object; + } else { + return freezeObject(object); + } + }; + })(Object.freeze); +} +if (!Object.preventExtensions) { + Object.preventExtensions = function preventExtensions(object) { + return object; + }; +} +if (!Object.isSealed) { + Object.isSealed = function isSealed(object) { + return false; + }; +} +if (!Object.isFrozen) { + Object.isFrozen = function isFrozen(object) { + return false; + }; +} +if (!Object.isExtensible) { + Object.isExtensible = function isExtensible(object) { + if (Object(object) === object) { + throw new TypeError(); // TODO message + } + var name = ''; + while (owns(object, name)) { + name += '?'; + } + object[name] = true; + var returnValue = owns(object, name); + delete object[name]; + return returnValue; + }; +} +if (!Object.keys) { + var hasDontEnumBug = true, + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ], + dontEnumsLength = dontEnums.length; + + for (var key in {"toString": null}) { + hasDontEnumBug = false; + } + + Object.keys = function keys(object) { + + if ( + (typeof object != "object" && typeof object != "function") || + object === null + ) { + throw new TypeError("Object.keys called on a non-object"); + } + + var keys = []; + for (var name in object) { + if (owns(object, name)) { + keys.push(name); + } + } + + if (hasDontEnumBug) { + for (var i = 0, ii = dontEnumsLength; i < ii; i++) { + var dontEnum = dontEnums[i]; + if (owns(object, dontEnum)) { + keys.push(dontEnum); + } + } + } + return keys; + }; + +} +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} +var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + + "\u2029\uFEFF"; +if (!String.prototype.trim || ws.trim()) { + ws = "[" + ws + "]"; + var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), + trimEndRegexp = new RegExp(ws + ws + "*$"); + String.prototype.trim = function trim() { + return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); + }; +} + +function toInteger(n) { + n = +n; + if (n !== n) { // isNaN + n = 0; + } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + return n; +} + +function isPrimitive(input) { + var type = typeof input; + return ( + input === null || + type === "undefined" || + type === "boolean" || + type === "number" || + type === "string" + ); +} + +function toPrimitive(input) { + var val, valueOf, toString; + if (isPrimitive(input)) { + return input; + } + valueOf = input.valueOf; + if (typeof valueOf === "function") { + val = valueOf.call(input); + if (isPrimitive(val)) { + return val; + } + } + toString = input.toString; + if (typeof toString === "function") { + val = toString.call(input); + if (isPrimitive(val)) { + return val; + } + } + throw new TypeError(); +} +var toObject = function (o) { + if (o == null) { // this matches both null and undefined + throw new TypeError("can't convert "+o+" to object"); + } + return Object(o); +}; + +});