/script-kiddie/002_script_kiddie/script-kiddie/node_modules/ace-builds/src-noconflict/worker-css.js |
@@ -0,0 +1,8760 @@ |
"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); |
|
ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { |
"use strict"; |
|
exports.inherits = function(ctor, superCtor) { |
ctor.super_ = superCtor; |
ctor.prototype = Object.create(superCtor.prototype, { |
constructor: { |
value: ctor, |
enumerable: false, |
writable: true, |
configurable: true |
} |
}); |
}; |
|
exports.mixin = function(obj, mixin) { |
for (var key in mixin) { |
obj[key] = mixin[key]; |
} |
return obj; |
}; |
|
exports.implement = function(proto, mixin) { |
exports.mixin(proto, mixin); |
}; |
|
}); |
|
ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { |
"use strict"; |
|
exports.last = function(a) { |
return a[a.length - 1]; |
}; |
|
exports.stringReverse = function(string) { |
return string.split("").reverse().join(""); |
}; |
|
exports.stringRepeat = function (string, count) { |
var result = ''; |
while (count > 0) { |
if (count & 1) |
result += string; |
|
if (count >>= 1) |
string += string; |
} |
return result; |
}; |
|
var trimBeginRegexp = /^\s\s*/; |
var trimEndRegexp = /\s\s*$/; |
|
exports.stringTrimLeft = function (string) { |
return string.replace(trimBeginRegexp, ''); |
}; |
|
exports.stringTrimRight = function (string) { |
return string.replace(trimEndRegexp, ''); |
}; |
|
exports.copyObject = function(obj) { |
var copy = {}; |
for (var key in obj) { |
copy[key] = obj[key]; |
} |
return copy; |
}; |
|
exports.copyArray = function(array){ |
var copy = []; |
for (var i=0, l=array.length; i<l; i++) { |
if (array[i] && typeof array[i] == "object") |
copy[i] = this.copyObject(array[i]); |
else |
copy[i] = array[i]; |
} |
return copy; |
}; |
|
exports.deepCopy = function 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, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<"); |
}; |
|
exports.getMatchOffsets = function(string, regExp) { |
var matches = []; |
|
string.replace(regExp, function(str) { |
matches.push({ |
offset: arguments[arguments.length-2], |
length: str.length |
}); |
}); |
|
return matches; |
}; |
exports.deferredCall = function(fcn) { |
var timer = null; |
var callback = function() { |
timer = null; |
fcn(); |
}; |
|
var deferred = function(timeout) { |
deferred.cancel(); |
timer = setTimeout(callback, timeout || 0); |
return deferred; |
}; |
|
deferred.schedule = deferred; |
|
deferred.call = function() { |
this.cancel(); |
fcn(); |
return deferred; |
}; |
|
deferred.cancel = function() { |
clearTimeout(timer); |
timer = null; |
return deferred; |
}; |
|
deferred.isPending = function() { |
return timer; |
}; |
|
return deferred; |
}; |
|
|
exports.delayedCall = function(fcn, defaultTimeout) { |
var timer = null; |
var callback = function() { |
timer = null; |
fcn(); |
}; |
|
var _self = function(timeout) { |
if (timer == null) |
timer = setTimeout(callback, timeout || defaultTimeout); |
}; |
|
_self.delay = function(timeout) { |
timer && clearTimeout(timer); |
timer = setTimeout(callback, timeout || defaultTimeout); |
}; |
_self.schedule = _self; |
|
_self.call = function() { |
this.cancel(); |
fcn(); |
}; |
|
_self.cancel = function() { |
timer && clearTimeout(timer); |
timer = null; |
}; |
|
_self.isPending = function() { |
return timer; |
}; |
|
return _self; |
}; |
}); |
|
ace.define("ace/range",["require","exports","module"], function(require, exports, module) { |
"use strict"; |
var comparePoints = function(p1, p2) { |
return p1.row - p2.row || p1.column - p2.column; |
}; |
var Range = function(startRow, startColumn, endRow, endColumn) { |
this.start = { |
row: startRow, |
column: startColumn |
}; |
|
this.end = { |
row: endRow, |
column: endColumn |
}; |
}; |
|
(function() { |
this.isEqual = function(range) { |
return this.start.row === range.start.row && |
this.end.row === range.end.row && |
this.start.column === range.start.column && |
this.end.column === range.end.column; |
}; |
this.toString = function() { |
return ("Range: [" + this.start.row + "/" + this.start.column + |
"] -> [" + this.end.row + "/" + this.end.column + "]"); |
}; |
|
this.contains = function(row, column) { |
return this.compare(row, column) == 0; |
}; |
this.compareRange = function(range) { |
var cmp, |
end = range.end, |
start = range.start; |
|
cmp = this.compare(end.row, end.column); |
if (cmp == 1) { |
cmp = this.compare(start.row, start.column); |
if (cmp == 1) { |
return 2; |
} else if (cmp == 0) { |
return 1; |
} else { |
return 0; |
} |
} else if (cmp == -1) { |
return -2; |
} else { |
cmp = this.compare(start.row, start.column); |
if (cmp == -1) { |
return -1; |
} else if (cmp == 1) { |
return 42; |
} else { |
return 0; |
} |
} |
}; |
this.comparePoint = function(p) { |
return this.compare(p.row, p.column); |
}; |
this.containsRange = function(range) { |
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; |
}; |
this.intersects = function(range) { |
var cmp = this.compareRange(range); |
return (cmp == -1 || cmp == 0 || cmp == 1); |
}; |
this.isEnd = function(row, column) { |
return this.end.row == row && this.end.column == column; |
}; |
this.isStart = function(row, column) { |
return this.start.row == row && this.start.column == column; |
}; |
this.setStart = function(row, column) { |
if (typeof row == "object") { |
this.start.column = row.column; |
this.start.row = row.row; |
} else { |
this.start.row = row; |
this.start.column = column; |
} |
}; |
this.setEnd = function(row, column) { |
if (typeof row == "object") { |
this.end.column = row.column; |
this.end.row = row.row; |
} else { |
this.end.row = row; |
this.end.column = column; |
} |
}; |
this.inside = function(row, column) { |
if (this.compare(row, column) == 0) { |
if (this.isEnd(row, column) || this.isStart(row, column)) { |
return false; |
} else { |
return true; |
} |
} |
return false; |
}; |
this.insideStart = function(row, column) { |
if (this.compare(row, column) == 0) { |
if (this.isEnd(row, column)) { |
return false; |
} else { |
return true; |
} |
} |
return false; |
}; |
this.insideEnd = function(row, column) { |
if (this.compare(row, column) == 0) { |
if (this.isStart(row, column)) { |
return false; |
} else { |
return true; |
} |
} |
return false; |
}; |
this.compare = function(row, column) { |
if (!this.isMultiLine()) { |
if (row === this.start.row) { |
return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); |
} |
} |
|
if (row < this.start.row) |
return -1; |
|
if (row > this.end.row) |
return 1; |
|
if (this.start.row === row) |
return column >= this.start.column ? 0 : -1; |
|
if (this.end.row === row) |
return column <= this.end.column ? 0 : 1; |
|
return 0; |
}; |
this.compareStart = function(row, column) { |
if (this.start.row == row && this.start.column == column) { |
return -1; |
} else { |
return this.compare(row, column); |
} |
}; |
this.compareEnd = function(row, column) { |
if (this.end.row == row && this.end.column == column) { |
return 1; |
} else { |
return this.compare(row, column); |
} |
}; |
this.compareInside = function(row, column) { |
if (this.end.row == row && this.end.column == column) { |
return 1; |
} else if (this.start.row == row && this.start.column == column) { |
return -1; |
} else { |
return this.compare(row, column); |
} |
}; |
this.clipRows = function(firstRow, lastRow) { |
if (this.end.row > lastRow) |
var end = {row: lastRow + 1, column: 0}; |
else if (this.end.row < firstRow) |
var end = {row: firstRow, column: 0}; |
|
if (this.start.row > lastRow) |
var start = {row: lastRow + 1, column: 0}; |
else if (this.start.row < firstRow) |
var start = {row: firstRow, column: 0}; |
|
return Range.fromPoints(start || this.start, end || this.end); |
}; |
this.extend = function(row, column) { |
var cmp = this.compare(row, column); |
|
if (cmp == 0) |
return this; |
else if (cmp == -1) |
var start = {row: row, column: column}; |
else |
var end = {row: row, column: column}; |
|
return Range.fromPoints(start || this.start, end || this.end); |
}; |
|
this.isEmpty = function() { |
return (this.start.row === this.end.row && this.start.column === this.end.column); |
}; |
this.isMultiLine = function() { |
return (this.start.row !== this.end.row); |
}; |
this.clone = function() { |
return Range.fromPoints(this.start, this.end); |
}; |
this.collapseRows = function() { |
if (this.end.column == 0) |
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) |
else |
return new Range(this.start.row, 0, this.end.row, 0) |
}; |
this.toScreenRange = function(session) { |
var screenPosStart = session.documentToScreenPosition(this.start); |
var screenPosEnd = session.documentToScreenPosition(this.end); |
|
return new Range( |
screenPosStart.row, screenPosStart.column, |
screenPosEnd.row, screenPosEnd.column |
); |
}; |
this.moveBy = function(row, column) { |
this.start.row += row; |
this.start.column += column; |
this.end.row += row; |
this.end.column += column; |
}; |
|
}).call(Range.prototype); |
Range.fromPoints = function(start, end) { |
return new Range(start.row, start.column, end.row, end.column); |
}; |
Range.comparePoints = comparePoints; |
|
Range.comparePoints = function(p1, p2) { |
return p1.row - p2.row || p1.column - p2.column; |
}; |
|
|
exports.Range = Range; |
}); |
|
ace.define("ace/apply_delta",["require","exports","module"], function(require, exports, module) { |
"use strict"; |
|
function throwDeltaError(delta, errorText){ |
console.log("Invalid Delta:", delta); |
throw "Invalid Delta: " + errorText; |
} |
|
function positionInDocument(docLines, position) { |
return position.row >= 0 && position.row < docLines.length && |
position.column >= 0 && position.column <= docLines[position.row].length; |
} |
|
function validateDelta(docLines, delta) { |
if (delta.action != "insert" && delta.action != "remove") |
throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); |
if (!(delta.lines instanceof Array)) |
throwDeltaError(delta, "delta.lines must be an Array"); |
if (!delta.start || !delta.end) |
throwDeltaError(delta, "delta.start/end must be an present"); |
var start = delta.start; |
if (!positionInDocument(docLines, delta.start)) |
throwDeltaError(delta, "delta.start must be contained in document"); |
var end = delta.end; |
if (delta.action == "remove" && !positionInDocument(docLines, end)) |
throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); |
var numRangeRows = end.row - start.row; |
var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); |
if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) |
throwDeltaError(delta, "delta.range must match delta lines"); |
} |
|
exports.applyDelta = function(docLines, delta, doNotValidate) { |
|
var row = delta.start.row; |
var startColumn = delta.start.column; |
var line = docLines[row] || ""; |
switch (delta.action) { |
case "insert": |
var lines = delta.lines; |
if (lines.length === 1) { |
docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); |
} else { |
var args = [row, 1].concat(delta.lines); |
docLines.splice.apply(docLines, args); |
docLines[row] = line.substring(0, startColumn) + docLines[row]; |
docLines[row + delta.lines.length - 1] += line.substring(startColumn); |
} |
break; |
case "remove": |
var endColumn = delta.end.column; |
var endRow = delta.end.row; |
if (row === endRow) { |
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); |
} else { |
docLines.splice( |
row, endRow - row + 1, |
line.substring(0, startColumn) + docLines[endRow].substring(endColumn) |
); |
} |
break; |
} |
} |
}); |
|
ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { |
"use strict"; |
|
var EventEmitter = {}; |
var stopPropagation = function() { this.propagationStopped = true; }; |
var preventDefault = function() { this.defaultPrevented = true; }; |
|
EventEmitter._emit = |
EventEmitter._dispatchEvent = function(eventName, e) { |
this._eventRegistry || (this._eventRegistry = {}); |
this._defaultHandlers || (this._defaultHandlers = {}); |
|
var listeners = this._eventRegistry[eventName] || []; |
var defaultHandler = this._defaultHandlers[eventName]; |
if (!listeners.length && !defaultHandler) |
return; |
|
if (typeof e != "object" || !e) |
e = {}; |
|
if (!e.type) |
e.type = eventName; |
if (!e.stopPropagation) |
e.stopPropagation = stopPropagation; |
if (!e.preventDefault) |
e.preventDefault = preventDefault; |
|
listeners = listeners.slice(); |
for (var i=0; i<listeners.length; i++) { |
listeners[i](e, this); |
if (e.propagationStopped) |
break; |
} |
|
if (defaultHandler && !e.defaultPrevented) |
return defaultHandler(e, this); |
}; |
|
|
EventEmitter._signal = function(eventName, e) { |
var listeners = (this._eventRegistry || {})[eventName]; |
if (!listeners) |
return; |
listeners = listeners.slice(); |
for (var i=0; i<listeners.length; i++) |
listeners[i](e, this); |
}; |
|
EventEmitter.once = function(eventName, callback) { |
var _self = this; |
callback && this.addEventListener(eventName, function newCallback() { |
_self.removeEventListener(eventName, newCallback); |
callback.apply(null, arguments); |
}); |
}; |
|
|
EventEmitter.setDefaultHandler = function(eventName, callback) { |
var handlers = this._defaultHandlers |
if (!handlers) |
handlers = this._defaultHandlers = {_disabled_: {}}; |
|
if (handlers[eventName]) { |
var old = handlers[eventName]; |
var disabled = handlers._disabled_[eventName]; |
if (!disabled) |
handlers._disabled_[eventName] = disabled = []; |
disabled.push(old); |
var i = disabled.indexOf(callback); |
if (i != -1) |
disabled.splice(i, 1); |
} |
handlers[eventName] = callback; |
}; |
EventEmitter.removeDefaultHandler = function(eventName, callback) { |
var handlers = this._defaultHandlers |
if (!handlers) |
return; |
var disabled = handlers._disabled_[eventName]; |
|
if (handlers[eventName] == callback) { |
var old = handlers[eventName]; |
if (disabled) |
this.setDefaultHandler(eventName, disabled.pop()); |
} else if (disabled) { |
var i = disabled.indexOf(callback); |
if (i != -1) |
disabled.splice(i, 1); |
} |
}; |
|
EventEmitter.on = |
EventEmitter.addEventListener = function(eventName, callback, capturing) { |
this._eventRegistry = this._eventRegistry || {}; |
|
var listeners = this._eventRegistry[eventName]; |
if (!listeners) |
listeners = this._eventRegistry[eventName] = []; |
|
if (listeners.indexOf(callback) == -1) |
listeners[capturing ? "unshift" : "push"](callback); |
return callback; |
}; |
|
EventEmitter.off = |
EventEmitter.removeListener = |
EventEmitter.removeEventListener = function(eventName, callback) { |
this._eventRegistry = this._eventRegistry || {}; |
|
var listeners = this._eventRegistry[eventName]; |
if (!listeners) |
return; |
|
var index = listeners.indexOf(callback); |
if (index !== -1) |
listeners.splice(index, 1); |
}; |
|
EventEmitter.removeAllListeners = function(eventName) { |
if (this._eventRegistry) this._eventRegistry[eventName] = []; |
}; |
|
exports.EventEmitter = EventEmitter; |
|
}); |
|
ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { |
"use strict"; |
|
var oop = require("./lib/oop"); |
var EventEmitter = require("./lib/event_emitter").EventEmitter; |
|
var Anchor = exports.Anchor = function(doc, row, column) { |
this.$onChange = this.onChange.bind(this); |
this.attach(doc); |
|
if (typeof column == "undefined") |
this.setPosition(row.row, row.column); |
else |
this.setPosition(row, column); |
}; |
|
(function() { |
|
oop.implement(this, EventEmitter); |
this.getPosition = function() { |
return this.$clipPositionToDocument(this.row, this.column); |
}; |
this.getDocument = function() { |
return this.document; |
}; |
this.$insertRight = false; |
this.onChange = function(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); |
|
}); |
|
ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { |
"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; |
}); |
|
ace.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); |
|
}); |
|
ace.define("ace/mode/css/csslint",["require","exports","module"], function(require, exports, module) { |
var parserlib = {}; |
(function(){ |
function EventTarget(){ |
this._listeners = {}; |
} |
|
EventTarget.prototype = { |
constructor: EventTarget, |
addListener: function(type, listener){ |
if (!this._listeners[type]){ |
this._listeners[type] = []; |
} |
|
this._listeners[type].push(listener); |
}, |
fire: function(event){ |
if (typeof event == "string"){ |
event = { type: event }; |
} |
if (typeof event.target != "undefined"){ |
event.target = this; |
} |
|
if (typeof event.type == "undefined"){ |
throw new Error("Event object missing 'type' property."); |
} |
|
if (this._listeners[event.type]){ |
var listeners = this._listeners[event.type].concat(); |
for (var i=0, len=listeners.length; i < len; i++){ |
listeners[i].call(this, event); |
} |
} |
}, |
removeListener: function(type, listener){ |
if (this._listeners[type]){ |
var listeners = this._listeners[type]; |
for (var i=0, len=listeners.length; i < len; i++){ |
if (listeners[i] === listener){ |
listeners.splice(i, 1); |
break; |
} |
} |
|
|
} |
} |
}; |
function StringReader(text){ |
this._input = text.replace(/\n\r?/g, "\n"); |
this._line = 1; |
this._col = 1; |
this._cursor = 0; |
} |
|
StringReader.prototype = { |
constructor: StringReader, |
getCol: function(){ |
return this._col; |
}, |
getLine: function(){ |
return this._line ; |
}, |
eof: function(){ |
return (this._cursor == this._input.length); |
}, |
peek: function(count){ |
var c = null; |
count = (typeof count == "undefined" ? 1 : count); |
if (this._cursor < this._input.length){ |
c = this._input.charAt(this._cursor + count - 1); |
} |
|
return c; |
}, |
read: function(){ |
var c = null; |
if (this._cursor < this._input.length){ |
if (this._input.charAt(this._cursor) == "\n"){ |
this._line++; |
this._col=1; |
} else { |
this._col++; |
} |
c = this._input.charAt(this._cursor++); |
} |
|
return c; |
}, |
mark: function(){ |
this._bookmark = { |
cursor: this._cursor, |
line: this._line, |
col: this._col |
}; |
}, |
|
reset: function(){ |
if (this._bookmark){ |
this._cursor = this._bookmark.cursor; |
this._line = this._bookmark.line; |
this._col = this._bookmark.col; |
delete this._bookmark; |
} |
}, |
readTo: function(pattern){ |
|
var buffer = "", |
c; |
while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ |
c = this.read(); |
if (c){ |
buffer += c; |
} else { |
throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); |
} |
} |
|
return buffer; |
|
}, |
readWhile: function(filter){ |
|
var buffer = "", |
c = this.read(); |
|
while(c !== null && filter(c)){ |
buffer += c; |
c = this.read(); |
} |
|
return buffer; |
|
}, |
readMatch: function(matcher){ |
|
var source = this._input.substring(this._cursor), |
value = null; |
if (typeof matcher == "string"){ |
if (source.indexOf(matcher) === 0){ |
value = this.readCount(matcher.length); |
} |
} else if (matcher instanceof RegExp){ |
if (matcher.test(source)){ |
value = this.readCount(RegExp.lastMatch.length); |
} |
} |
|
return value; |
}, |
readCount: function(count){ |
var buffer = ""; |
|
while(count--){ |
buffer += this.read(); |
} |
|
return buffer; |
} |
|
}; |
function SyntaxError(message, line, col){ |
this.col = col; |
this.line = line; |
this.message = message; |
|
} |
SyntaxError.prototype = new Error(); |
function SyntaxUnit(text, line, col, type){ |
this.col = col; |
this.line = line; |
this.text = text; |
this.type = type; |
} |
SyntaxUnit.fromToken = function(token){ |
return new SyntaxUnit(token.value, token.startLine, token.startCol); |
}; |
|
SyntaxUnit.prototype = { |
constructor: SyntaxUnit, |
valueOf: function(){ |
return this.text; |
}, |
toString: function(){ |
return this.text; |
} |
|
}; |
function TokenStreamBase(input, tokenData){ |
this._reader = input ? new StringReader(input.toString()) : null; |
this._token = null; |
this._tokenData = tokenData; |
this._lt = []; |
this._ltIndex = 0; |
|
this._ltIndexCache = []; |
} |
TokenStreamBase.createTokenData = function(tokens){ |
|
var nameMap = [], |
typeMap = {}, |
tokenData = tokens.concat([]), |
i = 0, |
len = tokenData.length+1; |
|
tokenData.UNKNOWN = -1; |
tokenData.unshift({name:"EOF"}); |
|
for (; i < len; i++){ |
nameMap.push(tokenData[i].name); |
tokenData[tokenData[i].name] = i; |
if (tokenData[i].text){ |
typeMap[tokenData[i].text] = i; |
} |
} |
|
tokenData.name = function(tt){ |
return nameMap[tt]; |
}; |
|
tokenData.type = function(c){ |
return typeMap[c]; |
}; |
|
return tokenData; |
}; |
|
TokenStreamBase.prototype = { |
constructor: TokenStreamBase, |
match: function(tokenTypes, channel){ |
if (!(tokenTypes instanceof Array)){ |
tokenTypes = [tokenTypes]; |
} |
|
var tt = this.get(channel), |
i = 0, |
len = tokenTypes.length; |
|
while(i < len){ |
if (tt == tokenTypes[i++]){ |
return true; |
} |
} |
this.unget(); |
return false; |
}, |
mustMatch: function(tokenTypes, channel){ |
|
var token; |
if (!(tokenTypes instanceof Array)){ |
tokenTypes = [tokenTypes]; |
} |
|
if (!this.match.apply(this, arguments)){ |
token = this.LT(1); |
throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + |
" at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); |
} |
}, |
advance: function(tokenTypes, channel){ |
|
while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ |
this.get(); |
} |
|
return this.LA(0); |
}, |
get: function(channel){ |
|
var tokenInfo = this._tokenData, |
reader = this._reader, |
value, |
i =0, |
len = tokenInfo.length, |
found = false, |
token, |
info; |
if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ |
|
i++; |
this._token = this._lt[this._ltIndex++]; |
info = tokenInfo[this._token.type]; |
while((info.channel !== undefined && channel !== info.channel) && |
this._ltIndex < this._lt.length){ |
this._token = this._lt[this._ltIndex++]; |
info = tokenInfo[this._token.type]; |
i++; |
} |
if ((info.channel === undefined || channel === info.channel) && |
this._ltIndex <= this._lt.length){ |
this._ltIndexCache.push(i); |
return this._token.type; |
} |
} |
token = this._getToken(); |
if (token.type > -1 && !tokenInfo[token.type].hide){ |
token.channel = tokenInfo[token.type].channel; |
this._token = token; |
this._lt.push(token); |
this._ltIndexCache.push(this._lt.length - this._ltIndex + i); |
if (this._lt.length > 5){ |
this._lt.shift(); |
} |
if (this._ltIndexCache.length > 5){ |
this._ltIndexCache.shift(); |
} |
this._ltIndex = this._lt.length; |
} |
info = tokenInfo[token.type]; |
if (info && |
(info.hide || |
(info.channel !== undefined && channel !== info.channel))){ |
return this.get(channel); |
} else { |
return token.type; |
} |
}, |
LA: function(index){ |
var total = index, |
tt; |
if (index > 0){ |
if (index > 5){ |
throw new Error("Too much lookahead."); |
} |
while(total){ |
tt = this.get(); |
total--; |
} |
while(total < index){ |
this.unget(); |
total++; |
} |
} else if (index < 0){ |
|
if(this._lt[this._ltIndex+index]){ |
tt = this._lt[this._ltIndex+index].type; |
} else { |
throw new Error("Too much lookbehind."); |
} |
|
} else { |
tt = this._token.type; |
} |
|
return tt; |
|
}, |
LT: function(index){ |
this.LA(index); |
return this._lt[this._ltIndex+index-1]; |
}, |
peek: function(){ |
return this.LA(1); |
}, |
token: function(){ |
return this._token; |
}, |
tokenName: function(tokenType){ |
if (tokenType < 0 || tokenType > this._tokenData.length){ |
return "UNKNOWN_TOKEN"; |
} else { |
return this._tokenData[tokenType].name; |
} |
}, |
tokenType: function(tokenName){ |
return this._tokenData[tokenName] || -1; |
}, |
unget: function(){ |
if (this._ltIndexCache.length){ |
this._ltIndex -= this._ltIndexCache.pop();//--; |
this._token = this._lt[this._ltIndex - 1]; |
} else { |
throw new Error("Too much lookahead."); |
} |
} |
|
}; |
|
|
parserlib.util = { |
StringReader: StringReader, |
SyntaxError : SyntaxError, |
SyntaxUnit : SyntaxUnit, |
EventTarget : EventTarget, |
TokenStreamBase : TokenStreamBase |
}; |
})(); |
(function(){ |
var EventTarget = parserlib.util.EventTarget, |
TokenStreamBase = parserlib.util.TokenStreamBase, |
StringReader = parserlib.util.StringReader, |
SyntaxError = parserlib.util.SyntaxError, |
SyntaxUnit = parserlib.util.SyntaxUnit; |
|
var Colors = { |
aliceblue :"#f0f8ff", |
antiquewhite :"#faebd7", |
aqua :"#00ffff", |
aquamarine :"#7fffd4", |
azure :"#f0ffff", |
beige :"#f5f5dc", |
bisque :"#ffe4c4", |
black :"#000000", |
blanchedalmond :"#ffebcd", |
blue :"#0000ff", |
blueviolet :"#8a2be2", |
brown :"#a52a2a", |
burlywood :"#deb887", |
cadetblue :"#5f9ea0", |
chartreuse :"#7fff00", |
chocolate :"#d2691e", |
coral :"#ff7f50", |
cornflowerblue :"#6495ed", |
cornsilk :"#fff8dc", |
crimson :"#dc143c", |
cyan :"#00ffff", |
darkblue :"#00008b", |
darkcyan :"#008b8b", |
darkgoldenrod :"#b8860b", |
darkgray :"#a9a9a9", |
darkgrey :"#a9a9a9", |
darkgreen :"#006400", |
darkkhaki :"#bdb76b", |
darkmagenta :"#8b008b", |
darkolivegreen :"#556b2f", |
darkorange :"#ff8c00", |
darkorchid :"#9932cc", |
darkred :"#8b0000", |
darksalmon :"#e9967a", |
darkseagreen :"#8fbc8f", |
darkslateblue :"#483d8b", |
darkslategray :"#2f4f4f", |
darkslategrey :"#2f4f4f", |
darkturquoise :"#00ced1", |
darkviolet :"#9400d3", |
deeppink :"#ff1493", |
deepskyblue :"#00bfff", |
dimgray :"#696969", |
dimgrey :"#696969", |
dodgerblue :"#1e90ff", |
firebrick :"#b22222", |
floralwhite :"#fffaf0", |
forestgreen :"#228b22", |
fuchsia :"#ff00ff", |
gainsboro :"#dcdcdc", |
ghostwhite :"#f8f8ff", |
gold :"#ffd700", |
goldenrod :"#daa520", |
gray :"#808080", |
grey :"#808080", |
green :"#008000", |
greenyellow :"#adff2f", |
honeydew :"#f0fff0", |
hotpink :"#ff69b4", |
indianred :"#cd5c5c", |
indigo :"#4b0082", |
ivory :"#fffff0", |
khaki :"#f0e68c", |
lavender :"#e6e6fa", |
lavenderblush :"#fff0f5", |
lawngreen :"#7cfc00", |
lemonchiffon :"#fffacd", |
lightblue :"#add8e6", |
lightcoral :"#f08080", |
lightcyan :"#e0ffff", |
lightgoldenrodyellow :"#fafad2", |
lightgray :"#d3d3d3", |
lightgrey :"#d3d3d3", |
lightgreen :"#90ee90", |
lightpink :"#ffb6c1", |
lightsalmon :"#ffa07a", |
lightseagreen :"#20b2aa", |
lightskyblue :"#87cefa", |
lightslategray :"#778899", |
lightslategrey :"#778899", |
lightsteelblue :"#b0c4de", |
lightyellow :"#ffffe0", |
lime :"#00ff00", |
limegreen :"#32cd32", |
linen :"#faf0e6", |
magenta :"#ff00ff", |
maroon :"#800000", |
mediumaquamarine:"#66cdaa", |
mediumblue :"#0000cd", |
mediumorchid :"#ba55d3", |
mediumpurple :"#9370d8", |
mediumseagreen :"#3cb371", |
mediumslateblue :"#7b68ee", |
mediumspringgreen :"#00fa9a", |
mediumturquoise :"#48d1cc", |
mediumvioletred :"#c71585", |
midnightblue :"#191970", |
mintcream :"#f5fffa", |
mistyrose :"#ffe4e1", |
moccasin :"#ffe4b5", |
navajowhite :"#ffdead", |
navy :"#000080", |
oldlace :"#fdf5e6", |
olive :"#808000", |
olivedrab :"#6b8e23", |
orange :"#ffa500", |
orangered :"#ff4500", |
orchid :"#da70d6", |
palegoldenrod :"#eee8aa", |
palegreen :"#98fb98", |
paleturquoise :"#afeeee", |
palevioletred :"#d87093", |
papayawhip :"#ffefd5", |
peachpuff :"#ffdab9", |
peru :"#cd853f", |
pink :"#ffc0cb", |
plum :"#dda0dd", |
powderblue :"#b0e0e6", |
purple :"#800080", |
red :"#ff0000", |
rosybrown :"#bc8f8f", |
royalblue :"#4169e1", |
saddlebrown :"#8b4513", |
salmon :"#fa8072", |
sandybrown :"#f4a460", |
seagreen :"#2e8b57", |
seashell :"#fff5ee", |
sienna :"#a0522d", |
silver :"#c0c0c0", |
skyblue :"#87ceeb", |
slateblue :"#6a5acd", |
slategray :"#708090", |
slategrey :"#708090", |
snow :"#fffafa", |
springgreen :"#00ff7f", |
steelblue :"#4682b4", |
tan :"#d2b48c", |
teal :"#008080", |
thistle :"#d8bfd8", |
tomato :"#ff6347", |
turquoise :"#40e0d0", |
violet :"#ee82ee", |
wheat :"#f5deb3", |
white :"#ffffff", |
whitesmoke :"#f5f5f5", |
yellow :"#ffff00", |
yellowgreen :"#9acd32", |
activeBorder :"Active window border.", |
activecaption :"Active window caption.", |
appworkspace :"Background color of multiple document interface.", |
background :"Desktop background.", |
buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", |
buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", |
buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", |
buttontext :"Text on push buttons.", |
captiontext :"Text in caption, size box, and scrollbar arrow box.", |
graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", |
greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", |
highlight :"Item(s) selected in a control.", |
highlighttext :"Text of item(s) selected in a control.", |
inactiveborder :"Inactive window border.", |
inactivecaption :"Inactive window caption.", |
inactivecaptiontext :"Color of text in an inactive caption.", |
infobackground :"Background color for tooltip controls.", |
infotext :"Text color for tooltip controls.", |
menu :"Menu background.", |
menutext :"Text in menus.", |
scrollbar :"Scroll bar gray area.", |
threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", |
threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", |
threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", |
threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", |
threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", |
window :"Window background.", |
windowframe :"Window frame.", |
windowtext :"Text in windows." |
}; |
function Combinator(text, line, col){ |
|
SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); |
this.type = "unknown"; |
if (/^\s+$/.test(text)){ |
this.type = "descendant"; |
} else if (text == ">"){ |
this.type = "child"; |
} else if (text == "+"){ |
this.type = "adjacent-sibling"; |
} else if (text == "~"){ |
this.type = "sibling"; |
} |
|
} |
|
Combinator.prototype = new SyntaxUnit(); |
Combinator.prototype.constructor = Combinator; |
function MediaFeature(name, value){ |
|
SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); |
this.name = name; |
this.value = value; |
} |
|
MediaFeature.prototype = new SyntaxUnit(); |
MediaFeature.prototype.constructor = MediaFeature; |
function MediaQuery(modifier, mediaType, features, line, col){ |
|
SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); |
this.modifier = modifier; |
this.mediaType = mediaType; |
this.features = features; |
|
} |
|
MediaQuery.prototype = new SyntaxUnit(); |
MediaQuery.prototype.constructor = MediaQuery; |
function Parser(options){ |
EventTarget.call(this); |
|
|
this.options = options || {}; |
|
this._tokenStream = null; |
} |
Parser.DEFAULT_TYPE = 0; |
Parser.COMBINATOR_TYPE = 1; |
Parser.MEDIA_FEATURE_TYPE = 2; |
Parser.MEDIA_QUERY_TYPE = 3; |
Parser.PROPERTY_NAME_TYPE = 4; |
Parser.PROPERTY_VALUE_TYPE = 5; |
Parser.PROPERTY_VALUE_PART_TYPE = 6; |
Parser.SELECTOR_TYPE = 7; |
Parser.SELECTOR_PART_TYPE = 8; |
Parser.SELECTOR_SUB_PART_TYPE = 9; |
|
Parser.prototype = function(){ |
|
var proto = new EventTarget(), //new prototype |
prop, |
additions = { |
constructor: Parser, |
DEFAULT_TYPE : 0, |
COMBINATOR_TYPE : 1, |
MEDIA_FEATURE_TYPE : 2, |
MEDIA_QUERY_TYPE : 3, |
PROPERTY_NAME_TYPE : 4, |
PROPERTY_VALUE_TYPE : 5, |
PROPERTY_VALUE_PART_TYPE : 6, |
SELECTOR_TYPE : 7, |
SELECTOR_PART_TYPE : 8, |
SELECTOR_SUB_PART_TYPE : 9, |
|
_stylesheet: function(){ |
|
var tokenStream = this._tokenStream, |
charset = null, |
count, |
token, |
tt; |
|
this.fire("startstylesheet"); |
this._charset(); |
|
this._skipCruft(); |
while (tokenStream.peek() == Tokens.IMPORT_SYM){ |
this._import(); |
this._skipCruft(); |
} |
while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ |
this._namespace(); |
this._skipCruft(); |
} |
tt = tokenStream.peek(); |
while(tt > Tokens.EOF){ |
|
try { |
|
switch(tt){ |
case Tokens.MEDIA_SYM: |
this._media(); |
this._skipCruft(); |
break; |
case Tokens.PAGE_SYM: |
this._page(); |
this._skipCruft(); |
break; |
case Tokens.FONT_FACE_SYM: |
this._font_face(); |
this._skipCruft(); |
break; |
case Tokens.KEYFRAMES_SYM: |
this._keyframes(); |
this._skipCruft(); |
break; |
case Tokens.VIEWPORT_SYM: |
this._viewport(); |
this._skipCruft(); |
break; |
case Tokens.UNKNOWN_SYM: //unknown @ rule |
tokenStream.get(); |
if (!this.options.strict){ |
this.fire({ |
type: "error", |
error: null, |
message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", |
line: tokenStream.LT(0).startLine, |
col: tokenStream.LT(0).startCol |
}); |
count=0; |
while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ |
count++; //keep track of nesting depth |
} |
|
while(count){ |
tokenStream.advance([Tokens.RBRACE]); |
count--; |
} |
|
} else { |
throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); |
} |
break; |
case Tokens.S: |
this._readWhitespace(); |
break; |
default: |
if(!this._ruleset()){ |
switch(tt){ |
case Tokens.CHARSET_SYM: |
token = tokenStream.LT(1); |
this._charset(false); |
throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); |
case Tokens.IMPORT_SYM: |
token = tokenStream.LT(1); |
this._import(false); |
throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); |
case Tokens.NAMESPACE_SYM: |
token = tokenStream.LT(1); |
this._namespace(false); |
throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); |
default: |
tokenStream.get(); //get the last token |
this._unexpectedToken(tokenStream.token()); |
} |
|
} |
} |
} catch(ex) { |
if (ex instanceof SyntaxError && !this.options.strict){ |
this.fire({ |
type: "error", |
error: ex, |
message: ex.message, |
line: ex.line, |
col: ex.col |
}); |
} else { |
throw ex; |
} |
} |
|
tt = tokenStream.peek(); |
} |
|
if (tt != Tokens.EOF){ |
this._unexpectedToken(tokenStream.token()); |
} |
|
this.fire("endstylesheet"); |
}, |
|
_charset: function(emit){ |
var tokenStream = this._tokenStream, |
charset, |
token, |
line, |
col; |
|
if (tokenStream.match(Tokens.CHARSET_SYM)){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this._readWhitespace(); |
tokenStream.mustMatch(Tokens.STRING); |
|
token = tokenStream.token(); |
charset = token.value; |
|
this._readWhitespace(); |
tokenStream.mustMatch(Tokens.SEMICOLON); |
|
if (emit !== false){ |
this.fire({ |
type: "charset", |
charset:charset, |
line: line, |
col: col |
}); |
} |
} |
}, |
|
_import: function(emit){ |
|
var tokenStream = this._tokenStream, |
tt, |
uri, |
importToken, |
mediaList = []; |
tokenStream.mustMatch(Tokens.IMPORT_SYM); |
importToken = tokenStream.token(); |
this._readWhitespace(); |
|
tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); |
uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); |
|
this._readWhitespace(); |
|
mediaList = this._media_query_list(); |
tokenStream.mustMatch(Tokens.SEMICOLON); |
this._readWhitespace(); |
|
if (emit !== false){ |
this.fire({ |
type: "import", |
uri: uri, |
media: mediaList, |
line: importToken.startLine, |
col: importToken.startCol |
}); |
} |
|
}, |
|
_namespace: function(emit){ |
|
var tokenStream = this._tokenStream, |
line, |
col, |
prefix, |
uri; |
tokenStream.mustMatch(Tokens.NAMESPACE_SYM); |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
this._readWhitespace(); |
if (tokenStream.match(Tokens.IDENT)){ |
prefix = tokenStream.token().value; |
this._readWhitespace(); |
} |
|
tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); |
uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); |
|
this._readWhitespace(); |
tokenStream.mustMatch(Tokens.SEMICOLON); |
this._readWhitespace(); |
|
if (emit !== false){ |
this.fire({ |
type: "namespace", |
prefix: prefix, |
uri: uri, |
line: line, |
col: col |
}); |
} |
|
}, |
|
_media: function(){ |
var tokenStream = this._tokenStream, |
line, |
col, |
mediaList;// = []; |
tokenStream.mustMatch(Tokens.MEDIA_SYM); |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this._readWhitespace(); |
|
mediaList = this._media_query_list(); |
|
tokenStream.mustMatch(Tokens.LBRACE); |
this._readWhitespace(); |
|
this.fire({ |
type: "startmedia", |
media: mediaList, |
line: line, |
col: col |
}); |
|
while(true) { |
if (tokenStream.peek() == Tokens.PAGE_SYM){ |
this._page(); |
} else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ |
this._font_face(); |
} else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ |
this._viewport(); |
} else if (!this._ruleset()){ |
break; |
} |
} |
|
tokenStream.mustMatch(Tokens.RBRACE); |
this._readWhitespace(); |
|
this.fire({ |
type: "endmedia", |
media: mediaList, |
line: line, |
col: col |
}); |
}, |
_media_query_list: function(){ |
var tokenStream = this._tokenStream, |
mediaList = []; |
|
|
this._readWhitespace(); |
|
if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ |
mediaList.push(this._media_query()); |
} |
|
while(tokenStream.match(Tokens.COMMA)){ |
this._readWhitespace(); |
mediaList.push(this._media_query()); |
} |
|
return mediaList; |
}, |
_media_query: function(){ |
var tokenStream = this._tokenStream, |
type = null, |
ident = null, |
token = null, |
expressions = []; |
|
if (tokenStream.match(Tokens.IDENT)){ |
ident = tokenStream.token().value.toLowerCase(); |
if (ident != "only" && ident != "not"){ |
tokenStream.unget(); |
ident = null; |
} else { |
token = tokenStream.token(); |
} |
} |
|
this._readWhitespace(); |
|
if (tokenStream.peek() == Tokens.IDENT){ |
type = this._media_type(); |
if (token === null){ |
token = tokenStream.token(); |
} |
} else if (tokenStream.peek() == Tokens.LPAREN){ |
if (token === null){ |
token = tokenStream.LT(1); |
} |
expressions.push(this._media_expression()); |
} |
|
if (type === null && expressions.length === 0){ |
return null; |
} else { |
this._readWhitespace(); |
while (tokenStream.match(Tokens.IDENT)){ |
if (tokenStream.token().value.toLowerCase() != "and"){ |
this._unexpectedToken(tokenStream.token()); |
} |
|
this._readWhitespace(); |
expressions.push(this._media_expression()); |
} |
} |
|
return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); |
}, |
_media_type: function(){ |
return this._media_feature(); |
}, |
_media_expression: function(){ |
var tokenStream = this._tokenStream, |
feature = null, |
token, |
expression = null; |
|
tokenStream.mustMatch(Tokens.LPAREN); |
|
feature = this._media_feature(); |
this._readWhitespace(); |
|
if (tokenStream.match(Tokens.COLON)){ |
this._readWhitespace(); |
token = tokenStream.LT(1); |
expression = this._expression(); |
} |
|
tokenStream.mustMatch(Tokens.RPAREN); |
this._readWhitespace(); |
|
return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); |
}, |
_media_feature: function(){ |
var tokenStream = this._tokenStream; |
|
tokenStream.mustMatch(Tokens.IDENT); |
|
return SyntaxUnit.fromToken(tokenStream.token()); |
}, |
_page: function(){ |
var tokenStream = this._tokenStream, |
line, |
col, |
identifier = null, |
pseudoPage = null; |
tokenStream.mustMatch(Tokens.PAGE_SYM); |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this._readWhitespace(); |
|
if (tokenStream.match(Tokens.IDENT)){ |
identifier = tokenStream.token().value; |
if (identifier.toLowerCase() === "auto"){ |
this._unexpectedToken(tokenStream.token()); |
} |
} |
if (tokenStream.peek() == Tokens.COLON){ |
pseudoPage = this._pseudo_page(); |
} |
|
this._readWhitespace(); |
|
this.fire({ |
type: "startpage", |
id: identifier, |
pseudo: pseudoPage, |
line: line, |
col: col |
}); |
|
this._readDeclarations(true, true); |
|
this.fire({ |
type: "endpage", |
id: identifier, |
pseudo: pseudoPage, |
line: line, |
col: col |
}); |
|
}, |
_margin: function(){ |
var tokenStream = this._tokenStream, |
line, |
col, |
marginSym = this._margin_sym(); |
|
if (marginSym){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this.fire({ |
type: "startpagemargin", |
margin: marginSym, |
line: line, |
col: col |
}); |
|
this._readDeclarations(true); |
|
this.fire({ |
type: "endpagemargin", |
margin: marginSym, |
line: line, |
col: col |
}); |
return true; |
} else { |
return false; |
} |
}, |
_margin_sym: function(){ |
|
var tokenStream = this._tokenStream; |
|
if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, |
Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, |
Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, |
Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, |
Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, |
Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, |
Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) |
{ |
return SyntaxUnit.fromToken(tokenStream.token()); |
} else { |
return null; |
} |
|
}, |
|
_pseudo_page: function(){ |
|
var tokenStream = this._tokenStream; |
|
tokenStream.mustMatch(Tokens.COLON); |
tokenStream.mustMatch(Tokens.IDENT); |
|
return tokenStream.token().value; |
}, |
|
_font_face: function(){ |
var tokenStream = this._tokenStream, |
line, |
col; |
tokenStream.mustMatch(Tokens.FONT_FACE_SYM); |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this._readWhitespace(); |
|
this.fire({ |
type: "startfontface", |
line: line, |
col: col |
}); |
|
this._readDeclarations(true); |
|
this.fire({ |
type: "endfontface", |
line: line, |
col: col |
}); |
}, |
|
_viewport: function(){ |
var tokenStream = this._tokenStream, |
line, |
col; |
|
tokenStream.mustMatch(Tokens.VIEWPORT_SYM); |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
|
this._readWhitespace(); |
|
this.fire({ |
type: "startviewport", |
line: line, |
col: col |
}); |
|
this._readDeclarations(true); |
|
this.fire({ |
type: "endviewport", |
line: line, |
col: col |
}); |
|
}, |
|
_operator: function(inFunction){ |
|
var tokenStream = this._tokenStream, |
token = null; |
|
if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || |
(inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ |
token = tokenStream.token(); |
this._readWhitespace(); |
} |
return token ? PropertyValuePart.fromToken(token) : null; |
|
}, |
|
_combinator: function(){ |
|
var tokenStream = this._tokenStream, |
value = null, |
token; |
|
if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ |
token = tokenStream.token(); |
value = new Combinator(token.value, token.startLine, token.startCol); |
this._readWhitespace(); |
} |
|
return value; |
}, |
|
_unary_operator: function(){ |
|
var tokenStream = this._tokenStream; |
|
if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ |
return tokenStream.token().value; |
} else { |
return null; |
} |
}, |
|
_property: function(){ |
|
var tokenStream = this._tokenStream, |
value = null, |
hack = null, |
tokenValue, |
token, |
line, |
col; |
if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ |
tokenStream.get(); |
token = tokenStream.token(); |
hack = token.value; |
line = token.startLine; |
col = token.startCol; |
} |
|
if(tokenStream.match(Tokens.IDENT)){ |
token = tokenStream.token(); |
tokenValue = token.value; |
if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ |
hack = "_"; |
tokenValue = tokenValue.substring(1); |
} |
|
value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); |
this._readWhitespace(); |
} |
|
return value; |
}, |
_ruleset: function(){ |
|
var tokenStream = this._tokenStream, |
tt, |
selectors; |
try { |
selectors = this._selectors_group(); |
} catch (ex){ |
if (ex instanceof SyntaxError && !this.options.strict){ |
this.fire({ |
type: "error", |
error: ex, |
message: ex.message, |
line: ex.line, |
col: ex.col |
}); |
tt = tokenStream.advance([Tokens.RBRACE]); |
if (tt == Tokens.RBRACE){ |
} else { |
throw ex; |
} |
|
} else { |
throw ex; |
} |
return true; |
} |
if (selectors){ |
|
this.fire({ |
type: "startrule", |
selectors: selectors, |
line: selectors[0].line, |
col: selectors[0].col |
}); |
|
this._readDeclarations(true); |
|
this.fire({ |
type: "endrule", |
selectors: selectors, |
line: selectors[0].line, |
col: selectors[0].col |
}); |
|
} |
|
return selectors; |
|
}, |
_selectors_group: function(){ |
var tokenStream = this._tokenStream, |
selectors = [], |
selector; |
|
selector = this._selector(); |
if (selector !== null){ |
|
selectors.push(selector); |
while(tokenStream.match(Tokens.COMMA)){ |
this._readWhitespace(); |
selector = this._selector(); |
if (selector !== null){ |
selectors.push(selector); |
} else { |
this._unexpectedToken(tokenStream.LT(1)); |
} |
} |
} |
|
return selectors.length ? selectors : null; |
}, |
_selector: function(){ |
|
var tokenStream = this._tokenStream, |
selector = [], |
nextSelector = null, |
combinator = null, |
ws = null; |
nextSelector = this._simple_selector_sequence(); |
if (nextSelector === null){ |
return null; |
} |
|
selector.push(nextSelector); |
|
do { |
combinator = this._combinator(); |
|
if (combinator !== null){ |
selector.push(combinator); |
nextSelector = this._simple_selector_sequence(); |
if (nextSelector === null){ |
this._unexpectedToken(tokenStream.LT(1)); |
} else { |
selector.push(nextSelector); |
} |
} else { |
if (this._readWhitespace()){ |
ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); |
combinator = this._combinator(); |
nextSelector = this._simple_selector_sequence(); |
if (nextSelector === null){ |
if (combinator !== null){ |
this._unexpectedToken(tokenStream.LT(1)); |
} |
} else { |
|
if (combinator !== null){ |
selector.push(combinator); |
} else { |
selector.push(ws); |
} |
|
selector.push(nextSelector); |
} |
} else { |
break; |
} |
|
} |
} while(true); |
|
return new Selector(selector, selector[0].line, selector[0].col); |
}, |
_simple_selector_sequence: function(){ |
|
var tokenStream = this._tokenStream, |
elementName = null, |
modifiers = [], |
selectorText= "", |
components = [ |
function(){ |
return tokenStream.match(Tokens.HASH) ? |
new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : |
null; |
}, |
this._class, |
this._attrib, |
this._pseudo, |
this._negation |
], |
i = 0, |
len = components.length, |
component = null, |
found = false, |
line, |
col; |
line = tokenStream.LT(1).startLine; |
col = tokenStream.LT(1).startCol; |
|
elementName = this._type_selector(); |
if (!elementName){ |
elementName = this._universal(); |
} |
|
if (elementName !== null){ |
selectorText += elementName; |
} |
|
while(true){ |
if (tokenStream.peek() === Tokens.S){ |
break; |
} |
while(i < len && component === null){ |
component = components[i++].call(this); |
} |
|
if (component === null){ |
if (selectorText === ""){ |
return null; |
} else { |
break; |
} |
} else { |
i = 0; |
modifiers.push(component); |
selectorText += component.toString(); |
component = null; |
} |
} |
|
|
return selectorText !== "" ? |
new SelectorPart(elementName, modifiers, selectorText, line, col) : |
null; |
}, |
_type_selector: function(){ |
|
var tokenStream = this._tokenStream, |
ns = this._namespace_prefix(), |
elementName = this._element_name(); |
|
if (!elementName){ |
if (ns){ |
tokenStream.unget(); |
if (ns.length > 1){ |
tokenStream.unget(); |
} |
} |
|
return null; |
} else { |
if (ns){ |
elementName.text = ns + elementName.text; |
elementName.col -= ns.length; |
} |
return elementName; |
} |
}, |
_class: function(){ |
|
var tokenStream = this._tokenStream, |
token; |
|
if (tokenStream.match(Tokens.DOT)){ |
tokenStream.mustMatch(Tokens.IDENT); |
token = tokenStream.token(); |
return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); |
} else { |
return null; |
} |
|
}, |
_element_name: function(){ |
|
var tokenStream = this._tokenStream, |
token; |
|
if (tokenStream.match(Tokens.IDENT)){ |
token = tokenStream.token(); |
return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); |
|
} else { |
return null; |
} |
}, |
_namespace_prefix: function(){ |
var tokenStream = this._tokenStream, |
value = ""; |
if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ |
|
if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ |
value += tokenStream.token().value; |
} |
|
tokenStream.mustMatch(Tokens.PIPE); |
value += "|"; |
|
} |
|
return value.length ? value : null; |
}, |
_universal: function(){ |
var tokenStream = this._tokenStream, |
value = "", |
ns; |
|
ns = this._namespace_prefix(); |
if(ns){ |
value += ns; |
} |
|
if(tokenStream.match(Tokens.STAR)){ |
value += "*"; |
} |
|
return value.length ? value : null; |
|
}, |
_attrib: function(){ |
|
var tokenStream = this._tokenStream, |
value = null, |
ns, |
token; |
|
if (tokenStream.match(Tokens.LBRACKET)){ |
token = tokenStream.token(); |
value = token.value; |
value += this._readWhitespace(); |
|
ns = this._namespace_prefix(); |
|
if (ns){ |
value += ns; |
} |
|
tokenStream.mustMatch(Tokens.IDENT); |
value += tokenStream.token().value; |
value += this._readWhitespace(); |
|
if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, |
Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ |
|
value += tokenStream.token().value; |
value += this._readWhitespace(); |
|
tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); |
value += tokenStream.token().value; |
value += this._readWhitespace(); |
} |
|
tokenStream.mustMatch(Tokens.RBRACKET); |
|
return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); |
} else { |
return null; |
} |
}, |
_pseudo: function(){ |
|
var tokenStream = this._tokenStream, |
pseudo = null, |
colons = ":", |
line, |
col; |
|
if (tokenStream.match(Tokens.COLON)){ |
|
if (tokenStream.match(Tokens.COLON)){ |
colons += ":"; |
} |
|
if (tokenStream.match(Tokens.IDENT)){ |
pseudo = tokenStream.token().value; |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol - colons.length; |
} else if (tokenStream.peek() == Tokens.FUNCTION){ |
line = tokenStream.LT(1).startLine; |
col = tokenStream.LT(1).startCol - colons.length; |
pseudo = this._functional_pseudo(); |
} |
|
if (pseudo){ |
pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); |
} |
} |
|
return pseudo; |
}, |
_functional_pseudo: function(){ |
|
var tokenStream = this._tokenStream, |
value = null; |
|
if(tokenStream.match(Tokens.FUNCTION)){ |
value = tokenStream.token().value; |
value += this._readWhitespace(); |
value += this._expression(); |
tokenStream.mustMatch(Tokens.RPAREN); |
value += ")"; |
} |
|
return value; |
}, |
_expression: function(){ |
|
var tokenStream = this._tokenStream, |
value = ""; |
|
while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, |
Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, |
Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, |
Tokens.RESOLUTION, Tokens.SLASH])){ |
|
value += tokenStream.token().value; |
value += this._readWhitespace(); |
} |
|
return value.length ? value : null; |
|
}, |
_negation: function(){ |
|
var tokenStream = this._tokenStream, |
line, |
col, |
value = "", |
arg, |
subpart = null; |
|
if (tokenStream.match(Tokens.NOT)){ |
value = tokenStream.token().value; |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
value += this._readWhitespace(); |
arg = this._negation_arg(); |
value += arg; |
value += this._readWhitespace(); |
tokenStream.match(Tokens.RPAREN); |
value += tokenStream.token().value; |
|
subpart = new SelectorSubPart(value, "not", line, col); |
subpart.args.push(arg); |
} |
|
return subpart; |
}, |
_negation_arg: function(){ |
|
var tokenStream = this._tokenStream, |
args = [ |
this._type_selector, |
this._universal, |
function(){ |
return tokenStream.match(Tokens.HASH) ? |
new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : |
null; |
}, |
this._class, |
this._attrib, |
this._pseudo |
], |
arg = null, |
i = 0, |
len = args.length, |
elementName, |
line, |
col, |
part; |
|
line = tokenStream.LT(1).startLine; |
col = tokenStream.LT(1).startCol; |
|
while(i < len && arg === null){ |
|
arg = args[i].call(this); |
i++; |
} |
if (arg === null){ |
this._unexpectedToken(tokenStream.LT(1)); |
} |
if (arg.type == "elementName"){ |
part = new SelectorPart(arg, [], arg.toString(), line, col); |
} else { |
part = new SelectorPart(null, [arg], arg.toString(), line, col); |
} |
|
return part; |
}, |
|
_declaration: function(){ |
|
var tokenStream = this._tokenStream, |
property = null, |
expr = null, |
prio = null, |
error = null, |
invalid = null, |
propertyName= ""; |
|
property = this._property(); |
if (property !== null){ |
|
tokenStream.mustMatch(Tokens.COLON); |
this._readWhitespace(); |
|
expr = this._expr(); |
if (!expr || expr.length === 0){ |
this._unexpectedToken(tokenStream.LT(1)); |
} |
|
prio = this._prio(); |
propertyName = property.toString(); |
if (this.options.starHack && property.hack == "*" || |
this.options.underscoreHack && property.hack == "_") { |
|
propertyName = property.text; |
} |
|
try { |
this._validateProperty(propertyName, expr); |
} catch (ex) { |
invalid = ex; |
} |
|
this.fire({ |
type: "property", |
property: property, |
value: expr, |
important: prio, |
line: property.line, |
col: property.col, |
invalid: invalid |
}); |
|
return true; |
} else { |
return false; |
} |
}, |
|
_prio: function(){ |
|
var tokenStream = this._tokenStream, |
result = tokenStream.match(Tokens.IMPORTANT_SYM); |
|
this._readWhitespace(); |
return result; |
}, |
|
_expr: function(inFunction){ |
|
var tokenStream = this._tokenStream, |
values = [], |
value = null, |
operator = null; |
|
value = this._term(inFunction); |
if (value !== null){ |
|
values.push(value); |
|
do { |
operator = this._operator(inFunction); |
if (operator){ |
values.push(operator); |
} /*else { |
values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); |
valueParts = []; |
}*/ |
|
value = this._term(inFunction); |
|
if (value === null){ |
break; |
} else { |
values.push(value); |
} |
} while(true); |
} |
|
return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; |
}, |
|
_term: function(inFunction){ |
|
var tokenStream = this._tokenStream, |
unary = null, |
value = null, |
endChar = null, |
token, |
line, |
col; |
unary = this._unary_operator(); |
if (unary !== null){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
} |
if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ |
|
value = this._ie_function(); |
if (unary === null){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
} |
} else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ |
|
token = tokenStream.token(); |
endChar = token.endChar; |
value = token.value + this._expr(inFunction).text; |
if (unary === null){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
} |
tokenStream.mustMatch(Tokens.type(endChar)); |
value += endChar; |
this._readWhitespace(); |
} else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, |
Tokens.ANGLE, Tokens.TIME, |
Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ |
|
value = tokenStream.token().value; |
if (unary === null){ |
line = tokenStream.token().startLine; |
col = tokenStream.token().startCol; |
} |
this._readWhitespace(); |
} else { |
token = this._hexcolor(); |
if (token === null){ |
if (unary === null){ |
line = tokenStream.LT(1).startLine; |
col = tokenStream.LT(1).startCol; |
} |
if (value === null){ |
if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ |
value = this._ie_function(); |
} else { |
value = this._function(); |
} |
} |
|
} else { |
value = token.value; |
if (unary === null){ |
line = token.startLine; |
col = token.startCol; |
} |
} |
|
} |
|
return value !== null ? |
new PropertyValuePart(unary !== null ? unary + value : value, line, col) : |
null; |
|
}, |
|
_function: function(){ |
|
var tokenStream = this._tokenStream, |
functionText = null, |
expr = null, |
lt; |
|
if (tokenStream.match(Tokens.FUNCTION)){ |
functionText = tokenStream.token().value; |
this._readWhitespace(); |
expr = this._expr(true); |
functionText += expr; |
if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ |
do { |
|
if (this._readWhitespace()){ |
functionText += tokenStream.token().value; |
} |
if (tokenStream.LA(0) == Tokens.COMMA){ |
functionText += tokenStream.token().value; |
} |
|
tokenStream.match(Tokens.IDENT); |
functionText += tokenStream.token().value; |
|
tokenStream.match(Tokens.EQUALS); |
functionText += tokenStream.token().value; |
lt = tokenStream.peek(); |
while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ |
tokenStream.get(); |
functionText += tokenStream.token().value; |
lt = tokenStream.peek(); |
} |
} while(tokenStream.match([Tokens.COMMA, Tokens.S])); |
} |
|
tokenStream.match(Tokens.RPAREN); |
functionText += ")"; |
this._readWhitespace(); |
} |
|
return functionText; |
}, |
|
_ie_function: function(){ |
|
var tokenStream = this._tokenStream, |
functionText = null, |
expr = null, |
lt; |
if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ |
functionText = tokenStream.token().value; |
|
do { |
|
if (this._readWhitespace()){ |
functionText += tokenStream.token().value; |
} |
if (tokenStream.LA(0) == Tokens.COMMA){ |
functionText += tokenStream.token().value; |
} |
|
tokenStream.match(Tokens.IDENT); |
functionText += tokenStream.token().value; |
|
tokenStream.match(Tokens.EQUALS); |
functionText += tokenStream.token().value; |
lt = tokenStream.peek(); |
while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ |
tokenStream.get(); |
functionText += tokenStream.token().value; |
lt = tokenStream.peek(); |
} |
} while(tokenStream.match([Tokens.COMMA, Tokens.S])); |
|
tokenStream.match(Tokens.RPAREN); |
functionText += ")"; |
this._readWhitespace(); |
} |
|
return functionText; |
}, |
|
_hexcolor: function(){ |
|
var tokenStream = this._tokenStream, |
token = null, |
color; |
|
if(tokenStream.match(Tokens.HASH)){ |
|
token = tokenStream.token(); |
color = token.value; |
if (!/#[a-f0-9]{3,6}/i.test(color)){ |
throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); |
} |
this._readWhitespace(); |
} |
|
return token; |
}, |
|
_keyframes: function(){ |
var tokenStream = this._tokenStream, |
token, |
tt, |
name, |
prefix = ""; |
|
tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); |
token = tokenStream.token(); |
if (/^@\-([^\-]+)\-/.test(token.value)) { |
prefix = RegExp.$1; |
} |
|
this._readWhitespace(); |
name = this._keyframe_name(); |
|
this._readWhitespace(); |
tokenStream.mustMatch(Tokens.LBRACE); |
|
this.fire({ |
type: "startkeyframes", |
name: name, |
prefix: prefix, |
line: token.startLine, |
col: token.startCol |
}); |
|
this._readWhitespace(); |
tt = tokenStream.peek(); |
while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { |
this._keyframe_rule(); |
this._readWhitespace(); |
tt = tokenStream.peek(); |
} |
|
this.fire({ |
type: "endkeyframes", |
name: name, |
prefix: prefix, |
line: token.startLine, |
col: token.startCol |
}); |
|
this._readWhitespace(); |
tokenStream.mustMatch(Tokens.RBRACE); |
|
}, |
|
_keyframe_name: function(){ |
var tokenStream = this._tokenStream, |
token; |
|
tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); |
return SyntaxUnit.fromToken(tokenStream.token()); |
}, |
|
_keyframe_rule: function(){ |
var tokenStream = this._tokenStream, |
token, |
keyList = this._key_list(); |
|
this.fire({ |
type: "startkeyframerule", |
keys: keyList, |
line: keyList[0].line, |
col: keyList[0].col |
}); |
|
this._readDeclarations(true); |
|
this.fire({ |
type: "endkeyframerule", |
keys: keyList, |
line: keyList[0].line, |
col: keyList[0].col |
}); |
|
}, |
|
_key_list: function(){ |
var tokenStream = this._tokenStream, |
token, |
key, |
keyList = []; |
keyList.push(this._key()); |
|
this._readWhitespace(); |
|
while(tokenStream.match(Tokens.COMMA)){ |
this._readWhitespace(); |
keyList.push(this._key()); |
this._readWhitespace(); |
} |
|
return keyList; |
}, |
|
_key: function(){ |
|
var tokenStream = this._tokenStream, |
token; |
|
if (tokenStream.match(Tokens.PERCENTAGE)){ |
return SyntaxUnit.fromToken(tokenStream.token()); |
} else if (tokenStream.match(Tokens.IDENT)){ |
token = tokenStream.token(); |
|
if (/from|to/i.test(token.value)){ |
return SyntaxUnit.fromToken(token); |
} |
|
tokenStream.unget(); |
} |
this._unexpectedToken(tokenStream.LT(1)); |
}, |
_skipCruft: function(){ |
while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ |
} |
}, |
_readDeclarations: function(checkStart, readMargins){ |
var tokenStream = this._tokenStream, |
tt; |
|
|
this._readWhitespace(); |
|
if (checkStart){ |
tokenStream.mustMatch(Tokens.LBRACE); |
} |
|
this._readWhitespace(); |
|
try { |
|
while(true){ |
|
if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ |
} else if (this._declaration()){ |
if (!tokenStream.match(Tokens.SEMICOLON)){ |
break; |
} |
} else { |
break; |
} |
this._readWhitespace(); |
} |
|
tokenStream.mustMatch(Tokens.RBRACE); |
this._readWhitespace(); |
|
} catch (ex) { |
if (ex instanceof SyntaxError && !this.options.strict){ |
this.fire({ |
type: "error", |
error: ex, |
message: ex.message, |
line: ex.line, |
col: ex.col |
}); |
tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); |
if (tt == Tokens.SEMICOLON){ |
this._readDeclarations(false, readMargins); |
} else if (tt != Tokens.RBRACE){ |
throw ex; |
} |
|
} else { |
throw ex; |
} |
} |
|
}, |
_readWhitespace: function(){ |
|
var tokenStream = this._tokenStream, |
ws = ""; |
|
while(tokenStream.match(Tokens.S)){ |
ws += tokenStream.token().value; |
} |
|
return ws; |
}, |
_unexpectedToken: function(token){ |
throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); |
}, |
_verifyEnd: function(){ |
if (this._tokenStream.LA(1) != Tokens.EOF){ |
this._unexpectedToken(this._tokenStream.LT(1)); |
} |
}, |
_validateProperty: function(property, value){ |
Validation.validate(property, value); |
}, |
|
parse: function(input){ |
this._tokenStream = new TokenStream(input, Tokens); |
this._stylesheet(); |
}, |
|
parseStyleSheet: function(input){ |
return this.parse(input); |
}, |
|
parseMediaQuery: function(input){ |
this._tokenStream = new TokenStream(input, Tokens); |
var result = this._media_query(); |
this._verifyEnd(); |
return result; |
}, |
parsePropertyValue: function(input){ |
|
this._tokenStream = new TokenStream(input, Tokens); |
this._readWhitespace(); |
|
var result = this._expr(); |
this._readWhitespace(); |
this._verifyEnd(); |
return result; |
}, |
parseRule: function(input){ |
this._tokenStream = new TokenStream(input, Tokens); |
this._readWhitespace(); |
|
var result = this._ruleset(); |
this._readWhitespace(); |
this._verifyEnd(); |
return result; |
}, |
parseSelector: function(input){ |
|
this._tokenStream = new TokenStream(input, Tokens); |
this._readWhitespace(); |
|
var result = this._selector(); |
this._readWhitespace(); |
this._verifyEnd(); |
return result; |
}, |
parseStyleAttribute: function(input){ |
input += "}"; // for error recovery in _readDeclarations() |
this._tokenStream = new TokenStream(input, Tokens); |
this._readDeclarations(); |
} |
}; |
for (prop in additions){ |
if (additions.hasOwnProperty(prop)){ |
proto[prop] = additions[prop]; |
} |
} |
|
return proto; |
}(); |
var Properties = { |
"align-items" : "flex-start | flex-end | center | baseline | stretch", |
"align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", |
"align-self" : "auto | flex-start | flex-end | center | baseline | stretch", |
"-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", |
"-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", |
"-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", |
"alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>", |
"alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", |
"animation" : 1, |
"animation-delay" : { multi: "<time>", comma: true }, |
"animation-direction" : { multi: "normal | 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 """; |
case "&": |
return "&"; |
case "<": |
return "<"; |
case ">": |
return ">"; |
} |
}); |
}; |
|
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, "&").replace(/</g, "<").replace(/>/g, ">"); |
}; |
|
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, "<").replace(/>/g, ">"); |
|
}; |
|
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, "&").replace(/</g, "<").replace(/>/g, ">"); |
}; |
|
if (messages.length > 0) { |
|
output.push("<file name=\""+filename+"\">"); |
CSSLint.Util.forEach(messages, function (message) { |
if (message.rollup) { |
output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); |
} else { |
output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" + |
" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>"); |
} |
}); |
output.push("</file>"); |
} |
|
return output.join(""); |
} |
}); |
|
CSSLint.addFormatter({ |
id: "text", |
name: "Plain Text", |
startFormat: function() { |
return ""; |
}, |
endFormat: function() { |
return ""; |
}, |
formatResults: function(results, filename, options) { |
var messages = results.messages, |
output = ""; |
options = options || {}; |
|
if (messages.length === 0) { |
return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + "."; |
} |
|
output = "\n\ncsslint: There "; |
if (messages.length === 1) { |
output += "is 1 problem"; |
} else { |
output += "are " + messages.length + " problems"; |
} |
output += " in " + filename + "."; |
|
var pos = filename.lastIndexOf("/"), |
shortFilename = filename; |
|
if (pos === -1){ |
pos = filename.lastIndexOf("\\"); |
} |
if (pos > -1){ |
shortFilename = filename.substring(pos+1); |
} |
|
CSSLint.Util.forEach(messages, function (message, i) { |
output = output + "\n\n" + shortFilename; |
if (message.rollup) { |
output += "\n" + (i+1) + ": " + message.type; |
output += "\n" + message.message; |
} else { |
output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col; |
output += "\n" + message.message; |
output += "\n" + message.evidence; |
} |
}); |
|
return output; |
} |
}); |
|
module.exports.CSSLint = CSSLint; |
|
}); |
|
ace.define("ace/mode/css_worker",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/worker/mirror","ace/mode/css/csslint"], function(require, exports, module) { |
"use strict"; |
|
var oop = require("../lib/oop"); |
var lang = require("../lib/lang"); |
var Mirror = require("../worker/mirror").Mirror; |
var CSSLint = require("./css/csslint").CSSLint; |
|
var Worker = exports.Worker = function(sender) { |
Mirror.call(this, sender); |
this.setTimeout(400); |
this.ruleset = null; |
this.setDisabledRules("ids|order-alphabetical"); |
this.setInfoRules( |
"adjoining-classes|qualified-headings|zero-units|gradients|" + |
"import|outline-none|vendor-prefix" |
); |
}; |
|
oop.inherits(Worker, Mirror); |
|
(function() { |
this.setInfoRules = function(ruleNames) { |
if (typeof ruleNames == "string") |
ruleNames = ruleNames.split("|"); |
this.infoRules = lang.arrayToMap(ruleNames); |
this.doc.getValue() && this.deferredUpdate.schedule(100); |
}; |
|
this.setDisabledRules = function(ruleNames) { |
if (!ruleNames) { |
this.ruleset = null; |
} else { |
if (typeof ruleNames == "string") |
ruleNames = ruleNames.split("|"); |
var all = {}; |
|
CSSLint.getRules().forEach(function(x){ |
all[x.id] = true; |
}); |
ruleNames.forEach(function(x) { |
delete all[x]; |
}); |
|
this.ruleset = all; |
} |
this.doc.getValue() && this.deferredUpdate.schedule(100); |
}; |
|
this.onUpdate = function() { |
var value = this.doc.getValue(); |
if (!value) |
return this.sender.emit("annotate", []); |
var infoRules = this.infoRules; |
|
var result = CSSLint.verify(value, this.ruleset); |
this.sender.emit("annotate", result.messages.map(function(msg) { |
return { |
row: msg.line - 1, |
column: msg.col - 1, |
text: msg.message, |
type: infoRules[msg.rule.id] ? "info" : msg.type, |
rule: msg.rule.name |
} |
})); |
}; |
|
}).call(Worker.prototype); |
|
}); |
|
ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { |
|
function Empty() {} |
|
if (!Function.prototype.bind) { |
Function.prototype.bind = function bind(that) { // .length is 1 |
var target = this; |
if (typeof target != "function") { |
throw new TypeError("Function.prototype.bind called on incompatible " + target); |
} |
var args = slice.call(arguments, 1); // for normal call |
var bound = function () { |
|
if (this instanceof bound) { |
|
var result = target.apply( |
this, |
args.concat(slice.call(arguments)) |
); |
if (Object(result) === result) { |
return result; |
} |
return this; |
|
} else { |
return target.apply( |
that, |
args.concat(slice.call(arguments)) |
); |
|
} |
|
}; |
if(target.prototype) { |
Empty.prototype = target.prototype; |
bound.prototype = new Empty(); |
Empty.prototype = null; |
} |
return bound; |
}; |
} |
var call = Function.prototype.call; |
var prototypeOfArray = Array.prototype; |
var prototypeOfObject = Object.prototype; |
var slice = prototypeOfArray.slice; |
var _toString = call.bind(prototypeOfObject.toString); |
var owns = call.bind(prototypeOfObject.hasOwnProperty); |
var defineGetter; |
var defineSetter; |
var lookupGetter; |
var lookupSetter; |
var supportsAccessors; |
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { |
defineGetter = call.bind(prototypeOfObject.__defineGetter__); |
defineSetter = call.bind(prototypeOfObject.__defineSetter__); |
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); |
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); |
} |
if ([1,2].splice(0).length != 2) { |
if(function() { // test IE < 9 to splice bug - see issue #138 |
function makeArray(l) { |
var a = new Array(l+2); |
a[0] = a[1] = 0; |
return a; |
} |
var array = [], lengthBefore; |
|
array.splice.apply(array, makeArray(20)); |
array.splice.apply(array, makeArray(26)); |
|
lengthBefore = array.length; //46 |
array.splice(5, 0, "XXX"); // add one element |
|
lengthBefore + 1 == array.length |
|
if (lengthBefore + 1 == array.length) { |
return true;// has right splice implementation without bugs |
} |
}()) {//IE 6/7 |
var array_splice = Array.prototype.splice; |
Array.prototype.splice = function(start, deleteCount) { |
if (!arguments.length) { |
return []; |
} else { |
return array_splice.apply(this, [ |
start === void 0 ? 0 : start, |
deleteCount === void 0 ? (this.length - start) : deleteCount |
].concat(slice.call(arguments, 2))) |
} |
}; |
} else {//IE8 |
Array.prototype.splice = function(pos, removeCount){ |
var length = this.length; |
if (pos > 0) { |
if (pos > length) |
pos = length; |
} else if (pos == void 0) { |
pos = 0; |
} else if (pos < 0) { |
pos = Math.max(length + pos, 0); |
} |
|
if (!(pos+removeCount < length)) |
removeCount = length - pos; |
|
var removed = this.slice(pos, pos+removeCount); |
var insert = slice.call(arguments, 2); |
var add = insert.length; |
if (pos === length) { |
if (add) { |
this.push.apply(this, insert); |
} |
} else { |
var remove = Math.min(removeCount, length - pos); |
var tailOldPos = pos + remove; |
var tailNewPos = tailOldPos + add - remove; |
var tailCount = length - tailOldPos; |
var lengthAfterRemove = length - remove; |
|
if (tailNewPos < tailOldPos) { // case A |
for (var i = 0; i < tailCount; ++i) { |
this[tailNewPos+i] = this[tailOldPos+i]; |
} |
} else if (tailNewPos > tailOldPos) { // case B |
for (i = tailCount; i--; ) { |
this[tailNewPos+i] = this[tailOldPos+i]; |
} |
} // else, add == remove (nothing to do) |
|
if (add && pos === lengthAfterRemove) { |
this.length = lengthAfterRemove; // truncate array |
this.push.apply(this, insert); |
} else { |
this.length = lengthAfterRemove + add; // reserves space |
for (i = 0; i < add; ++i) { |
this[pos+i] = insert[i]; |
} |
} |
} |
return removed; |
}; |
} |
} |
if (!Array.isArray) { |
Array.isArray = function isArray(obj) { |
return _toString(obj) == "[object Array]"; |
}; |
} |
var boxedString = Object("a"), |
splitString = boxedString[0] != "a" || !(0 in boxedString); |
|
if (!Array.prototype.forEach) { |
Array.prototype.forEach = function forEach(fun /*, thisp*/) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
thisp = arguments[1], |
i = -1, |
length = self.length >>> 0; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(); // TODO message |
} |
|
while (++i < length) { |
if (i in self) { |
fun.call(thisp, self[i], i, object); |
} |
} |
}; |
} |
if (!Array.prototype.map) { |
Array.prototype.map = function map(fun /*, thisp*/) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0, |
result = Array(length), |
thisp = arguments[1]; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
|
for (var i = 0; i < length; i++) { |
if (i in self) |
result[i] = fun.call(thisp, self[i], i, object); |
} |
return result; |
}; |
} |
if (!Array.prototype.filter) { |
Array.prototype.filter = function filter(fun /*, thisp */) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0, |
result = [], |
value, |
thisp = arguments[1]; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
|
for (var i = 0; i < length; i++) { |
if (i in self) { |
value = self[i]; |
if (fun.call(thisp, value, i, object)) { |
result.push(value); |
} |
} |
} |
return result; |
}; |
} |
if (!Array.prototype.every) { |
Array.prototype.every = function every(fun /*, thisp */) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0, |
thisp = arguments[1]; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
|
for (var i = 0; i < length; i++) { |
if (i in self && !fun.call(thisp, self[i], i, object)) { |
return false; |
} |
} |
return true; |
}; |
} |
if (!Array.prototype.some) { |
Array.prototype.some = function some(fun /*, thisp */) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0, |
thisp = arguments[1]; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
|
for (var i = 0; i < length; i++) { |
if (i in self && fun.call(thisp, self[i], i, object)) { |
return true; |
} |
} |
return false; |
}; |
} |
if (!Array.prototype.reduce) { |
Array.prototype.reduce = function reduce(fun /*, initial*/) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
if (!length && arguments.length == 1) { |
throw new TypeError("reduce of empty array with no initial value"); |
} |
|
var i = 0; |
var result; |
if (arguments.length >= 2) { |
result = arguments[1]; |
} else { |
do { |
if (i in self) { |
result = self[i++]; |
break; |
} |
if (++i >= length) { |
throw new TypeError("reduce of empty array with no initial value"); |
} |
} while (true); |
} |
|
for (; i < length; i++) { |
if (i in self) { |
result = fun.call(void 0, result, self[i], i, object); |
} |
} |
|
return result; |
}; |
} |
if (!Array.prototype.reduceRight) { |
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { |
var object = toObject(this), |
self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
object, |
length = self.length >>> 0; |
if (_toString(fun) != "[object Function]") { |
throw new TypeError(fun + " is not a function"); |
} |
if (!length && arguments.length == 1) { |
throw new TypeError("reduceRight of empty array with no initial value"); |
} |
|
var result, i = length - 1; |
if (arguments.length >= 2) { |
result = arguments[1]; |
} else { |
do { |
if (i in self) { |
result = self[i--]; |
break; |
} |
if (--i < 0) { |
throw new TypeError("reduceRight of empty array with no initial value"); |
} |
} while (true); |
} |
|
do { |
if (i in this) { |
result = fun.call(void 0, result, self[i], i, object); |
} |
} while (i--); |
|
return result; |
}; |
} |
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { |
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { |
var self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
toObject(this), |
length = self.length >>> 0; |
|
if (!length) { |
return -1; |
} |
|
var i = 0; |
if (arguments.length > 1) { |
i = toInteger(arguments[1]); |
} |
i = i >= 0 ? i : Math.max(0, length + i); |
for (; i < length; i++) { |
if (i in self && self[i] === sought) { |
return i; |
} |
} |
return -1; |
}; |
} |
if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { |
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { |
var self = splitString && _toString(this) == "[object String]" ? |
this.split("") : |
toObject(this), |
length = self.length >>> 0; |
|
if (!length) { |
return -1; |
} |
var i = length - 1; |
if (arguments.length > 1) { |
i = Math.min(i, toInteger(arguments[1])); |
} |
i = i >= 0 ? i : length - Math.abs(i); |
for (; i >= 0; i--) { |
if (i in self && sought === self[i]) { |
return i; |
} |
} |
return -1; |
}; |
} |
if (!Object.getPrototypeOf) { |
Object.getPrototypeOf = function getPrototypeOf(object) { |
return object.__proto__ || ( |
object.constructor ? |
object.constructor.prototype : |
prototypeOfObject |
); |
}; |
} |
if (!Object.getOwnPropertyDescriptor) { |
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + |
"non-object: "; |
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { |
if ((typeof object != "object" && typeof object != "function") || object === null) |
throw new TypeError(ERR_NON_OBJECT + object); |
if (!owns(object, property)) |
return; |
|
var descriptor, getter, setter; |
descriptor = { enumerable: true, configurable: true }; |
if (supportsAccessors) { |
var prototype = object.__proto__; |
object.__proto__ = prototypeOfObject; |
|
var getter = lookupGetter(object, property); |
var setter = lookupSetter(object, property); |
object.__proto__ = prototype; |
|
if (getter || setter) { |
if (getter) descriptor.get = getter; |
if (setter) descriptor.set = setter; |
return descriptor; |
} |
} |
descriptor.value = object[property]; |
return descriptor; |
}; |
} |
if (!Object.getOwnPropertyNames) { |
Object.getOwnPropertyNames = function getOwnPropertyNames(object) { |
return Object.keys(object); |
}; |
} |
if (!Object.create) { |
var createEmpty; |
if (Object.prototype.__proto__ === null) { |
createEmpty = function () { |
return { "__proto__": null }; |
}; |
} else { |
createEmpty = function () { |
var empty = {}; |
for (var i in empty) |
empty[i] = null; |
empty.constructor = |
empty.hasOwnProperty = |
empty.propertyIsEnumerable = |
empty.isPrototypeOf = |
empty.toLocaleString = |
empty.toString = |
empty.valueOf = |
empty.__proto__ = null; |
return empty; |
} |
} |
|
Object.create = function create(prototype, properties) { |
var object; |
if (prototype === null) { |
object = createEmpty(); |
} else { |
if (typeof prototype != "object") |
throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); |
var Type = function () {}; |
Type.prototype = prototype; |
object = new Type(); |
object.__proto__ = prototype; |
} |
if (properties !== void 0) |
Object.defineProperties(object, properties); |
return object; |
}; |
} |
|
function doesDefinePropertyWork(object) { |
try { |
Object.defineProperty(object, "sentinel", {}); |
return "sentinel" in object; |
} catch (exception) { |
} |
} |
if (Object.defineProperty) { |
var definePropertyWorksOnObject = doesDefinePropertyWork({}); |
var definePropertyWorksOnDom = typeof document == "undefined" || |
doesDefinePropertyWork(document.createElement("div")); |
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { |
var definePropertyFallback = Object.defineProperty; |
} |
} |
|
if (!Object.defineProperty || definePropertyFallback) { |
var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; |
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " |
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + |
"on this javascript engine"; |
|
Object.defineProperty = function defineProperty(object, property, descriptor) { |
if ((typeof object != "object" && typeof object != "function") || object === null) |
throw new TypeError(ERR_NON_OBJECT_TARGET + object); |
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) |
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); |
if (definePropertyFallback) { |
try { |
return definePropertyFallback.call(Object, object, property, descriptor); |
} catch (exception) { |
} |
} |
if (owns(descriptor, "value")) { |
|
if (supportsAccessors && (lookupGetter(object, property) || |
lookupSetter(object, property))) |
{ |
var prototype = object.__proto__; |
object.__proto__ = prototypeOfObject; |
delete object[property]; |
object[property] = descriptor.value; |
object.__proto__ = prototype; |
} else { |
object[property] = descriptor.value; |
} |
} else { |
if (!supportsAccessors) |
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); |
if (owns(descriptor, "get")) |
defineGetter(object, property, descriptor.get); |
if (owns(descriptor, "set")) |
defineSetter(object, property, descriptor.set); |
} |
|
return object; |
}; |
} |
if (!Object.defineProperties) { |
Object.defineProperties = function defineProperties(object, properties) { |
for (var property in properties) { |
if (owns(properties, property)) |
Object.defineProperty(object, property, properties[property]); |
} |
return object; |
}; |
} |
if (!Object.seal) { |
Object.seal = function seal(object) { |
return object; |
}; |
} |
if (!Object.freeze) { |
Object.freeze = function freeze(object) { |
return object; |
}; |
} |
try { |
Object.freeze(function () {}); |
} catch (exception) { |
Object.freeze = (function freeze(freezeObject) { |
return function freeze(object) { |
if (typeof object == "function") { |
return object; |
} else { |
return freezeObject(object); |
} |
}; |
})(Object.freeze); |
} |
if (!Object.preventExtensions) { |
Object.preventExtensions = function preventExtensions(object) { |
return object; |
}; |
} |
if (!Object.isSealed) { |
Object.isSealed = function isSealed(object) { |
return false; |
}; |
} |
if (!Object.isFrozen) { |
Object.isFrozen = function isFrozen(object) { |
return false; |
}; |
} |
if (!Object.isExtensible) { |
Object.isExtensible = function isExtensible(object) { |
if (Object(object) === object) { |
throw new TypeError(); // TODO message |
} |
var name = ''; |
while (owns(object, name)) { |
name += '?'; |
} |
object[name] = true; |
var returnValue = owns(object, name); |
delete object[name]; |
return returnValue; |
}; |
} |
if (!Object.keys) { |
var hasDontEnumBug = true, |
dontEnums = [ |
"toString", |
"toLocaleString", |
"valueOf", |
"hasOwnProperty", |
"isPrototypeOf", |
"propertyIsEnumerable", |
"constructor" |
], |
dontEnumsLength = dontEnums.length; |
|
for (var key in {"toString": null}) { |
hasDontEnumBug = false; |
} |
|
Object.keys = function keys(object) { |
|
if ( |
(typeof object != "object" && typeof object != "function") || |
object === null |
) { |
throw new TypeError("Object.keys called on a non-object"); |
} |
|
var keys = []; |
for (var name in object) { |
if (owns(object, name)) { |
keys.push(name); |
} |
} |
|
if (hasDontEnumBug) { |
for (var i = 0, ii = dontEnumsLength; i < ii; i++) { |
var dontEnum = dontEnums[i]; |
if (owns(object, dontEnum)) { |
keys.push(dontEnum); |
} |
} |
} |
return keys; |
}; |
|
} |
if (!Date.now) { |
Date.now = function now() { |
return new Date().getTime(); |
}; |
} |
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + |
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + |
"\u2029\uFEFF"; |
if (!String.prototype.trim || ws.trim()) { |
ws = "[" + ws + "]"; |
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), |
trimEndRegexp = new RegExp(ws + ws + "*$"); |
String.prototype.trim = function trim() { |
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); |
}; |
} |
|
function toInteger(n) { |
n = +n; |
if (n !== n) { // isNaN |
n = 0; |
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { |
n = (n > 0 || -1) * Math.floor(Math.abs(n)); |
} |
return n; |
} |
|
function isPrimitive(input) { |
var type = typeof input; |
return ( |
input === null || |
type === "undefined" || |
type === "boolean" || |
type === "number" || |
type === "string" |
); |
} |
|
function toPrimitive(input) { |
var val, valueOf, toString; |
if (isPrimitive(input)) { |
return input; |
} |
valueOf = input.valueOf; |
if (typeof valueOf === "function") { |
val = valueOf.call(input); |
if (isPrimitive(val)) { |
return val; |
} |
} |
toString = input.toString; |
if (typeof toString === "function") { |
val = toString.call(input); |
if (isPrimitive(val)) { |
return val; |
} |
} |
throw new TypeError(); |
} |
var toObject = function (o) { |
if (o == null) { // this matches both null and undefined |
throw new TypeError("can't convert "+o+" to object"); |
} |
return Object(o); |
}; |
|
}); |