markdown格式wiki文档

worker-css.js 290KB

    "no use strict"; ;(function(window) { if (typeof window.window != "undefined" && window.document) return; if (window.require && window.define) return; if (!window.console) { 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, data: err.data, 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 require(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; } if (!window.require.tlns) return console.log("unable to load " + id); var path = resolveModuleId(id, window.require.tlns); if (path.slice(-3) != ".js") path += ".js"; window.require.id = id; window.require.modules[id] = {}; // prevent infinite loop on broken modules importScripts(path); return window.require(parentId, id); }; function resolveModuleId(id, paths) { var testPath = id, tail = ""; while (testPath) { var alias = paths[testPath]; if (typeof alias == "string") { return alias + tail; } else if (alias) { return alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name); } else if (alias === false) { return ""; } var i = testPath.lastIndexOf("/"); if (i === -1) break; tail = testPath.substr(i) + tail; testPath = testPath.slice(0, i); } return id; } 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 = {}; require.tlns = {}; window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { for (var i in topLevelNamespaces) require.tlns[i] = topLevelNamespaces[i]; }; 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.event && sender) { sender._signal(msg.event, msg.data); } else if (msg.command) { if (main[msg.command]) main[msg.command].apply(main, msg.args); else if (window[msg.command]) window[msg.command].apply(window, msg.args); else throw new Error("Unknown command:" + msg.command); } else if (msg.init) { window.initBaseUrls(msg.tlns); require("ace/lib/es5-shim"); sender = window.sender = window.initSender(); var clazz = require(msg.module)[msg.classname]; main = window.main = new clazz(sender); } }; })(this); 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); }; }); 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 deepCopy(obj) { if (typeof obj !== "object" || !obj) return obj; var copy; if (Array.isArray(obj)) { copy = []; for (var key = 0; key < obj.length; key++) { copy[key] = deepCopy(obj[key]); } return copy; } if (Object.prototype.toString.call(obj) !== "[object Object]") return obj; copy = {}; for (var key in obj) copy[key] = deepCopy(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; }; }); 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; }); define("ace/apply_delta",["require","exports","module"], function(require, exports, module) { "use strict"; function throwDeltaError(delta, errorText){ console.log("Invalid Delta:", delta); throw "Invalid Delta: " + errorText; } function positionInDocument(docLines, position) { return position.row >= 0 && position.row < docLines.length && position.column >= 0 && position.column <= docLines[position.row].length; } function validateDelta(docLines, delta) { if (delta.action != "insert" && delta.action != "remove") throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); if (!(delta.lines instanceof Array)) throwDeltaError(delta, "delta.lines must be an Array"); if (!delta.start || !delta.end) throwDeltaError(delta, "delta.start/end must be an present"); var start = delta.start; if (!positionInDocument(docLines, delta.start)) throwDeltaError(delta, "delta.start must be contained in document"); var end = delta.end; if (delta.action == "remove" && !positionInDocument(docLines, end)) throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); var numRangeRows = end.row - start.row; var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) throwDeltaError(delta, "delta.range must match delta lines"); } exports.applyDelta = function(docLines, delta, doNotValidate) { var row = delta.start.row; var startColumn = delta.start.column; var line = docLines[row] || ""; switch (delta.action) { case "insert": var lines = delta.lines; if (lines.length === 1) { docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); } else { var args = [row, 1].concat(delta.lines); docLines.splice.apply(docLines, args); docLines[row] = line.substring(0, startColumn) + docLines[row]; docLines[row + delta.lines.length - 1] += line.substring(startColumn); } break; case "remove": var endColumn = delta.end.column; var endRow = delta.end.row; if (row === endRow) { docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); } else { docLines.splice( row, endRow - row + 1, line.substring(0, startColumn) + docLines[endRow].substring(endColumn) ); } break; } } }); 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; }); 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(delta) { if (delta.start.row == delta.end.row && delta.start.row != this.row) return; if (delta.start.row > this.row) return; var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); this.setPosition(point.row, point.column, true); }; function $pointsInOrder(point1, point2, equalPointsInOrder) { var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); } function $getTransformedPoint(delta, point, moveIfEqual) { var deltaIsInsert = delta.action == "insert"; var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); var deltaStart = delta.start; var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range. if ($pointsInOrder(point, deltaStart, moveIfEqual)) { return { row: point.row, column: point.column }; } if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { return { row: point.row + deltaRowShift, column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) }; } return { row: deltaStart.row, column: deltaStart.column }; } 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); }); define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var applyDelta = require("./apply_delta").applyDelta; var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var Document = function(textOrLines) { this.$lines = [""]; if (textOrLines.length === 0) { this.$lines = [""]; } else if (Array.isArray(textOrLines)) { this.insertMergedLines({row: 0, column: 0}, textOrLines); } else { this.insert({row: 0, column:0}, textOrLines); } }; (function() { oop.implement(this, EventEmitter); this.setValue = function(text) { var len = this.getLength() - 1; this.remove(new Range(0, 0, len, this.getLine(len).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) { return this.getLinesForRange(range).join(this.getNewLineCharacter()); }; this.getLinesForRange = function(range) { var lines; if (range.start.row === range.end.row) { lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; } else { lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); var l = lines.length - 1; if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column); } return lines; }; this.insertLines = function(row, lines) { console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); return this.insertFullLines(row, lines); }; this.removeLines = function(firstRow, lastRow) { console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); return this.removeFullLines(firstRow, lastRow); }; this.insertNewLine = function(position) { console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."); return this.insertMergedLines(position, ["", ""]); }; this.insert = function(position, text) { if (this.getLength() <= 1) this.$detectNewLine(text); return this.insertMergedLines(position, this.$split(text)); }; this.insertInLine = function(position, text) { var start = this.clippedPos(position.row, position.column); var end = this.pos(position.row, position.column + text.length); this.applyDelta({ start: start, end: end, action: "insert", lines: [text] }, true); return this.clonePos(end); }; this.clippedPos = function(row, column) { var length = this.getLength(); if (row === undefined) { row = length; } else if (row < 0) { row = 0; } else if (row >= length) { row = length - 1; column = undefined; } var line = this.getLine(row); if (column == undefined) column = line.length; column = Math.min(Math.max(column, 0), line.length); return {row: row, column: column}; }; this.clonePos = function(pos) { return {row: pos.row, column: pos.column}; }; this.pos = function(row, column) { return {row: row, column: column}; }; this.$clipPosition = function(position) { var length = this.getLength(); if (position.row >= length) { position.row = Math.max(0, length - 1); position.column = this.getLine(length - 1).length; } else { position.row = Math.max(0, position.row); position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); } return position; }; this.insertFullLines = function(row, lines) { row = Math.min(Math.max(row, 0), this.getLength()); var column = 0; if (row < this.getLength()) { lines = lines.concat([""]); column = 0; } else { lines = [""].concat(lines); row--; column = this.$lines[row].length; } this.insertMergedLines({row: row, column: column}, lines); }; this.insertMergedLines = function(position, lines) { var start = this.clippedPos(position.row, position.column); var end = { row: start.row + lines.length - 1, column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length }; this.applyDelta({ start: start, end: end, action: "insert", lines: lines }); return this.clonePos(end); }; this.remove = function(range) { var start = this.clippedPos(range.start.row, range.start.column); var end = this.clippedPos(range.end.row, range.end.column); this.applyDelta({ start: start, end: end, action: "remove", lines: this.getLinesForRange({start: start, end: end}) }); return this.clonePos(start); }; this.removeInLine = function(row, startColumn, endColumn) { var start = this.clippedPos(row, startColumn); var end = this.clippedPos(row, endColumn); this.applyDelta({ start: start, end: end, action: "remove", lines: this.getLinesForRange({start: start, end: end}) }, true); return this.clonePos(start); }; this.removeFullLines = function(firstRow, lastRow) { firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; var deleteLastNewLine = lastRow < this.getLength() - 1; var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); var range = new Range(startRow, startCol, endRow, endCol); var deletedLines = this.$lines.slice(firstRow, lastRow + 1); this.applyDelta({ start: range.start, end: range.end, action: "remove", lines: this.getLinesForRange(range) }); return deletedLines; }; this.removeNewLine = function(row) { if (row < this.getLength() - 1 && row >= 0) { this.applyDelta({ start: this.pos(row, this.getLine(row).length), end: this.pos(row + 1, 0), action: "remove", lines: ["", ""] }); } }; 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); var end; if (text) { end = this.insert(range.start, text); } else { end = range.start; } return end; }; this.applyDeltas = function(deltas) { for (var i=0; i<deltas.length; i++) { this.applyDelta(deltas[i]); } }; this.revertDeltas = function(deltas) { for (var i=deltas.length-1; i>=0; i--) { this.revertDelta(deltas[i]); } }; this.applyDelta = function(delta, doNotValidate) { var isInsert = delta.action == "insert"; if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] : !Range.comparePoints(delta.start, delta.end)) { return; } if (isInsert && delta.lines.length > 20000) this.$splitAndapplyLargeDelta(delta, 20000); applyDelta(this.$lines, delta, doNotValidate); this._signal("change", delta); }; this.$splitAndapplyLargeDelta = function(delta, MAX) { var lines = delta.lines; var l = lines.length; var row = delta.start.row; var column = delta.start.column; var from = 0, to = 0; do { from = to; to += MAX - 1; var chunk = lines.slice(from, to); if (to > l) { delta.lines = chunk; delta.start.row = row + from; delta.start.column = column; break; } chunk.push(""); this.applyDelta({ start: this.pos(row + from, column), end: this.pos(row + to, column = 0), action: delta.action, lines: chunk }, true); } while(true); }; this.revertDelta = function(delta) { this.applyDelta({ start: this.clonePos(delta.start), end: this.clonePos(delta.end), action: (delta.action == "insert" ? "remove" : "insert"), lines: delta.lines.slice() }); }; 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; }); define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; 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) { var data = e.data; if (data[0].start) { doc.applyDeltas(data); } else { for (var i = 0; i < data.length; i += 2) { if (Array.isArray(data[i+1])) { var d = {action: "insert", start: data[i], lines: data[i+1]}; } else { var d = {action: "remove", start: data[i], end: data[i+1]}; } doc.applyDelta(d, true); } } 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); }); 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 | reverse | alternate | alternate-reverse", 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 | reverse | alternate | alternate-reverse", 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 | reverse | alternate | alternate-reverse", 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 | reverse | alternate | alternate-reverse", 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 | reverse | alternate | alternate-reverse", 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; }); 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); }); 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); }; });