/** * @license Paged.js v0.1.43 | MIT | https://gitlab.pagedmedia.org/tools/pagedjs */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = global || self, global.PagedPolyfill = factory()); }(this, (function () { 'use strict'; function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } function getCjsExportFromNamespace (n) { return n && n['default'] || n; } var isImplemented = function () { var assign = Object.assign, obj; if (typeof assign !== "function") return false; obj = { foo: "raz" }; assign(obj, { bar: "dwa" }, { trzy: "trzy" }); return (obj.foo + obj.bar + obj.trzy) === "razdwatrzy"; }; var isImplemented$1 = function () { try { Object.keys("primitive"); return true; } catch (e) { return false; } }; // eslint-disable-next-line no-empty-function var noop = function () {}; var _undefined = noop(); // Support ES3 engines var isValue = function (val) { return (val !== _undefined) && (val !== null); }; var keys = Object.keys; var shim = function (object) { return keys(isValue(object) ? Object(object) : object); }; var keys$1 = isImplemented$1() ? Object.keys : shim; var validValue = function (value) { if (!isValue(value)) throw new TypeError("Cannot use null or undefined"); return value; }; var max = Math.max; var shim$1 = function (dest, src /*, …srcn*/) { var error, i, length = max(arguments.length, 2), assign; dest = Object(validValue(dest)); assign = function (key) { try { dest[key] = src[key]; } catch (e) { if (!error) error = e; } }; for (i = 1; i < length; ++i) { src = arguments[i]; keys$1(src).forEach(assign); } if (error !== undefined) throw error; return dest; }; var assign = isImplemented() ? Object.assign : shim$1; var forEach = Array.prototype.forEach, create = Object.create; var process = function (src, obj) { var key; for (key in src) obj[key] = src[key]; }; // eslint-disable-next-line no-unused-vars var normalizeOptions = function (opts1 /*, …options*/) { var result = create(null); forEach.call(arguments, function (options) { if (!isValue(options)) return; process(Object(options), result); }); return result; }; // Deprecated var isCallable = function (obj) { return typeof obj === "function"; }; var str = "razdwatrzy"; var isImplemented$2 = function () { if (typeof str.contains !== "function") return false; return (str.contains("dwa") === true) && (str.contains("foo") === false); }; var indexOf = String.prototype.indexOf; var shim$2 = function (searchString/*, position*/) { return indexOf.call(this, searchString, arguments[1]) > -1; }; var contains = isImplemented$2() ? String.prototype.contains : shim$2; var d_1 = createCommonjsModule(function (module) { var d; d = module.exports = function (dscr, value/*, options*/) { var c, e, w, options, desc; if ((arguments.length < 2) || (typeof dscr !== 'string')) { options = value; value = dscr; dscr = null; } else { options = arguments[2]; } if (dscr == null) { c = w = true; e = false; } else { c = contains.call(dscr, 'c'); e = contains.call(dscr, 'e'); w = contains.call(dscr, 'w'); } desc = { value: value, configurable: c, enumerable: e, writable: w }; return !options ? desc : assign(normalizeOptions(options), desc); }; d.gs = function (dscr, get, set/*, options*/) { var c, e, options, desc; if (typeof dscr !== 'string') { options = set; set = get; get = dscr; dscr = null; } else { options = arguments[3]; } if (get == null) { get = undefined; } else if (!isCallable(get)) { options = get; get = set = undefined; } else if (set == null) { set = undefined; } else if (!isCallable(set)) { options = set; set = undefined; } if (dscr == null) { c = true; e = false; } else { c = contains.call(dscr, 'c'); e = contains.call(dscr, 'e'); } desc = { get: get, set: set, configurable: c, enumerable: e }; return !options ? desc : assign(normalizeOptions(options), desc); }; }); var validCallable = function (fn) { if (typeof fn !== "function") throw new TypeError(fn + " is not a function"); return fn; }; var eventEmitter = createCommonjsModule(function (module, exports) { var apply = Function.prototype.apply, call = Function.prototype.call , create = Object.create, defineProperty = Object.defineProperty , defineProperties = Object.defineProperties , hasOwnProperty = Object.prototype.hasOwnProperty , descriptor = { configurable: true, enumerable: false, writable: true } , on, once, off, emit, methods, descriptors, base; on = function (type, listener) { var data; validCallable(listener); if (!hasOwnProperty.call(this, '__ee__')) { data = descriptor.value = create(null); defineProperty(this, '__ee__', descriptor); descriptor.value = null; } else { data = this.__ee__; } if (!data[type]) data[type] = listener; else if (typeof data[type] === 'object') data[type].push(listener); else data[type] = [data[type], listener]; return this; }; once = function (type, listener) { var once, self; validCallable(listener); self = this; on.call(this, type, once = function () { off.call(self, type, once); apply.call(listener, this, arguments); }); once.__eeOnceListener__ = listener; return this; }; off = function (type, listener) { var data, listeners, candidate, i; validCallable(listener); if (!hasOwnProperty.call(this, '__ee__')) return this; data = this.__ee__; if (!data[type]) return this; listeners = data[type]; if (typeof listeners === 'object') { for (i = 0; (candidate = listeners[i]); ++i) { if ((candidate === listener) || (candidate.__eeOnceListener__ === listener)) { if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; else listeners.splice(i, 1); } } } else { if ((listeners === listener) || (listeners.__eeOnceListener__ === listener)) { delete data[type]; } } return this; }; emit = function (type) { var i, l, listener, listeners, args; if (!hasOwnProperty.call(this, '__ee__')) return; listeners = this.__ee__[type]; if (!listeners) return; if (typeof listeners === 'object') { l = arguments.length; args = new Array(l - 1); for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; listeners = listeners.slice(); for (i = 0; (listener = listeners[i]); ++i) { apply.call(listener, this, args); } } else { switch (arguments.length) { case 1: call.call(listeners, this); break; case 2: call.call(listeners, this, arguments[1]); break; case 3: call.call(listeners, this, arguments[1], arguments[2]); break; default: l = arguments.length; args = new Array(l - 1); for (i = 1; i < l; ++i) { args[i - 1] = arguments[i]; } apply.call(listeners, this, args); } } }; methods = { on: on, once: once, off: off, emit: emit }; descriptors = { on: d_1(on), once: d_1(once), off: d_1(off), emit: d_1(emit) }; base = defineProperties({}, descriptors); module.exports = exports = function (o) { return (o == null) ? create(base) : defineProperties(Object(o), descriptors); }; exports.methods = methods; }); var eventEmitter_1 = eventEmitter.methods; /** * Hooks allow for injecting functions that must all complete in order before finishing * They will execute in parallel but all must finish before continuing * Functions may return a promise if they are asycn. * From epubjs/src/utils/hooks * @param {any} context scope of this * @example this.content = new Hook(this); */ class Hook { constructor(context){ this.context = context || this; this.hooks = []; } /** * Adds a function to be run before a hook completes * @example this.content.register(function(){...}); * @return {undefined} void */ register(){ for(var i = 0; i < arguments.length; ++i) { if (typeof arguments[i] === "function") { this.hooks.push(arguments[i]); } else { // unpack array for(var j = 0; j < arguments[i].length; ++j) { this.hooks.push(arguments[i][j]); } } } } /** * Triggers a hook to run all functions * @example this.content.trigger(args).then(function(){...}); * @return {Promise} results */ trigger(){ var args = arguments; var context = this.context; var promises = []; this.hooks.forEach(function(task) { var executing = task.apply(context, args); if(executing && typeof executing["then"] === "function") { // Task is a function that returns a promise promises.push(executing); } // Otherwise Task resolves immediately, add resolved promise with result promises.push(new Promise((resolve, reject) => { resolve(executing); })); }); return Promise.all(promises); } /** * Triggers a hook to run all functions synchronously * @example this.content.trigger(args).then(function(){...}); * @return {Array} results */ triggerSync(){ var args = arguments; var context = this.context; var results = []; this.hooks.forEach(function(task) { var executing = task.apply(context, args); results.push(executing); }); return results; } // Adds a function to be run before a hook completes list(){ return this.hooks; } clear(){ return this.hooks = []; } } function getBoundingClientRect(element) { if (!element) { return; } let rect; if (typeof element.getBoundingClientRect !== "undefined") { rect = element.getBoundingClientRect(); } else { let range = document.createRange(); range.selectNode(element); rect = range.getBoundingClientRect(); } return rect; } function getClientRects(element) { if (!element) { return; } let rect; if (typeof element.getClientRects !== "undefined") { rect = element.getClientRects(); } else { let range = document.createRange(); range.selectNode(element); rect = range.getClientRects(); } return rect; } /** * Generates a UUID * based on: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript * @returns {string} uuid */ function UUID() { var d = new Date().getTime(); if (typeof performance !== "undefined" && typeof performance.now === "function") { d += performance.now(); //use high-precision timer if available } return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); }); } function attr(element, attributes) { for (var i = 0; i < attributes.length; i++) { if (element.hasAttribute(attributes[i])) { return element.getAttribute(attributes[i]); } } } /* Based on by https://mths.be/cssescape v1.5.1 by @mathias | MIT license * Allows # and . */ function querySelectorEscape(value) { if (arguments.length == 0) { throw new TypeError("`CSS.escape` requires an argument."); } var string = String(value); var length = string.length; var index = -1; var codeUnit; var result = ""; var firstCodeUnit = string.charCodeAt(0); while (++index < length) { codeUnit = string.charCodeAt(index); // Note: there’s no need to special-case astral symbols, surrogate // pairs, or lone surrogates. // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER // (U+FFFD). if (codeUnit == 0x0000) { result += "\uFFFD"; continue; } if ( // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is // U+007F, […] (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || // If the character is the first character and is in the range [0-9] // (U+0030 to U+0039), […] (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || // If the character is the second character and is in the range [0-9] // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] ( index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002D ) ) { // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point result += "\\" + codeUnit.toString(16) + " "; continue; } if ( // If the character is the first character and is a `-` (U+002D), and // there is no second character, […] index == 0 && length == 1 && codeUnit == 0x002D ) { result += "\\" + string.charAt(index); continue; } // support for period character in id if (codeUnit == 0x002E) { if (string.charAt(0) == "#") { result += "\\."; continue; } } // If the character is not handled by one of the above rules and is // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to // U+005A), or [a-z] (U+0061 to U+007A), […] if ( codeUnit >= 0x0080 || codeUnit == 0x002D || codeUnit == 0x005F || codeUnit == 35 || // Allow # codeUnit == 46 || // Allow . codeUnit >= 0x0030 && codeUnit <= 0x0039 || codeUnit >= 0x0041 && codeUnit <= 0x005A || codeUnit >= 0x0061 && codeUnit <= 0x007A ) { // the character itself result += string.charAt(index); continue; } // Otherwise, the escaped character. // https://drafts.csswg.org/cssom/#escape-a-character result += "\\" + string.charAt(index); } return result; } /** * Creates a new pending promise and provides methods to resolve or reject it. * From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible * @returns {object} defered */ function defer() { this.resolve = null; this.reject = null; this.id = UUID(); this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); Object.freeze(this); } const requestIdleCallback = typeof window !== "undefined" && ("requestIdleCallback" in window ? window.requestIdleCallback : window.requestAnimationFrame); function CSSValueToString(obj) { return obj.value + (obj.unit || ""); } function isElement(node) { return node && node.nodeType === 1; } function isText(node) { return node && node.nodeType === 3; } function *walk(start, limiter) { let node = start; while (node) { yield node; if (node.childNodes.length) { node = node.firstChild; } else if (node.nextSibling) { if (limiter && node === limiter) { node = undefined; break; } node = node.nextSibling; } else { while (node) { node = node.parentNode; if (limiter && node === limiter) { node = undefined; break; } if (node && node.nextSibling) { node = node.nextSibling; break; } } } } } function nodeAfter(node, limiter) { if (limiter && node === limiter) { return; } let significantNode = nextSignificantNode(node); if (significantNode) { return significantNode; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } significantNode = nextSignificantNode(node); if (significantNode) { return significantNode; } } } } function nodeBefore(node, limiter) { if (limiter && node === limiter) { return; } let significantNode = previousSignificantNode(node); if (significantNode) { return significantNode; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } significantNode = previousSignificantNode(node); if (significantNode) { return significantNode; } } } } function elementAfter(node, limiter) { let after = nodeAfter(node, limiter); while (after && after.nodeType !== 1) { after = nodeAfter(after, limiter); } return after; } function elementBefore(node, limiter) { let before = nodeBefore(node, limiter); while (before && before.nodeType !== 1) { before = nodeBefore(before, limiter); } return before; } function displayedElementAfter(node, limiter) { let after = elementAfter(node, limiter); while (after && after.dataset.undisplayed) { after = elementAfter(after); } return after; } function displayedElementBefore(node, limiter) { let before = elementBefore(node, limiter); while (before && before.dataset.undisplayed) { before = elementBefore(before); } return before; } function rebuildAncestors(node) { let parent, ancestor; let ancestors = []; let added = []; let fragment = document.createDocumentFragment(); // Gather all ancestors let element = node; while(element.parentNode && element.parentNode.nodeType === 1) { ancestors.unshift(element.parentNode); element = element.parentNode; } for (var i = 0; i < ancestors.length; i++) { ancestor = ancestors[i]; parent = ancestor.cloneNode(false); parent.setAttribute("data-split-from", parent.getAttribute("data-ref")); // ancestor.setAttribute("data-split-to", parent.getAttribute("data-ref")); if (parent.hasAttribute("id")) { let dataID = parent.getAttribute("id"); parent.setAttribute("data-id", dataID); parent.removeAttribute("id"); } // This is handled by css :not, but also tidied up here if (parent.hasAttribute("data-break-before")) { parent.removeAttribute("data-break-before"); } if (parent.hasAttribute("data-previous-break-after")) { parent.removeAttribute("data-previous-break-after"); } if (added.length) { let container = added[added.length-1]; container.appendChild(parent); } else { fragment.appendChild(parent); } added.push(parent); } added = undefined; return fragment; } /* export function split(bound, cutElement, breakAfter) { let needsRemoval = []; let index = indexOf(cutElement); if (!breakAfter && index === 0) { return; } if (breakAfter && index === (cutElement.parentNode.children.length - 1)) { return; } // Create a fragment with rebuilt ancestors let fragment = rebuildAncestors(cutElement); // Clone cut if (!breakAfter) { let clone = cutElement.cloneNode(true); let ref = cutElement.parentNode.getAttribute('data-ref'); let parent = fragment.querySelector("[data-ref='" + ref + "']"); parent.appendChild(clone); needsRemoval.push(cutElement); } // Remove all after cut let next = nodeAfter(cutElement, bound); while (next) { let clone = next.cloneNode(true); let ref = next.parentNode.getAttribute('data-ref'); let parent = fragment.querySelector("[data-ref='" + ref + "']"); parent.appendChild(clone); needsRemoval.push(next); next = nodeAfter(next, bound); } // Remove originals needsRemoval.forEach((node) => { if (node) { node.remove(); } }); // Insert after bounds bound.parentNode.insertBefore(fragment, bound.nextSibling); return [bound, bound.nextSibling]; } */ function needsBreakBefore(node) { if( typeof node !== "undefined" && typeof node.dataset !== "undefined" && typeof node.dataset.breakBefore !== "undefined" && (node.dataset.breakBefore === "always" || node.dataset.breakBefore === "page" || node.dataset.breakBefore === "left" || node.dataset.breakBefore === "right" || node.dataset.breakBefore === "recto" || node.dataset.breakBefore === "verso") ) { return true; } return false; } function needsPreviousBreakAfter(node) { if( typeof node !== "undefined" && typeof node.dataset !== "undefined" && typeof node.dataset.previousBreakAfter !== "undefined" && (node.dataset.previousBreakAfter === "always" || node.dataset.previousBreakAfter === "page" || node.dataset.previousBreakAfter === "left" || node.dataset.previousBreakAfter === "right" || node.dataset.previousBreakAfter === "recto" || node.dataset.previousBreakAfter === "verso") ) { return true; } return false; } function needsPageBreak(node, previousSignificantNode) { if (typeof node === "undefined" || !previousSignificantNode || isIgnorable(node)) { return false; } if (node.dataset && node.dataset.undisplayed) { return false; } const previousSignificantNodePage = previousSignificantNode.dataset ? previousSignificantNode.dataset.page : undefined; const currentNodePage = node.dataset ? node.dataset.page : undefined; return currentNodePage !== previousSignificantNodePage; } function *words(node) { let currentText = node.nodeValue; let max = currentText.length; let currentOffset = 0; let currentLetter; let range; while(currentOffset < max) { currentLetter = currentText[currentOffset]; if (/^[\S\u202F\u00A0]$/.test(currentLetter)) { if (!range) { range = document.createRange(); range.setStart(node, currentOffset); } } else { if (range) { range.setEnd(node, currentOffset); yield range; range = undefined; } } currentOffset += 1; } if (range) { range.setEnd(node, currentOffset); yield range; range = undefined; } } function *letters(wordRange) { let currentText = wordRange.startContainer; let max = currentText.length; let currentOffset = wordRange.startOffset; // let currentLetter; let range; while(currentOffset < max) { // currentLetter = currentText[currentOffset]; range = document.createRange(); range.setStart(currentText, currentOffset); range.setEnd(currentText, currentOffset+1); yield range; currentOffset += 1; } } function isContainer(node) { let container; if (typeof node.tagName === "undefined") { return true; } if (node.style && node.style.display === "none") { return false; } switch (node.tagName) { // Inline case "A": case "ABBR": case "ACRONYM": case "B": case "BDO": case "BIG": case "BR": case "BUTTON": case "CITE": case "CODE": case "DFN": case "EM": case "I": case "IMG": case "INPUT": case "KBD": case "LABEL": case "MAP": case "OBJECT": case "Q": case "SAMP": case "SCRIPT": case "SELECT": case "SMALL": case "SPAN": case "STRONG": case "SUB": case "SUP": case "TEXTAREA": case "TIME": case "TT": case "VAR": case "P": case "H1": case "H2": case "H3": case "H4": case "H5": case "H6": case "FIGCAPTION": case "BLOCKQUOTE": case "PRE": case "LI": case "TR": case "DT": case "DD": case "VIDEO": case "CANVAS": container = false; break; default: container = true; } return container; } function cloneNode(n, deep=false) { return n.cloneNode(deep); } function findElement(node, doc) { const ref = node.getAttribute("data-ref"); return findRef(ref, doc); } function findRef(ref, doc) { return doc.querySelector(`[data-ref='${ref}']`); } function validNode(node) { if (isText(node)) { return true; } if (isElement(node) && node.dataset.ref) { return true; } return false; } function prevValidNode(node) { while (!validNode(node)) { if (node.previousSibling) { node = node.previousSibling; } else { node = node.parentNode; } if (!node) { break; } } return node; } function indexOf$1(node) { let parent = node.parentNode; if (!parent) { return 0; } return Array.prototype.indexOf.call(parent.childNodes, node); } function child(node, index) { return node.childNodes[index]; } function hasContent(node) { if (isElement(node)) { return true; } else if (isText(node) && node.textContent.trim().length) { return true; } return false; } function indexOfTextNode(node, parent) { if (!isText(node)) { return -1; } let nodeTextContent = node.textContent; let child; let index = -1; for (var i = 0; i < parent.childNodes.length; i++) { child = parent.childNodes[i]; if (child.nodeType === 3) { let text = parent.childNodes[i].textContent; if (text.includes(nodeTextContent)) { index = i; break; } } } return index; } /** * Throughout, whitespace is defined as one of the characters * "\t" TAB \u0009 * "\n" LF \u000A * "\r" CR \u000D * " " SPC \u0020 * * This does not use Javascript's "\s" because that includes non-breaking * spaces (and also some other characters). */ /** * Determine if a node should be ignored by the iterator functions. * taken from https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace#Whitespace_helper_functions * * @param {Node} node An object implementing the DOM1 |Node| interface. * @return {boolean} true if the node is: * 1) A |Text| node that is all whitespace * 2) A |Comment| node * and otherwise false. */ function isIgnorable(node) { return (node.nodeType === 8) || // A comment node ((node.nodeType === 3) && isAllWhitespace(node)); // a text node, all whitespace } /** * Determine whether a node's text content is entirely whitespace. * * @param {Node} node A node implementing the |CharacterData| interface (i.e., a |Text|, |Comment|, or |CDATASection| node * @return {boolean} true if all of the text content of |nod| is whitespace, otherwise false. */ function isAllWhitespace(node) { return !(/[^\t\n\r ]/.test(node.textContent)); } /** * Version of |previousSibling| that skips nodes that are entirely * whitespace or comments. (Normally |previousSibling| is a property * of all DOM nodes that gives the sibling node, the node that is * a child of the same parent, that occurs immediately before the * reference node.) * * @param {ChildNode} sib The reference node. * @return {Node|null} Either: * 1) The closest previous sibling to |sib| that is not ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function previousSignificantNode(sib) { while ((sib = sib.previousSibling)) { if (!isIgnorable(sib)) return sib; } return null; } function breakInsideAvoidParentNode(node) { while ((node = node.parentNode)) { if (node && node.dataset && node.dataset.breakInside === "avoid") { return node; } } return null; } /** * Find a parent with a given node name. * @param {Node} node - initial Node * @param {string} nodeName - node name (eg. "TD", "TABLE", "STRONG"...) * @param {Node} limiter - go up to the parent until there's no more parent or the current node is equals to the limiter * @returns {Node|undefined} - Either: * 1) The closest parent for a the given node name, or * 2) undefined if no such node exists. */ function parentOf(node, nodeName, limiter) { if (limiter && node === limiter) { return; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } if (node.nodeName === nodeName) { return node; } } } } /** * Version of |nextSibling| that skips nodes that are entirely * whitespace or comments. * * @param {ChildNode} sib The reference node. * @return {Node|null} Either: * 1) The closest next sibling to |sib| that is not ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function nextSignificantNode(sib) { while ((sib = sib.nextSibling)) { if (!isIgnorable(sib)) return sib; } return null; } function filterTree(content, func, what) { const treeWalker = document.createTreeWalker( content || this.dom, what || NodeFilter.SHOW_ALL, func ? { acceptNode: func } : null, false ); let node; let current; node = treeWalker.nextNode(); while(node) { current = node; node = treeWalker.nextNode(); current.parentNode.removeChild(current); } } /** * Layout * @class */ class BreakToken { constructor(node, offset) { this.node = node; this.offset = offset; } equals(otherBreakToken) { if (!otherBreakToken) { return false; } if (this["node"] && otherBreakToken["node"] && this["node"] !== otherBreakToken["node"]) { return false; } if (this["offset"] && otherBreakToken["offset"] && this["offset"] !== otherBreakToken["offset"]) { return false; } return true; } } const MAX_CHARS_PER_BREAK = 1500; /** * Layout * @class */ class Layout { constructor(element, hooks, options) { this.element = element; this.bounds = this.element.getBoundingClientRect(); if (hooks) { this.hooks = hooks; } else { this.hooks = {}; this.hooks.layout = new Hook(); this.hooks.renderNode = new Hook(); this.hooks.layoutNode = new Hook(); this.hooks.beforeOverflow = new Hook(); this.hooks.onOverflow = new Hook(); this.hooks.onBreakToken = new Hook(); } this.settings = options || {}; this.maxChars = this.settings.maxChars || MAX_CHARS_PER_BREAK; this.forceRenderBreak = false; } async renderTo(wrapper, source, breakToken, bounds = this.bounds) { let start = this.getStart(source, breakToken); let walker = walk(start, source); let node; let prevNode; let done; let next; let hasRenderedContent = false; let newBreakToken; let length = 0; let prevBreakToken = breakToken || new BreakToken(start); while (!done && !newBreakToken) { next = walker.next(); prevNode = node; node = next.value; done = next.done; if (!node) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", prevNode); return undefined; } return newBreakToken; } this.hooks && this.hooks.layoutNode.trigger(node); // Check if the rendered element has a break set if (hasRenderedContent && this.shouldBreak(node)) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", node); return undefined; } length = 0; break; } // Should the Node be a shallow or deep clone let shallow = isContainer(node); let rendered = this.append(node, wrapper, breakToken, shallow); length += rendered.textContent.length; // Check if layout has content yet if (!hasRenderedContent) { hasRenderedContent = hasContent(node); } // Skip to the next node if a deep clone was rendered if (!shallow) { walker = walk(nodeAfter(node, source), source); } if (this.forceRenderBreak) { this.hooks && this.hooks.layout.trigger(wrapper, this); newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } length = 0; this.forceRenderBreak = false; break; } // Only check x characters if (length >= this.maxChars) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", node); return undefined; } if (newBreakToken) { length = 0; } } } return newBreakToken; } breakAt(node, offset = 0) { let newBreakToken = new BreakToken( node, offset ); let breakHooks = this.hooks.onBreakToken.triggerSync(newBreakToken, undefined, node, this); breakHooks.forEach((newToken) => { if (typeof newToken != "undefined") { newBreakToken = newToken; } }); return newBreakToken; } shouldBreak(node) { let previousSibling = previousSignificantNode(node); let parentNode = node.parentNode; let parentBreakBefore = needsBreakBefore(node) && parentNode && !previousSibling && needsBreakBefore(parentNode); let doubleBreakBefore; if (parentBreakBefore) { doubleBreakBefore = node.dataset.breakBefore === parentNode.dataset.breakBefore; } return !doubleBreakBefore && needsBreakBefore(node) || needsPreviousBreakAfter(node) || needsPageBreak(node, previousSibling); } forceBreak() { this.forceRenderBreak = true; } getStart(source, breakToken) { let start; let node = breakToken && breakToken.node; if (node) { start = node; } else { start = source.firstChild; } return start; } append(node, dest, breakToken, shallow = true, rebuild = true) { let clone = cloneNode(node, !shallow); if (node.parentNode && isElement(node.parentNode)) { let parent = findElement(node.parentNode, dest); // Rebuild chain if (parent) { parent.appendChild(clone); } else if (rebuild) { let fragment = rebuildAncestors(node); parent = findElement(node.parentNode, fragment); if (!parent) { dest.appendChild(clone); } else if (breakToken && isText(breakToken.node) && breakToken.offset > 0) { clone.textContent = clone.textContent.substring(breakToken.offset); parent.appendChild(clone); } else { parent.appendChild(clone); } dest.appendChild(fragment); } else { dest.appendChild(clone); } } else { dest.appendChild(clone); } let nodeHooks = this.hooks.renderNode.triggerSync(clone, node, this); nodeHooks.forEach((newNode) => { if (typeof newNode != "undefined") { clone = newNode; } }); return clone; } async waitForImages(imgs) { let results = Array.from(imgs).map(async (img) => { return this.awaitImageLoaded(img); }); await Promise.all(results); } async awaitImageLoaded(image) { return new Promise(resolve => { if (image.complete !== true) { image.onload = function () { let {width, height} = window.getComputedStyle(image); resolve(width, height); }; image.onerror = function (e) { let {width, height} = window.getComputedStyle(image); resolve(width, height, e); }; } else { let {width, height} = window.getComputedStyle(image); resolve(width, height); } }); } avoidBreakInside(node, limiter) { let breakNode; if (node === limiter) { return; } while (node.parentNode) { node = node.parentNode; if (node === limiter) { break; } if (window.getComputedStyle(node)["break-inside"] === "avoid") { breakNode = node; break; } } return breakNode; } createBreakToken(overflow, rendered, source) { let container = overflow.startContainer; let offset = overflow.startOffset; let node, renderedNode, parent, index, temp; if (isElement(container)) { temp = child(container, offset); if (isElement(temp)) { renderedNode = findElement(temp, rendered); if (!renderedNode) { // Find closest element with data-ref let prevNode = prevValidNode(temp); if (!isElement(prevNode)) { prevNode = prevNode.parentElement; } renderedNode = findElement(prevNode, rendered); // Check if temp is the last rendered node at its level. if (!temp.nextSibling) { // We need to ensure that the previous sibling of temp is fully rendered. const renderedNodeFromSource = findElement(renderedNode, source); const walker = document.createTreeWalker(renderedNodeFromSource, NodeFilter.SHOW_ELEMENT); const lastChildOfRenderedNodeFromSource = walker.lastChild(); const lastChildOfRenderedNodeMatchingFromRendered = findElement(lastChildOfRenderedNodeFromSource, rendered); // Check if we found that the last child in source if (!lastChildOfRenderedNodeMatchingFromRendered) { // Pending content to be rendered before virtual break token return; } // Otherwise we will return a break token as per below } // renderedNode is actually the last unbroken box that does not overflow. // Break Token is therefore the next sibling of renderedNode within source node. node = findElement(renderedNode, source).nextSibling; offset = 0; } else { node = findElement(renderedNode, source); offset = 0; } } else { renderedNode = findElement(container, rendered); if (!renderedNode) { renderedNode = findElement(prevValidNode(container), rendered); } parent = findElement(renderedNode, source); index = indexOfTextNode(temp, parent); // No seperatation for the first textNode of an element if(index === 0) { node = parent; offset = 0; } else { node = child(parent, index); offset = 0; } } } else { renderedNode = findElement(container.parentNode, rendered); if (!renderedNode) { renderedNode = findElement(prevValidNode(container.parentNode), rendered); } parent = findElement(renderedNode, source); index = indexOfTextNode(container, parent); if (index === -1) { return; } node = child(parent, index); offset += node.textContent.indexOf(container.textContent); } if (!node) { return; } return new BreakToken( node, offset ); } findBreakToken(rendered, source, bounds = this.bounds, prevBreakToken, extract = true) { let overflow = this.findOverflow(rendered, bounds); let breakToken, breakLetter; let overflowHooks = this.hooks.onOverflow.triggerSync(overflow, rendered, bounds, this); overflowHooks.forEach((newOverflow) => { if (typeof newOverflow != "undefined") { overflow = newOverflow; } }); if (overflow) { breakToken = this.createBreakToken(overflow, rendered, source); // breakToken is nullable let breakHooks = this.hooks.onBreakToken.triggerSync(breakToken, overflow, rendered, this); breakHooks.forEach((newToken) => { if (typeof newToken != "undefined") { breakToken = newToken; } }); // Stop removal if we are in a loop if (breakToken && breakToken.equals(prevBreakToken)) { return breakToken; } if (breakToken && breakToken["node"] && breakToken["offset"] && breakToken["node"].textContent) { breakLetter = breakToken["node"].textContent.charAt(breakToken["offset"]); } else { breakLetter = undefined; } if (breakToken && breakToken.node && extract) { this.removeOverflow(overflow, breakLetter); } } return breakToken; } hasOverflow(element, bounds = this.bounds) { let constrainingElement = element && element.parentNode; // this gets the element, instead of the wrapper for the width workaround let {width} = element.getBoundingClientRect(); let scrollWidth = constrainingElement ? constrainingElement.scrollWidth : 0; return Math.max(Math.floor(width), scrollWidth) > Math.round(bounds.width); } findOverflow(rendered, bounds = this.bounds) { if (!this.hasOverflow(rendered, bounds)) return; let start = Math.round(bounds.left); let end = Math.round(bounds.right); let range; let walker = walk(rendered.firstChild, rendered); // Find Start let next, done, node, offset, skip, breakAvoid, prev, br; while (!done) { next = walker.next(); done = next.done; node = next.value; skip = false; breakAvoid = false; prev = undefined; br = undefined; if (node) { let pos = getBoundingClientRect(node); let left = Math.round(pos.left); let right = Math.floor(pos.right); if (!range && left >= end) { // Check if it is a float let isFloat = false; // Check if the node is inside a break-inside: avoid table cell const insideTableCell = parentOf(node, "TD", rendered); if (insideTableCell && window.getComputedStyle(insideTableCell)["break-inside"] === "avoid") { // breaking inside a table cell produces unexpected result, as a workaround, we forcibly avoid break inside in a cell. prev = insideTableCell; } else if (isElement(node)) { let styles = window.getComputedStyle(node); isFloat = styles.getPropertyValue("float") !== "none"; skip = styles.getPropertyValue("break-inside") === "avoid"; breakAvoid = node.dataset.breakBefore === "avoid" || node.dataset.previousBreakAfter === "avoid"; prev = breakAvoid && nodeBefore(node, rendered); br = node.tagName === "BR" || node.tagName === "WBR"; } if (prev) { range = document.createRange(); range.selectNode(prev); break; } if (!br && !isFloat && isElement(node)) { range = document.createRange(); range.selectNode(node); break; } if (isText(node) && node.textContent.trim().length) { range = document.createRange(); range.selectNode(node); break; } } if (!range && isText(node) && node.textContent.trim().length && !breakInsideAvoidParentNode(node.parentNode)) { let rects = getClientRects(node); let rect; left = 0; for (var i = 0; i != rects.length; i++) { rect = rects[i]; if (rect.width > 0 && (!left || rect.left > left)) { left = rect.left; } } if (left >= end) { range = document.createRange(); offset = this.textBreak(node, start, end); if (!offset) { range = undefined; } else { range.setStart(node, offset); } break; } } // Skip children if (skip || right <= end) { next = nodeAfter(node, rendered); if (next) { walker = walk(next, rendered); } } } } // Find End if (range) { range.setEndAfter(rendered.lastChild); return range; } } findEndToken(rendered, source, bounds = this.bounds) { if (rendered.childNodes.length === 0) { return; } let lastChild = rendered.lastChild; let lastNodeIndex; while (lastChild && lastChild.lastChild) { if (!validNode(lastChild)) { // Only get elements with refs lastChild = lastChild.previousSibling; } else if (!validNode(lastChild.lastChild)) { // Deal with invalid dom items lastChild = prevValidNode(lastChild.lastChild); break; } else { lastChild = lastChild.lastChild; } } if (isText(lastChild)) { if (lastChild.parentNode.dataset.ref) { lastNodeIndex = indexOf$1(lastChild); lastChild = lastChild.parentNode; } else { lastChild = lastChild.previousSibling; } } let original = findElement(lastChild, source); if (lastNodeIndex) { original = original.childNodes[lastNodeIndex]; } let after = nodeAfter(original); return this.breakAt(after); } textBreak(node, start, end) { let wordwalker = words(node); let left = 0; let right = 0; let word, next, done, pos; let offset; while (!done) { next = wordwalker.next(); word = next.value; done = next.done; if (!word) { break; } pos = getBoundingClientRect(word); left = Math.floor(pos.left); right = Math.floor(pos.right); if (left >= end) { offset = word.startOffset; break; } if (right > end) { let letterwalker = letters(word); let letter, nextLetter, doneLetter; while (!doneLetter) { nextLetter = letterwalker.next(); letter = nextLetter.value; doneLetter = nextLetter.done; if (!letter) { break; } pos = getBoundingClientRect(letter); left = Math.floor(pos.left); if (left >= end) { offset = letter.startOffset; done = true; break; } } } } return offset; } removeOverflow(overflow, breakLetter) { let {startContainer} = overflow; let extracted = overflow.extractContents(); this.hyphenateAtBreak(startContainer, breakLetter); return extracted; } hyphenateAtBreak(startContainer, breakLetter) { if (isText(startContainer)) { let startText = startContainer.textContent; let prevLetter = startText[startText.length - 1]; // Add a hyphen if previous character is a letter or soft hyphen if ( (breakLetter && /^\w|\u00AD$/.test(prevLetter) && /^\w|\u00AD$/.test(breakLetter)) || (!breakLetter && /^\w|\u00AD$/.test(prevLetter)) ) { startContainer.parentNode.classList.add("pagedjs_hyphen"); startContainer.textContent += this.settings.hyphenGlyph || "\u2011"; } } } equalTokens(a, b) { if (!a || !b) { return false; } if (a["node"] && b["node"] && a["node"] !== b["node"]) { return false; } if (a["offset"] && b["offset"] && a["offset"] !== b["offset"]) { return false; } return true; } } eventEmitter(Layout.prototype); /** * Render a page * @class */ class Page { constructor(pagesArea, pageTemplate, blank, hooks) { this.pagesArea = pagesArea; this.pageTemplate = pageTemplate; this.blank = blank; this.width = undefined; this.height = undefined; this.hooks = hooks; // this.element = this.create(this.pageTemplate); } create(template, after) { //let documentFragment = document.createRange().createContextualFragment( TEMPLATE ); //let page = documentFragment.children[0]; let clone = document.importNode(this.pageTemplate.content, true); let page, index; if (after) { this.pagesArea.insertBefore(clone, after.nextElementSibling); index = Array.prototype.indexOf.call(this.pagesArea.children, after.nextElementSibling); page = this.pagesArea.children[index]; } else { this.pagesArea.appendChild(clone); page = this.pagesArea.lastChild; } let pagebox = page.querySelector(".pagedjs_pagebox"); let area = page.querySelector(".pagedjs_page_content"); let size = area.getBoundingClientRect(); area.style.columnWidth = Math.round(size.width) + "px"; area.style.columnGap = "calc(var(--pagedjs-margin-right) + var(--pagedjs-margin-left))"; // area.style.overflow = "scroll"; this.width = Math.round(size.width); this.height = Math.round(size.height); this.element = page; this.pagebox = pagebox; this.area = area; return page; } createWrapper() { let wrapper = document.createElement("div"); this.area.appendChild(wrapper); this.wrapper = wrapper; return wrapper; } index(pgnum) { this.position = pgnum; let page = this.element; // let pagebox = this.pagebox; let index = pgnum + 1; let id = `page-${index}`; this.id = id; // page.dataset.pageNumber = index; page.dataset.pageNumber = index; page.setAttribute("id", id); if (this.name) { page.classList.add("pagedjs_" + this.name + "_page"); } if (this.blank) { page.classList.add("pagedjs_blank_page"); } if (pgnum === 0) { page.classList.add("pagedjs_first_page"); } if (pgnum % 2 !== 1) { page.classList.remove("pagedjs_left_page"); page.classList.add("pagedjs_right_page"); } else { page.classList.remove("pagedjs_right_page"); page.classList.add("pagedjs_left_page"); } } /* size(width, height) { if (width === this.width && height === this.height) { return; } this.width = width; this.height = height; this.element.style.width = Math.round(width) + "px"; this.element.style.height = Math.round(height) + "px"; this.element.style.columnWidth = Math.round(width) + "px"; } */ async layout(contents, breakToken, maxChars) { this.clear(); this.startToken = breakToken; this.layoutMethod = new Layout(this.area, this.hooks, maxChars); let newBreakToken = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken); this.addListeners(contents); this.endToken = newBreakToken; return newBreakToken; } async append(contents, breakToken) { if (!this.layoutMethod) { return this.layout(contents, breakToken); } let newBreakToken = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken); this.endToken = newBreakToken; return newBreakToken; } getByParent(ref, entries) { let e; for (var i = 0; i < entries.length; i++) { e = entries[i]; if (e.dataset.ref === ref) { return e; } } } onOverflow(func) { this._onOverflow = func; } onUnderflow(func) { this._onUnderflow = func; } clear() { this.removeListeners(); this.wrapper && this.wrapper.remove(); this.createWrapper(); } addListeners(contents) { if (typeof ResizeObserver !== "undefined") { this.addResizeObserver(contents); } else { this._checkOverflowAfterResize = this.checkOverflowAfterResize.bind(this, contents); this.element.addEventListener("overflow", this._checkOverflowAfterResize, false); this.element.addEventListener("underflow", this._checkOverflowAfterResize, false); } // TODO: fall back to mutation observer? this._onScroll = function () { if (this.listening) { this.element.scrollLeft = 0; } }.bind(this); // Keep scroll left from changing this.element.addEventListener("scroll", this._onScroll); this.listening = true; return true; } removeListeners() { this.listening = false; if (typeof ResizeObserver !== "undefined" && this.ro) { this.ro.disconnect(); } else if (this.element) { this.element.removeEventListener("overflow", this._checkOverflowAfterResize, false); this.element.removeEventListener("underflow", this._checkOverflowAfterResize, false); } this.element && this.element.removeEventListener("scroll", this._onScroll); } addResizeObserver(contents) { let wrapper = this.wrapper; let prevHeight = wrapper.getBoundingClientRect().height; this.ro = new ResizeObserver(entries => { if (!this.listening) { return; } requestAnimationFrame(() => { for (let entry of entries) { const cr = entry.contentRect; if (cr.height > prevHeight) { this.checkOverflowAfterResize(contents); prevHeight = wrapper.getBoundingClientRect().height; } else if (cr.height < prevHeight) { // TODO: calc line height && (prevHeight - cr.height) >= 22 this.checkUnderflowAfterResize(contents); prevHeight = cr.height; } } }); }); this.ro.observe(wrapper); } checkOverflowAfterResize(contents) { if (!this.listening || !this.layoutMethod) { return; } let newBreakToken = this.layoutMethod.findBreakToken(this.wrapper, contents, this.startToken); if (newBreakToken) { this.endToken = newBreakToken; this._onOverflow && this._onOverflow(newBreakToken); } } checkUnderflowAfterResize(contents) { if (!this.listening || !this.layoutMethod) { return; } let endToken = this.layoutMethod.findEndToken(this.wrapper, contents); if (endToken) { this._onUnderflow && this._onUnderflow(endToken); } } destroy() { this.removeListeners(); this.element.remove(); this.element = undefined; this.wrapper = undefined; } } eventEmitter(Page.prototype); /** * Render a flow of text offscreen * @class */ class ContentParser { constructor(content, cb) { if (content && content.nodeType) { // handle dom this.dom = this.add(content); } else if (typeof content === "string") { this.dom = this.parse(content); } return this.dom; } parse(markup, mime) { let range = document.createRange(); let fragment = range.createContextualFragment(markup); this.addRefs(fragment); return fragment; } add(contents) { // let fragment = document.createDocumentFragment(); // // let children = [...contents.childNodes]; // for (let child of children) { // let clone = child.cloneNode(true); // fragment.appendChild(clone); // } this.addRefs(contents); return contents; } addRefs(content) { var treeWalker = document.createTreeWalker( content, NodeFilter.SHOW_ELEMENT, null, false ); let node = treeWalker.nextNode(); while(node) { if (!node.hasAttribute("data-ref")) { let uuid = UUID(); node.setAttribute("data-ref", uuid); } if (node.id) { node.setAttribute("data-id", node.id); } // node.setAttribute("data-children", node.childNodes.length); // node.setAttribute("data-text", node.textContent.trim().length); node = treeWalker.nextNode(); } } find(ref) { return this.refs[ref]; } destroy() { this.refs = undefined; this.dom = undefined; } } /** * Queue for handling tasks one at a time * @class * @param {scope} context what this will resolve to in the tasks */ class Queue { constructor(context){ this._q = []; this.context = context; this.tick = requestAnimationFrame; this.running = false; this.paused = false; } /** * Add an item to the queue * @return {Promise} enqueued */ enqueue() { var deferred, promise; var queued; var task = [].shift.call(arguments); var args = arguments; // Handle single args without context // if(args && !Array.isArray(args)) { // args = [args]; // } if(!task) { throw new Error("No Task Provided"); } if(typeof task === "function"){ deferred = new defer(); promise = deferred.promise; queued = { "task" : task, "args" : args, //"context" : context, "deferred" : deferred, "promise" : promise }; } else { // Task is a promise queued = { "promise" : task }; } this._q.push(queued); // Wait to start queue flush if (this.paused == false && !this.running) { this.run(); } return queued.promise; } /** * Run one item * @return {Promise} dequeued */ dequeue(){ var inwait, task, result; if(this._q.length && !this.paused) { inwait = this._q.shift(); task = inwait.task; if(task){ // console.log(task) result = task.apply(this.context, inwait.args); if(result && typeof result["then"] === "function") { // Task is a function that returns a promise return result.then(function(){ inwait.deferred.resolve.apply(this.context, arguments); }.bind(this), function() { inwait.deferred.reject.apply(this.context, arguments); }.bind(this)); } else { // Task resolves immediately inwait.deferred.resolve.apply(this.context, result); return inwait.promise; } } else if(inwait.promise) { // Task is a promise return inwait.promise; } } else { inwait = new defer(); inwait.deferred.resolve(); return inwait.promise; } } // Run All Immediately dump(){ while(this._q.length) { this.dequeue(); } } /** * Run all tasks sequentially, at convince * @return {Promise} all run */ run(){ if(!this.running){ this.running = true; this.defered = new defer(); } this.tick.call(window, () => { if(this._q.length) { this.dequeue() .then(function(){ this.run(); }.bind(this)); } else { this.defered.resolve(); this.running = undefined; } }); // Unpause if(this.paused == true) { this.paused = false; } return this.defered.promise; } /** * Flush all, as quickly as possible * @return {Promise} ran */ flush(){ if(this.running){ return this.running; } if(this._q.length) { this.running = this.dequeue() .then(function(){ this.running = undefined; return this.flush(); }.bind(this)); return this.running; } } /** * Clear all items in wait * @return {void} */ clear(){ this._q = []; } /** * Get the number of tasks in the queue * @return {number} tasks */ length(){ return this._q.length; } /** * Pause a running queue * @return {void} */ pause(){ this.paused = true; } /** * End the queue * @return {void} */ stop(){ this._q = []; this.running = false; this.paused = true; } } const TEMPLATE = ` <div class="pagedjs_page"> <div class="pagedjs_sheet"> <div class="pagedjs_bleed pagedjs_bleed-top"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-bottom"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-left"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-right"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_pagebox"> <div class="pagedjs_margin-top-left-corner-holder"> <div class="pagedjs_margin pagedjs_margin-top-left-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-top"> <div class="pagedjs_margin pagedjs_margin-top-left"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-top-center"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-top-right"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-top-right-corner-holder"> <div class="pagedjs_margin pagedjs_margin-top-right-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-right"> <div class="pagedjs_margin pagedjs_margin-right-top"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-right-middle"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-right-bottom"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-left"> <div class="pagedjs_margin pagedjs_margin-left-top"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-left-middle"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-left-bottom"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom-left-corner-holder"> <div class="pagedjs_margin pagedjs_margin-bottom-left-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom"> <div class="pagedjs_margin pagedjs_margin-bottom-left"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-bottom-center"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-bottom-right"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom-right-corner-holder"> <div class="pagedjs_margin pagedjs_margin-bottom-right-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_area"> <div class="pagedjs_page_content"></div> </div> </div> </div> </div>`; /** * Chop up text into flows * @class */ class Chunker { constructor(content, renderTo, options) { // this.preview = preview; this.settings = options || {}; this.hooks = {}; this.hooks.beforeParsed = new Hook(this); this.hooks.filter = new Hook(this); this.hooks.afterParsed = new Hook(this); this.hooks.beforePageLayout = new Hook(this); this.hooks.layout = new Hook(this); this.hooks.renderNode = new Hook(this); this.hooks.layoutNode = new Hook(this); this.hooks.onOverflow = new Hook(this); this.hooks.onBreakToken = new Hook(); this.hooks.afterPageLayout = new Hook(this); this.hooks.afterRendered = new Hook(this); this.pages = []; this.total = 0; this.q = new Queue(this); this.stopped = false; this.rendered = false; this.content = content; this.charsPerBreak = []; this.maxChars; if (content) { this.flow(content, renderTo); } } setup(renderTo) { this.pagesArea = document.createElement("div"); this.pagesArea.classList.add("pagedjs_pages"); if (renderTo) { renderTo.appendChild(this.pagesArea); } else { document.querySelector("body").appendChild(this.pagesArea); } this.pageTemplate = document.createElement("template"); this.pageTemplate.innerHTML = TEMPLATE; } async flow(content, renderTo) { let parsed; await this.hooks.beforeParsed.trigger(content, this); parsed = new ContentParser(content); this.hooks.filter.triggerSync(parsed); this.source = parsed; this.breakToken = undefined; if (this.pagesArea && this.pageTemplate) { this.q.clear(); this.removePages(); } else { this.setup(renderTo); } this.emit("rendering", parsed); await this.hooks.afterParsed.trigger(parsed, this); await this.loadFonts(); let rendered = await this.render(parsed, this.breakToken); while (rendered.canceled) { this.start(); rendered = await this.render(parsed, this.breakToken); } this.rendered = true; this.pagesArea.style.setProperty("--pagedjs-page-count", this.total); await this.hooks.afterRendered.trigger(this.pages, this); this.emit("rendered", this.pages); return this; } // oversetPages() { // let overset = []; // for (let i = 0; i < this.pages.length; i++) { // let page = this.pages[i]; // if (page.overset) { // overset.push(page); // // page.overset = false; // } // } // return overset; // } // // async handleOverset(parsed) { // let overset = this.oversetPages(); // if (overset.length) { // console.log("overset", overset); // let index = this.pages.indexOf(overset[0]) + 1; // console.log("INDEX", index); // // // Remove pages // // this.removePages(index); // // // await this.render(parsed, overset[0].overset); // // // return this.handleOverset(parsed); // } // } async render(parsed, startAt) { let renderer = this.layout(parsed, startAt, this.settings); let done = false; let result; while (!done) { result = await this.q.enqueue(() => { return this.renderAsync(renderer); }); done = result.done; } return result; } start() { this.rendered = false; this.stopped = false; } stop() { this.stopped = true; // this.q.clear(); } renderOnIdle(renderer) { return new Promise(resolve => { requestIdleCallback(async () => { if (this.stopped) { return resolve({ done: true, canceled: true }); } let result = await renderer.next(); if (this.stopped) { resolve({ done: true, canceled: true }); } else { resolve(result); } }); }); } async renderAsync(renderer) { if (this.stopped) { return { done: true, canceled: true }; } let result = await renderer.next(); if (this.stopped) { return { done: true, canceled: true }; } else { return result; } } async handleBreaks(node) { let currentPage = this.total + 1; let currentPosition = currentPage % 2 === 0 ? "left" : "right"; // TODO: Recto and Verso should reverse for rtl languages let currentSide = currentPage % 2 === 0 ? "verso" : "recto"; let previousBreakAfter; let breakBefore; let page; if (currentPage === 1) { return; } if (node && typeof node.dataset !== "undefined" && typeof node.dataset.previousBreakAfter !== "undefined") { previousBreakAfter = node.dataset.previousBreakAfter; } if (node && typeof node.dataset !== "undefined" && typeof node.dataset.breakBefore !== "undefined") { breakBefore = node.dataset.breakBefore; } if( previousBreakAfter && (previousBreakAfter === "left" || previousBreakAfter === "right") && previousBreakAfter !== currentPosition) { page = this.addPage(true); } else if( previousBreakAfter && (previousBreakAfter === "verso" || previousBreakAfter === "recto") && previousBreakAfter !== currentSide) { page = this.addPage(true); } else if( breakBefore && (breakBefore === "left" || breakBefore === "right") && breakBefore !== currentPosition) { page = this.addPage(true); } else if( breakBefore && (breakBefore === "verso" || breakBefore === "recto") && breakBefore !== currentSide) { page = this.addPage(true); } if (page) { await this.hooks.beforePageLayout.trigger(page, undefined, undefined, this); this.emit("page", page); // await this.hooks.layout.trigger(page.element, page, undefined, this); await this.hooks.afterPageLayout.trigger(page.element, page, undefined, this); this.emit("renderedPage", page); } } async *layout(content, startAt) { let breakToken = startAt || false; while (breakToken !== undefined && ( true)) { if (breakToken && breakToken.node) { await this.handleBreaks(breakToken.node); } else { await this.handleBreaks(content.firstChild); } let page = this.addPage(); await this.hooks.beforePageLayout.trigger(page, content, breakToken, this); this.emit("page", page); // Layout content in the page, starting from the breakToken breakToken = await page.layout(content, breakToken, this.maxChars); await this.hooks.afterPageLayout.trigger(page.element, page, breakToken, this); this.emit("renderedPage", page); this.recoredCharLength(page.wrapper.textContent.length); yield breakToken; // Stop if we get undefined, showing we have reached the end of the content } } recoredCharLength(length) { if (length === 0) { return; } this.charsPerBreak.push(length); // Keep the length of the last few breaks if (this.charsPerBreak.length > 4) { this.charsPerBreak.shift(); } this.maxChars = this.charsPerBreak.reduce((a, b) => a + b, 0) / (this.charsPerBreak.length); } removePages(fromIndex=0) { if (fromIndex >= this.pages.length) { return; } // Remove pages for (let i = fromIndex; i < this.pages.length; i++) { this.pages[i].destroy(); } if (fromIndex > 0) { this.pages.splice(fromIndex); } else { this.pages = []; } this.total = this.pages.length; } addPage(blank) { let lastPage = this.pages[this.pages.length - 1]; // Create a new page from the template let page = new Page(this.pagesArea, this.pageTemplate, blank, this.hooks); this.pages.push(page); // Create the pages page.create(undefined, lastPage && lastPage.element); page.index(this.total); if (!blank) { // Listen for page overflow page.onOverflow((overflowToken) => { console.warn("overflow on", page.id, overflowToken); // Only reflow while rendering if (this.rendered) { return; } let index = this.pages.indexOf(page) + 1; // Stop the rendering this.stop(); // Set the breakToken to resume at this.breakToken = overflowToken; // Remove pages this.removePages(index); if (this.rendered === true) { this.rendered = false; this.q.enqueue(async () => { this.start(); await this.render(this.source, this.breakToken); this.rendered = true; }); } }); page.onUnderflow((overflowToken) => { // console.log("underflow on", page.id, overflowToken); // page.append(this.source, overflowToken); }); } this.total = this.pages.length; return page; } /* insertPage(index, blank) { let lastPage = this.pages[index]; // Create a new page from the template let page = new Page(this.pagesArea, this.pageTemplate, blank, this.hooks); let total = this.pages.splice(index, 0, page); // Create the pages page.create(undefined, lastPage && lastPage.element); page.index(index + 1); for (let i = index + 2; i < this.pages.length; i++) { this.pages[i].index(i); } if (!blank) { // Listen for page overflow page.onOverflow((overflowToken) => { if (total < this.pages.length) { this.pages[total].layout(this.source, overflowToken); } else { let newPage = this.addPage(); newPage.layout(this.source, overflowToken); } }); page.onUnderflow(() => { // console.log("underflow on", page.id); }); } this.total += 1; return page; } */ loadFonts() { let fontPromises = []; (document.fonts || []).forEach((fontFace) => { if (fontFace.status !== "loaded") { let fontLoaded = fontFace.load().then((r) => { return fontFace.family; }, (r) => { console.warn("Failed to preload font-family:", fontFace.family); return fontFace.family; }); fontPromises.push(fontLoaded); } }); return Promise.all(fontPromises).catch((err) => { console.warn(err); }); } destroy() { this.pagesArea.remove(); this.pageTemplate.remove(); } } eventEmitter(Chunker.prototype); // // list // ┌──────┐ // ┌──────────────┼─head │ // │ │ tail─┼──────────────┐ // │ └──────┘ │ // ▼ ▼ // item item item item // ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ // null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │ // │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null // ├──────┤ ├──────┤ ├──────┤ ├──────┤ // │ data │ │ data │ │ data │ │ data │ // └──────┘ └──────┘ └──────┘ └──────┘ // function createItem(data) { return { prev: null, next: null, data: data }; } function allocateCursor(node, prev, next) { var cursor; if (cursors !== null) { cursor = cursors; cursors = cursors.cursor; cursor.prev = prev; cursor.next = next; cursor.cursor = node.cursor; } else { cursor = { prev: prev, next: next, cursor: node.cursor }; } node.cursor = cursor; return cursor; } function releaseCursor(node) { var cursor = node.cursor; node.cursor = cursor.cursor; cursor.prev = null; cursor.next = null; cursor.cursor = cursors; cursors = cursor; } var cursors = null; var List = function() { this.cursor = null; this.head = null; this.tail = null; }; List.createItem = createItem; List.prototype.createItem = createItem; List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) { var cursor = this.cursor; while (cursor !== null) { if (cursor.prev === prevOld) { cursor.prev = prevNew; } if (cursor.next === nextOld) { cursor.next = nextNew; } cursor = cursor.cursor; } }; List.prototype.getSize = function() { var size = 0; var cursor = this.head; while (cursor) { size++; cursor = cursor.next; } return size; }; List.prototype.fromArray = function(array) { var cursor = null; this.head = null; for (var i = 0; i < array.length; i++) { var item = createItem(array[i]); if (cursor !== null) { cursor.next = item; } else { this.head = item; } item.prev = cursor; cursor = item; } this.tail = cursor; return this; }; List.prototype.toArray = function() { var cursor = this.head; var result = []; while (cursor) { result.push(cursor.data); cursor = cursor.next; } return result; }; List.prototype.toJSON = List.prototype.toArray; List.prototype.isEmpty = function() { return this.head === null; }; List.prototype.first = function() { return this.head && this.head.data; }; List.prototype.last = function() { return this.tail && this.tail.data; }; List.prototype.each = function(fn, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, null, this.head); while (cursor.next !== null) { item = cursor.next; cursor.next = item.next; fn.call(context, item.data, item, this); } // pop cursor releaseCursor(this); }; List.prototype.forEach = List.prototype.each; List.prototype.eachRight = function(fn, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, this.tail, null); while (cursor.prev !== null) { item = cursor.prev; cursor.prev = item.prev; fn.call(context, item.data, item, this); } // pop cursor releaseCursor(this); }; List.prototype.forEachRight = List.prototype.eachRight; List.prototype.nextUntil = function(start, fn, context) { if (start === null) { return; } var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, null, start); while (cursor.next !== null) { item = cursor.next; cursor.next = item.next; if (fn.call(context, item.data, item, this)) { break; } } // pop cursor releaseCursor(this); }; List.prototype.prevUntil = function(start, fn, context) { if (start === null) { return; } var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, start, null); while (cursor.prev !== null) { item = cursor.prev; cursor.prev = item.prev; if (fn.call(context, item.data, item, this)) { break; } } // pop cursor releaseCursor(this); }; List.prototype.some = function(fn, context) { var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { if (fn.call(context, cursor.data, cursor, this)) { return true; } cursor = cursor.next; } return false; }; List.prototype.map = function(fn, context) { var result = new List(); var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { result.appendData(fn.call(context, cursor.data, cursor, this)); cursor = cursor.next; } return result; }; List.prototype.filter = function(fn, context) { var result = new List(); var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { if (fn.call(context, cursor.data, cursor, this)) { result.appendData(cursor.data); } cursor = cursor.next; } return result; }; List.prototype.clear = function() { this.head = null; this.tail = null; }; List.prototype.copy = function() { var result = new List(); var cursor = this.head; while (cursor !== null) { result.insert(createItem(cursor.data)); cursor = cursor.next; } return result; }; List.prototype.prepend = function(item) { // head // ^ // item this.updateCursors(null, item, this.head, item); // insert to the beginning of the list if (this.head !== null) { // new item <- first item this.head.prev = item; // new item -> first item item.next = this.head; } else { // if list has no head, then it also has no tail // in this case tail points to the new item this.tail = item; } // head always points to new item this.head = item; return this; }; List.prototype.prependData = function(data) { return this.prepend(createItem(data)); }; List.prototype.append = function(item) { return this.insert(item); }; List.prototype.appendData = function(data) { return this.insert(createItem(data)); }; List.prototype.insert = function(item, before) { if (before !== undefined && before !== null) { // prev before // ^ // item this.updateCursors(before.prev, item, before, item); if (before.prev === null) { // insert to the beginning of list if (this.head !== before) { throw new Error('before doesn\'t belong to list'); } // since head points to before therefore list doesn't empty // no need to check tail this.head = item; before.prev = item; item.next = before; this.updateCursors(null, item); } else { // insert between two items before.prev.next = item; item.prev = before.prev; before.prev = item; item.next = before; } } else { // tail // ^ // item this.updateCursors(this.tail, item, null, item); // insert to the ending of the list if (this.tail !== null) { // last item -> new item this.tail.next = item; // last item <- new item item.prev = this.tail; } else { // if list has no tail, then it also has no head // in this case head points to new item this.head = item; } // tail always points to new item this.tail = item; } return this; }; List.prototype.insertData = function(data, before) { return this.insert(createItem(data), before); }; List.prototype.remove = function(item) { // item // ^ // prev next this.updateCursors(item, item.prev, item, item.next); if (item.prev !== null) { item.prev.next = item.next; } else { if (this.head !== item) { throw new Error('item doesn\'t belong to list'); } this.head = item.next; } if (item.next !== null) { item.next.prev = item.prev; } else { if (this.tail !== item) { throw new Error('item doesn\'t belong to list'); } this.tail = item.prev; } item.prev = null; item.next = null; return item; }; List.prototype.push = function(data) { this.insert(createItem(data)); }; List.prototype.pop = function() { if (this.tail !== null) { return this.remove(this.tail); } }; List.prototype.unshift = function(data) { this.prepend(createItem(data)); }; List.prototype.shift = function() { if (this.head !== null) { return this.remove(this.head); } }; List.prototype.prependList = function(list) { return this.insertList(list, this.head); }; List.prototype.appendList = function(list) { return this.insertList(list); }; List.prototype.insertList = function(list, before) { // ignore empty lists if (list.head === null) { return this; } if (before !== undefined && before !== null) { this.updateCursors(before.prev, list.tail, before, list.head); // insert in the middle of dist list if (before.prev !== null) { // before.prev <-> list.head before.prev.next = list.head; list.head.prev = before.prev; } else { this.head = list.head; } before.prev = list.tail; list.tail.next = before; } else { this.updateCursors(this.tail, list.tail, null, list.head); // insert to end of the list if (this.tail !== null) { // if destination list has a tail, then it also has a head, // but head doesn't change // dest tail -> source head this.tail.next = list.head; // dest tail <- source head list.head.prev = this.tail; } else { // if list has no a tail, then it also has no a head // in this case points head to new item this.head = list.head; } // tail always start point to new item this.tail = list.tail; } list.head = null; list.tail = null; return this; }; List.prototype.replace = function(oldItem, newItemOrList) { if ('head' in newItemOrList) { this.insertList(newItemOrList, oldItem); } else { this.insert(newItemOrList, oldItem); } this.remove(oldItem); }; var List_1 = List; var createCustomError = function createCustomError(name, message) { // use Object.create(), because some VMs prevent setting line/column otherwise // (iOS Safari 10 even throws an exception) var error = Object.create(SyntaxError.prototype); var errorStack = new Error(); error.name = name; error.message = message; Object.defineProperty(error, 'stack', { get: function() { return (errorStack.stack || '').replace(/^(.+\n){1,3}/, name + ': ' + message + '\n'); } }); return error; }; var MAX_LINE_LENGTH = 100; var OFFSET_CORRECTION = 60; var TAB_REPLACEMENT = ' '; function sourceFragment(error, extraLines) { function processLines(start, end) { return lines.slice(start, end).map(function(line, idx) { var num = String(start + idx + 1); while (num.length < maxNumLength) { num = ' ' + num; } return num + ' |' + line; }).join('\n'); } var lines = error.source.split(/\r\n?|\n|\f/); var line = error.line; var column = error.column; var startLine = Math.max(1, line - extraLines) - 1; var endLine = Math.min(line + extraLines, lines.length + 1); var maxNumLength = Math.max(4, String(endLine).length) + 1; var cutLeft = 0; // column correction according to replaced tab before column column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length; if (column > MAX_LINE_LENGTH) { cutLeft = column - OFFSET_CORRECTION + 3; column = OFFSET_CORRECTION - 2; } for (var i = startLine; i <= endLine; i++) { if (i >= 0 && i < lines.length) { lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT); lines[i] = (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') + lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) + (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : ''); } } return [ processLines(startLine, line), new Array(column + maxNumLength + 2).join('-') + '^', processLines(line, endLine) ].filter(Boolean).join('\n'); } var SyntaxError$1 = function(message, source, offset, line, column) { var error = createCustomError('SyntaxError', message); error.source = source; error.offset = offset; error.line = line; error.column = column; error.sourceFragment = function(extraLines) { return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines); }; Object.defineProperty(error, 'formattedMessage', { get: function() { return ( 'Parse error: ' + error.message + '\n' + sourceFragment(error, 2) ); } }); // for backward capability error.parseError = { offset: offset, line: line, column: column }; return error; }; var _SyntaxError = SyntaxError$1; // CSS Syntax Module Level 3 // https://www.w3.org/TR/css-syntax-3/ var TYPE = { EOF: 0, // <EOF-token> Ident: 1, // <ident-token> Function: 2, // <function-token> AtKeyword: 3, // <at-keyword-token> Hash: 4, // <hash-token> String: 5, // <string-token> BadString: 6, // <bad-string-token> Url: 7, // <url-token> BadUrl: 8, // <bad-url-token> Delim: 9, // <delim-token> Number: 10, // <number-token> Percentage: 11, // <percentage-token> Dimension: 12, // <dimension-token> WhiteSpace: 13, // <whitespace-token> CDO: 14, // <CDO-token> CDC: 15, // <CDC-token> Colon: 16, // <colon-token> : Semicolon: 17, // <semicolon-token> ; Comma: 18, // <comma-token> , LeftSquareBracket: 19, // <[-token> RightSquareBracket: 20, // <]-token> LeftParenthesis: 21, // <(-token> RightParenthesis: 22, // <)-token> LeftCurlyBracket: 23, // <{-token> RightCurlyBracket: 24, // <}-token> Comment: 25 }; var NAME = Object.keys(TYPE).reduce(function(result, key) { result[TYPE[key]] = key; return result; }, {}); var _const = { TYPE: TYPE, NAME: NAME }; var EOF = 0; // https://drafts.csswg.org/css-syntax-3/ // § 4.2. Definitions // digit // A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9). function isDigit(code) { return code >= 0x0030 && code <= 0x0039; } // hex digit // A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F), // or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f). function isHexDigit(code) { return ( isDigit(code) || // 0 .. 9 (code >= 0x0041 && code <= 0x0046) || // A .. F (code >= 0x0061 && code <= 0x0066) // a .. f ); } // uppercase letter // A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z). function isUppercaseLetter(code) { return code >= 0x0041 && code <= 0x005A; } // lowercase letter // A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z). function isLowercaseLetter(code) { return code >= 0x0061 && code <= 0x007A; } // letter // An uppercase letter or a lowercase letter. function isLetter(code) { return isUppercaseLetter(code) || isLowercaseLetter(code); } // non-ASCII code point // A code point with a value equal to or greater than U+0080 <control>. function isNonAscii(code) { return code >= 0x0080; } // name-start code point // A letter, a non-ASCII code point, or U+005F LOW LINE (_). function isNameStart(code) { return isLetter(code) || isNonAscii(code) || code === 0x005F; } // name code point // A name-start code point, a digit, or U+002D HYPHEN-MINUS (-). function isName(code) { return isNameStart(code) || isDigit(code) || code === 0x002D; } // non-printable code point // A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION, // or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE. function isNonPrintable(code) { return ( (code >= 0x0000 && code <= 0x0008) || (code === 0x000B) || (code >= 0x000E && code <= 0x001F) || (code === 0x007F) ); } // newline // U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition, // as they are converted to U+000A LINE FEED during preprocessing. // TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED function isNewline(code) { return code === 0x000A || code === 0x000D || code === 0x000C; } // whitespace // A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE. function isWhiteSpace(code) { return isNewline(code) || code === 0x0020 || code === 0x0009; } // § 4.3.8. Check if two code points are a valid escape function isValidEscape(first, second) { // If the first code point is not U+005C REVERSE SOLIDUS (\), return false. if (first !== 0x005C) { return false; } // Otherwise, if the second code point is a newline or EOF, return false. if (isNewline(second) || second === EOF) { return false; } // Otherwise, return true. return true; } // § 4.3.9. Check if three code points would start an identifier function isIdentifierStart(first, second, third) { // Look at the first code point: // U+002D HYPHEN-MINUS if (first === 0x002D) { // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS, // or the second and third code points are a valid escape, return true. Otherwise, return false. return ( isNameStart(second) || second === 0x002D || isValidEscape(second, third) ); } // name-start code point if (isNameStart(first)) { // Return true. return true; } // U+005C REVERSE SOLIDUS (\) if (first === 0x005C) { // If the first and second code points are a valid escape, return true. Otherwise, return false. return isValidEscape(first, second); } // anything else // Return false. return false; } // § 4.3.10. Check if three code points would start a number function isNumberStart(first, second, third) { // Look at the first code point: // U+002B PLUS SIGN (+) // U+002D HYPHEN-MINUS (-) if (first === 0x002B || first === 0x002D) { // If the second code point is a digit, return true. if (isDigit(second)) { return 2; } // Otherwise, if the second code point is a U+002E FULL STOP (.) // and the third code point is a digit, return true. // Otherwise, return false. return second === 0x002E && isDigit(third) ? 3 : 0; } // U+002E FULL STOP (.) if (first === 0x002E) { // If the second code point is a digit, return true. Otherwise, return false. return isDigit(second) ? 2 : 0; } // digit if (isDigit(first)) { // Return true. return 1; } // anything else // Return false. return 0; } // // Misc // // detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark) function isBOM(code) { // UTF-16BE if (code === 0xFEFF) { return 1; } // UTF-16LE if (code === 0xFFFE) { return 1; } return 0; } // Fast code category // // https://drafts.csswg.org/css-syntax/#tokenizer-definitions // > non-ASCII code point // > A code point with a value equal to or greater than U+0080 <control> // > name-start code point // > A letter, a non-ASCII code point, or U+005F LOW LINE (_). // > name code point // > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-) // That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only var CATEGORY = new Array(0x80); charCodeCategory.Eof = 0x80; charCodeCategory.WhiteSpace = 0x82; charCodeCategory.Digit = 0x83; charCodeCategory.NameStart = 0x84; charCodeCategory.NonPrintable = 0x85; for (var i = 0; i < CATEGORY.length; i++) { switch (true) { case isWhiteSpace(i): CATEGORY[i] = charCodeCategory.WhiteSpace; break; case isDigit(i): CATEGORY[i] = charCodeCategory.Digit; break; case isNameStart(i): CATEGORY[i] = charCodeCategory.NameStart; break; case isNonPrintable(i): CATEGORY[i] = charCodeCategory.NonPrintable; break; default: CATEGORY[i] = i || charCodeCategory.Eof; } } function charCodeCategory(code) { return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart; } var charCodeDefinitions = { isDigit: isDigit, isHexDigit: isHexDigit, isUppercaseLetter: isUppercaseLetter, isLowercaseLetter: isLowercaseLetter, isLetter: isLetter, isNonAscii: isNonAscii, isNameStart: isNameStart, isName: isName, isNonPrintable: isNonPrintable, isNewline: isNewline, isWhiteSpace: isWhiteSpace, isValidEscape: isValidEscape, isIdentifierStart: isIdentifierStart, isNumberStart: isNumberStart, isBOM: isBOM, charCodeCategory: charCodeCategory }; var isDigit$1 = charCodeDefinitions.isDigit; var isHexDigit$1 = charCodeDefinitions.isHexDigit; var isUppercaseLetter$1 = charCodeDefinitions.isUppercaseLetter; var isName$1 = charCodeDefinitions.isName; var isWhiteSpace$1 = charCodeDefinitions.isWhiteSpace; var isValidEscape$1 = charCodeDefinitions.isValidEscape; function getCharCode(source, offset) { return offset < source.length ? source.charCodeAt(offset) : 0; } function getNewlineLength(source, offset, code) { if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) { return 2; } return 1; } function cmpChar(testStr, offset, referenceCode) { var code = testStr.charCodeAt(offset); // code.toLowerCase() for A..Z if (isUppercaseLetter$1(code)) { code = code | 32; } return code === referenceCode; } function cmpStr(testStr, start, end, referenceStr) { if (end - start !== referenceStr.length) { return false; } if (start < 0 || end > testStr.length) { return false; } for (var i = start; i < end; i++) { var testCode = testStr.charCodeAt(i); var referenceCode = referenceStr.charCodeAt(i - start); // testCode.toLowerCase() for A..Z if (isUppercaseLetter$1(testCode)) { testCode = testCode | 32; } if (testCode !== referenceCode) { return false; } } return true; } function findWhiteSpaceStart(source, offset) { for (; offset >= 0; offset--) { if (!isWhiteSpace$1(source.charCodeAt(offset))) { break; } } return offset + 1; } function findWhiteSpaceEnd(source, offset) { for (; offset < source.length; offset++) { if (!isWhiteSpace$1(source.charCodeAt(offset))) { break; } } return offset; } function findDecimalNumberEnd(source, offset) { for (; offset < source.length; offset++) { if (!isDigit$1(source.charCodeAt(offset))) { break; } } return offset; } // § 4.3.7. Consume an escaped code point function consumeEscaped(source, offset) { // It assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed and // that the next input code point has already been verified to be part of a valid escape. offset += 2; // hex digit if (isHexDigit$1(getCharCode(source, offset - 1))) { // Consume as many hex digits as possible, but no more than 5. // Note that this means 1-6 hex digits have been consumed in total. for (var maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) { if (!isHexDigit$1(getCharCode(source, offset))) { break; } } // If the next input code point is whitespace, consume it as well. var code = getCharCode(source, offset); if (isWhiteSpace$1(code)) { offset += getNewlineLength(source, offset, code); } } return offset; } // §4.3.11. Consume a name // Note: This algorithm does not do the verification of the first few code points that are necessary // to ensure the returned code points would constitute an <ident-token>. If that is the intended use, // ensure that the stream starts with an identifier before calling this algorithm. function consumeName(source, offset) { // Let result initially be an empty string. // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); // name code point if (isName$1(code)) { // Append the code point to result. continue; } // the stream starts with a valid escape if (isValidEscape$1(code, getCharCode(source, offset + 1))) { // Consume an escaped code point. Append the returned code point to result. offset = consumeEscaped(source, offset) - 1; continue; } // anything else // Reconsume the current input code point. Return result. break; } return offset; } // §4.3.12. Consume a number function consumeNumber(source, offset) { var code = source.charCodeAt(offset); // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-), // consume it and append it to repr. if (code === 0x002B || code === 0x002D) { code = source.charCodeAt(offset += 1); } // 3. While the next input code point is a digit, consume it and append it to repr. if (isDigit$1(code)) { offset = findDecimalNumberEnd(source, offset + 1); code = source.charCodeAt(offset); } // 4. If the next 2 input code points are U+002E FULL STOP (.) followed by a digit, then: if (code === 0x002E && isDigit$1(source.charCodeAt(offset + 1))) { // 4.1 Consume them. // 4.2 Append them to repr. code = source.charCodeAt(offset += 2); // 4.3 Set type to "number". // TODO // 4.4 While the next input code point is a digit, consume it and append it to repr. offset = findDecimalNumberEnd(source, offset); } // 5. If the next 2 or 3 input code points are U+0045 LATIN CAPITAL LETTER E (E) // or U+0065 LATIN SMALL LETTER E (e), ... , followed by a digit, then: if (cmpChar(source, offset, 101 /* e */)) { var sign = 0; code = source.charCodeAt(offset + 1); // ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ... if (code === 0x002D || code === 0x002B) { sign = 1; code = source.charCodeAt(offset + 2); } // ... followed by a digit if (isDigit$1(code)) { // 5.1 Consume them. // 5.2 Append them to repr. // 5.3 Set type to "number". // TODO // 5.4 While the next input code point is a digit, consume it and append it to repr. offset = findDecimalNumberEnd(source, offset + 1 + sign + 1); } } return offset; } // § 4.3.14. Consume the remnants of a bad url // ... its sole use is to consume enough of the input stream to reach a recovery point // where normal tokenizing can resume. function consumeBadUrlRemnants(source, offset) { // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); // U+0029 RIGHT PARENTHESIS ()) // EOF if (code === 0x0029) { // Return. offset++; break; } if (isValidEscape$1(code, getCharCode(source, offset + 1))) { // Consume an escaped code point. // Note: This allows an escaped right parenthesis ("\)") to be encountered // without ending the <bad-url-token>. This is otherwise identical to // the "anything else" clause. offset = consumeEscaped(source, offset); } } return offset; } var utils = { consumeEscaped: consumeEscaped, consumeName: consumeName, consumeNumber: consumeNumber, consumeBadUrlRemnants: consumeBadUrlRemnants, cmpChar: cmpChar, cmpStr: cmpStr, getNewlineLength: getNewlineLength, findWhiteSpaceStart: findWhiteSpaceStart, findWhiteSpaceEnd: findWhiteSpaceEnd }; var TYPE$1 = _const.TYPE; var NAME$1 = _const.NAME; var cmpStr$1 = utils.cmpStr; var EOF$1 = TYPE$1.EOF; var WHITESPACE = TYPE$1.WhiteSpace; var COMMENT = TYPE$1.Comment; var OFFSET_MASK = 0x00FFFFFF; var TYPE_SHIFT = 24; var TokenStream = function() { this.offsetAndType = null; this.balance = null; this.reset(); }; TokenStream.prototype = { reset: function() { this.eof = false; this.tokenIndex = -1; this.tokenType = 0; this.tokenStart = this.firstCharOffset; this.tokenEnd = this.firstCharOffset; }, lookupType: function(offset) { offset += this.tokenIndex; if (offset < this.tokenCount) { return this.offsetAndType[offset] >> TYPE_SHIFT; } return EOF$1; }, lookupOffset: function(offset) { offset += this.tokenIndex; if (offset < this.tokenCount) { return this.offsetAndType[offset - 1] & OFFSET_MASK; } return this.source.length; }, lookupValue: function(offset, referenceStr) { offset += this.tokenIndex; if (offset < this.tokenCount) { return cmpStr$1( this.source, this.offsetAndType[offset - 1] & OFFSET_MASK, this.offsetAndType[offset] & OFFSET_MASK, referenceStr ); } return false; }, getTokenStart: function(tokenIndex) { if (tokenIndex === this.tokenIndex) { return this.tokenStart; } if (tokenIndex > 0) { return tokenIndex < this.tokenCount ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK : this.offsetAndType[this.tokenCount] & OFFSET_MASK; } return this.firstCharOffset; }, // TODO: -> skipUntilBalanced getRawLength: function(startToken, mode) { var cursor = startToken; var balanceEnd; var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK; var type; loop: for (; cursor < this.tokenCount; cursor++) { balanceEnd = this.balance[cursor]; // stop scanning on balance edge that points to offset before start token if (balanceEnd < startToken) { break loop; } type = this.offsetAndType[cursor] >> TYPE_SHIFT; // check token is stop type switch (mode(type, this.source, offset)) { case 1: break loop; case 2: cursor++; break loop; default: offset = this.offsetAndType[cursor] & OFFSET_MASK; // fast forward to the end of balanced block if (this.balance[balanceEnd] === cursor) { cursor = balanceEnd; } } } return cursor - this.tokenIndex; }, isBalanceEdge: function(pos) { return this.balance[this.tokenIndex] < pos; }, isDelim: function(code, offset) { if (offset) { return ( this.lookupType(offset) === TYPE$1.Delim && this.source.charCodeAt(this.lookupOffset(offset)) === code ); } return ( this.tokenType === TYPE$1.Delim && this.source.charCodeAt(this.tokenStart) === code ); }, getTokenValue: function() { return this.source.substring(this.tokenStart, this.tokenEnd); }, getTokenLength: function() { return this.tokenEnd - this.tokenStart; }, substrToCursor: function(start) { return this.source.substring(start, this.tokenStart); }, skipWS: function() { for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) { if ((this.offsetAndType[i] >> TYPE_SHIFT) !== WHITESPACE) { break; } } if (skipTokenCount > 0) { this.skip(skipTokenCount); } }, skipSC: function() { while (this.tokenType === WHITESPACE || this.tokenType === COMMENT) { this.next(); } }, skip: function(tokenCount) { var next = this.tokenIndex + tokenCount; if (next < this.tokenCount) { this.tokenIndex = next; this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK; next = this.offsetAndType[next]; this.tokenType = next >> TYPE_SHIFT; this.tokenEnd = next & OFFSET_MASK; } else { this.tokenIndex = this.tokenCount; this.next(); } }, next: function() { var next = this.tokenIndex + 1; if (next < this.tokenCount) { this.tokenIndex = next; this.tokenStart = this.tokenEnd; next = this.offsetAndType[next]; this.tokenType = next >> TYPE_SHIFT; this.tokenEnd = next & OFFSET_MASK; } else { this.tokenIndex = this.tokenCount; this.eof = true; this.tokenType = EOF$1; this.tokenStart = this.tokenEnd = this.source.length; } }, dump: function() { var offset = this.firstCharOffset; return Array.prototype.slice.call(this.offsetAndType, 0, this.tokenCount).map(function(item, idx) { var start = offset; var end = item & OFFSET_MASK; offset = end; return { idx: idx, type: NAME$1[item >> TYPE_SHIFT], chunk: this.source.substring(start, end), balance: this.balance[idx] }; }, this); } }; var TokenStream_1 = TokenStream; function noop$1(value) { return value; } function generateMultiplier(multiplier) { if (multiplier.min === 0 && multiplier.max === 0) { return '*'; } if (multiplier.min === 0 && multiplier.max === 1) { return '?'; } if (multiplier.min === 1 && multiplier.max === 0) { return multiplier.comma ? '#' : '+'; } if (multiplier.min === 1 && multiplier.max === 1) { return ''; } return ( (multiplier.comma ? '#' : '') + (multiplier.min === multiplier.max ? '{' + multiplier.min + '}' : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}' ) ); } function generateTypeOpts(node) { switch (node.type) { case 'Range': return ( ' [' + (node.min === null ? '-∞' : node.min) + ',' + (node.max === null ? '∞' : node.max) + ']' ); default: throw new Error('Unknown node type `' + node.type + '`'); } } function generateSequence(node, decorate, forceBraces, compact) { var combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' '; var result = node.terms.map(function(term) { return generate(term, decorate, forceBraces, compact); }).join(combinator); if (node.explicit || forceBraces) { result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]'); } return result; } function generate(node, decorate, forceBraces, compact) { var result; switch (node.type) { case 'Group': result = generateSequence(node, decorate, forceBraces, compact) + (node.disallowEmpty ? '!' : ''); break; case 'Multiplier': // return since node is a composition return ( generate(node.term, decorate, forceBraces, compact) + decorate(generateMultiplier(node), node) ); case 'Type': result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>'; break; case 'Property': result = '<\'' + node.name + '\'>'; break; case 'Keyword': result = node.name; break; case 'AtKeyword': result = '@' + node.name; break; case 'Function': result = node.name + '('; break; case 'String': case 'Token': result = node.value; break; case 'Comma': result = ','; break; default: throw new Error('Unknown node type `' + node.type + '`'); } return decorate(result, node); } var generate_1 = function(node, options) { var decorate = noop$1; var forceBraces = false; var compact = false; if (typeof options === 'function') { decorate = options; } else if (options) { forceBraces = Boolean(options.forceBraces); compact = Boolean(options.compact); if (typeof options.decorate === 'function') { decorate = options.decorate; } } return generate(node, decorate, forceBraces, compact); }; function fromMatchResult(matchResult) { var tokens = matchResult.tokens; var longestMatch = matchResult.longestMatch; var node = longestMatch < tokens.length ? tokens[longestMatch].node : null; var mismatchOffset = -1; var entries = 0; var css = ''; for (var i = 0; i < tokens.length; i++) { if (i === longestMatch) { mismatchOffset = css.length; } if (node !== null && tokens[i].node === node) { if (i <= longestMatch) { entries++; } else { entries = 0; } } css += tokens[i].value; } return { node: node, css: css, mismatchOffset: mismatchOffset === -1 ? css.length : mismatchOffset, last: node === null || entries > 1 }; } function getLocation(node, point) { var loc = node && node.loc && node.loc[point]; if (loc) { return { offset: loc.offset, line: loc.line, column: loc.column }; } return null; } var SyntaxReferenceError = function(type, referenceName) { var error = createCustomError( 'SyntaxReferenceError', type + (referenceName ? ' `' + referenceName + '`' : '') ); error.reference = referenceName; return error; }; var MatchError = function(message, syntax, node, matchResult) { var error = createCustomError('SyntaxMatchError', message); var details = fromMatchResult(matchResult); var mismatchOffset = details.mismatchOffset || 0; var badNode = details.node || node; var end = getLocation(badNode, 'end'); var start = details.last ? end : getLocation(badNode, 'start'); var css = details.css; error.rawMessage = message; error.syntax = syntax ? generate_1(syntax) : '<generic>'; error.css = css; error.mismatchOffset = mismatchOffset; error.loc = { source: (badNode && badNode.loc && badNode.loc.source) || '<unknown>', start: start, end: end }; error.line = start ? start.line : undefined; error.column = start ? start.column : undefined; error.offset = start ? start.offset : undefined; error.message = message + '\n' + ' syntax: ' + error.syntax + '\n' + ' value: ' + (error.css || '<empty string>') + '\n' + ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^'; return error; }; var error = { SyntaxReferenceError: SyntaxReferenceError, MatchError: MatchError }; var hasOwnProperty = Object.prototype.hasOwnProperty; var keywords = Object.create(null); var properties = Object.create(null); var HYPHENMINUS = 45; // '-'.charCodeAt() function isCustomProperty(str, offset) { offset = offset || 0; return str.length - offset >= 2 && str.charCodeAt(offset) === HYPHENMINUS && str.charCodeAt(offset + 1) === HYPHENMINUS; } function getVendorPrefix(str, offset) { offset = offset || 0; // verdor prefix should be at least 3 chars length if (str.length - offset >= 3) { // vendor prefix starts with hyper minus following non-hyper minus if (str.charCodeAt(offset) === HYPHENMINUS && str.charCodeAt(offset + 1) !== HYPHENMINUS) { // vendor prefix should contain a hyper minus at the ending var secondDashIndex = str.indexOf('-', offset + 2); if (secondDashIndex !== -1) { return str.substring(offset, secondDashIndex + 1); } } } return ''; } function getKeywordDescriptor(keyword) { if (hasOwnProperty.call(keywords, keyword)) { return keywords[keyword]; } var name = keyword.toLowerCase(); if (hasOwnProperty.call(keywords, name)) { return keywords[keyword] = keywords[name]; } var custom = isCustomProperty(name, 0); var vendor = !custom ? getVendorPrefix(name, 0) : ''; return keywords[keyword] = Object.freeze({ basename: name.substr(vendor.length), name: name, vendor: vendor, prefix: vendor, custom: custom }); } function getPropertyDescriptor(property) { if (hasOwnProperty.call(properties, property)) { return properties[property]; } var name = property; var hack = property[0]; if (hack === '/') { hack = property[1] === '/' ? '//' : '/'; } else if (hack !== '_' && hack !== '*' && hack !== '$' && hack !== '#' && hack !== '+' && hack !== '&') { hack = ''; } var custom = isCustomProperty(name, hack.length); // re-use result when possible (the same as for lower case) if (!custom) { name = name.toLowerCase(); if (hasOwnProperty.call(properties, name)) { return properties[property] = properties[name]; } } var vendor = !custom ? getVendorPrefix(name, hack.length) : ''; var prefix = name.substr(0, hack.length + vendor.length); return properties[property] = Object.freeze({ basename: name.substr(prefix.length), name: name.substr(hack.length), hack: hack, vendor: vendor, prefix: prefix, custom: custom }); } var names = { keyword: getKeywordDescriptor, property: getPropertyDescriptor, isCustomProperty: isCustomProperty, vendorPrefix: getVendorPrefix }; var MIN_SIZE = 16 * 1024; var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported var adoptBuffer = function adoptBuffer(buffer, size) { if (buffer === null || buffer.length < size) { return new SafeUint32Array(Math.max(size + 1024, MIN_SIZE)); } return buffer; }; var TYPE$2 = _const.TYPE; var isNewline$1 = charCodeDefinitions.isNewline; var isName$2 = charCodeDefinitions.isName; var isValidEscape$2 = charCodeDefinitions.isValidEscape; var isNumberStart$1 = charCodeDefinitions.isNumberStart; var isIdentifierStart$1 = charCodeDefinitions.isIdentifierStart; var charCodeCategory$1 = charCodeDefinitions.charCodeCategory; var isBOM$1 = charCodeDefinitions.isBOM; var cmpStr$2 = utils.cmpStr; var getNewlineLength$1 = utils.getNewlineLength; var findWhiteSpaceEnd$1 = utils.findWhiteSpaceEnd; var consumeEscaped$1 = utils.consumeEscaped; var consumeName$1 = utils.consumeName; var consumeNumber$1 = utils.consumeNumber; var consumeBadUrlRemnants$1 = utils.consumeBadUrlRemnants; var OFFSET_MASK$1 = 0x00FFFFFF; var TYPE_SHIFT$1 = 24; function tokenize(source, stream) { function getCharCode(offset) { return offset < sourceLength ? source.charCodeAt(offset) : 0; } // § 4.3.3. Consume a numeric token function consumeNumericToken() { // Consume a number and let number be the result. offset = consumeNumber$1(source, offset); // If the next 3 input code points would start an identifier, then: if (isIdentifierStart$1(getCharCode(offset), getCharCode(offset + 1), getCharCode(offset + 2))) { // Create a <dimension-token> with the same value and type flag as number, and a unit set initially to the empty string. // Consume a name. Set the <dimension-token>’s unit to the returned value. // Return the <dimension-token>. type = TYPE$2.Dimension; offset = consumeName$1(source, offset); return; } // Otherwise, if the next input code point is U+0025 PERCENTAGE SIGN (%), consume it. if (getCharCode(offset) === 0x0025) { // Create a <percentage-token> with the same value as number, and return it. type = TYPE$2.Percentage; offset++; return; } // Otherwise, create a <number-token> with the same value and type flag as number, and return it. type = TYPE$2.Number; } // § 4.3.4. Consume an ident-like token function consumeIdentLikeToken() { const nameStartOffset = offset; // Consume a name, and let string be the result. offset = consumeName$1(source, offset); // If string’s value is an ASCII case-insensitive match for "url", // and the next input code point is U+0028 LEFT PARENTHESIS ((), consume it. if (cmpStr$2(source, nameStartOffset, offset, 'url') && getCharCode(offset) === 0x0028) { // While the next two input code points are whitespace, consume the next input code point. offset = findWhiteSpaceEnd$1(source, offset + 1); // If the next one or two input code points are U+0022 QUOTATION MARK ("), U+0027 APOSTROPHE ('), // or whitespace followed by U+0022 QUOTATION MARK (") or U+0027 APOSTROPHE ('), // then create a <function-token> with its value set to string and return it. if (getCharCode(offset) === 0x0022 || getCharCode(offset) === 0x0027) { type = TYPE$2.Function; offset = nameStartOffset + 4; return; } // Otherwise, consume a url token, and return it. consumeUrlToken(); return; } // Otherwise, if the next input code point is U+0028 LEFT PARENTHESIS ((), consume it. // Create a <function-token> with its value set to string and return it. if (getCharCode(offset) === 0x0028) { type = TYPE$2.Function; offset++; return; } // Otherwise, create an <ident-token> with its value set to string and return it. type = TYPE$2.Ident; } // § 4.3.5. Consume a string token function consumeStringToken(endingCodePoint) { // This algorithm may be called with an ending code point, which denotes the code point // that ends the string. If an ending code point is not specified, // the current input code point is used. if (!endingCodePoint) { endingCodePoint = getCharCode(offset++); } // Initially create a <string-token> with its value set to the empty string. type = TYPE$2.String; // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); switch (charCodeCategory$1(code)) { // ending code point case endingCodePoint: // Return the <string-token>. offset++; return; // EOF case charCodeCategory$1.Eof: // This is a parse error. Return the <string-token>. return; // newline case charCodeCategory$1.WhiteSpace: if (isNewline$1(code)) { // This is a parse error. Reconsume the current input code point, // create a <bad-string-token>, and return it. offset += getNewlineLength$1(source, offset, code); type = TYPE$2.BadString; return; } break; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the next input code point is EOF, do nothing. if (offset === source.length - 1) { break; } var nextCode = getCharCode(offset + 1); // Otherwise, if the next input code point is a newline, consume it. if (isNewline$1(nextCode)) { offset += getNewlineLength$1(source, offset + 1, nextCode); } else if (isValidEscape$2(code, nextCode)) { // Otherwise, (the stream starts with a valid escape) consume // an escaped code point and append the returned code point to // the <string-token>’s value. offset = consumeEscaped$1(source, offset) - 1; } break; // anything else // Append the current input code point to the <string-token>’s value. } } } // § 4.3.6. Consume a url token // Note: This algorithm assumes that the initial "url(" has already been consumed. // This algorithm also assumes that it’s being called to consume an "unquoted" value, like url(foo). // A quoted value, like url("foo"), is parsed as a <function-token>. Consume an ident-like token // automatically handles this distinction; this algorithm shouldn’t be called directly otherwise. function consumeUrlToken() { // Initially create a <url-token> with its value set to the empty string. type = TYPE$2.Url; // Consume as much whitespace as possible. offset = findWhiteSpaceEnd$1(source, offset); // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); switch (charCodeCategory$1(code)) { // U+0029 RIGHT PARENTHESIS ()) case 0x0029: // Return the <url-token>. offset++; return; // EOF case charCodeCategory$1.Eof: // This is a parse error. Return the <url-token>. return; // whitespace case charCodeCategory$1.WhiteSpace: // Consume as much whitespace as possible. offset = findWhiteSpaceEnd$1(source, offset); // If the next input code point is U+0029 RIGHT PARENTHESIS ()) or EOF, // consume it and return the <url-token> // (if EOF was encountered, this is a parse error); if (getCharCode(offset) === 0x0029 || offset >= source.length) { if (offset < source.length) { offset++; } return; } // otherwise, consume the remnants of a bad url, create a <bad-url-token>, // and return it. offset = consumeBadUrlRemnants$1(source, offset); type = TYPE$2.BadUrl; return; // U+0022 QUOTATION MARK (") // U+0027 APOSTROPHE (') // U+0028 LEFT PARENTHESIS (() // non-printable code point case 0x0022: case 0x0027: case 0x0028: case charCodeCategory$1.NonPrintable: // This is a parse error. Consume the remnants of a bad url, // create a <bad-url-token>, and return it. offset = consumeBadUrlRemnants$1(source, offset); type = TYPE$2.BadUrl; return; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the stream starts with a valid escape, consume an escaped code point and // append the returned code point to the <url-token>’s value. if (isValidEscape$2(code, getCharCode(offset + 1))) { offset = consumeEscaped$1(source, offset) - 1; break; } // Otherwise, this is a parse error. Consume the remnants of a bad url, // create a <bad-url-token>, and return it. offset = consumeBadUrlRemnants$1(source, offset); type = TYPE$2.BadUrl; return; // anything else // Append the current input code point to the <url-token>’s value. } } } if (!stream) { stream = new TokenStream_1(); } // ensure source is a string source = String(source || ''); var sourceLength = source.length; var offsetAndType = adoptBuffer(stream.offsetAndType, sourceLength + 1); // +1 because of eof-token var balance = adoptBuffer(stream.balance, sourceLength + 1); var tokenCount = 0; var start = isBOM$1(getCharCode(0)); var offset = start; var balanceCloseType = 0; var balanceStart = 0; var balancePrev = 0; // https://drafts.csswg.org/css-syntax-3/#consume-token // § 4.3.1. Consume a token while (offset < sourceLength) { var code = source.charCodeAt(offset); var type = 0; balance[tokenCount] = sourceLength; switch (charCodeCategory$1(code)) { // whitespace case charCodeCategory$1.WhiteSpace: // Consume as much whitespace as possible. Return a <whitespace-token>. type = TYPE$2.WhiteSpace; offset = findWhiteSpaceEnd$1(source, offset + 1); break; // U+0022 QUOTATION MARK (") case 0x0022: // Consume a string token and return it. consumeStringToken(); break; // U+0023 NUMBER SIGN (#) case 0x0023: // If the next input code point is a name code point or the next two input code points are a valid escape, then: if (isName$2(getCharCode(offset + 1)) || isValidEscape$2(getCharCode(offset + 1), getCharCode(offset + 2))) { // Create a <hash-token>. type = TYPE$2.Hash; // If the next 3 input code points would start an identifier, set the <hash-token>’s type flag to "id". // if (isIdentifierStart(getCharCode(offset + 1), getCharCode(offset + 2), getCharCode(offset + 3))) { // // TODO: set id flag // } // Consume a name, and set the <hash-token>’s value to the returned string. offset = consumeName$1(source, offset + 1); // Return the <hash-token>. } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+0027 APOSTROPHE (') case 0x0027: // Consume a string token and return it. consumeStringToken(); break; // U+0028 LEFT PARENTHESIS (() case 0x0028: // Return a <(-token>. type = TYPE$2.LeftParenthesis; offset++; break; // U+0029 RIGHT PARENTHESIS ()) case 0x0029: // Return a <)-token>. type = TYPE$2.RightParenthesis; offset++; break; // U+002B PLUS SIGN (+) case 0x002B: // If the input stream starts with a number, ... if (isNumberStart$1(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+002C COMMA (,) case 0x002C: // Return a <comma-token>. type = TYPE$2.Comma; offset++; break; // U+002D HYPHEN-MINUS (-) case 0x002D: // If the input stream starts with a number, reconsume the current input code point, consume a numeric token, and return it. if (isNumberStart$1(code, getCharCode(offset + 1), getCharCode(offset + 2))) { consumeNumericToken(); } else { // Otherwise, if the next 2 input code points are U+002D HYPHEN-MINUS U+003E GREATER-THAN SIGN (->), consume them and return a <CDC-token>. if (getCharCode(offset + 1) === 0x002D && getCharCode(offset + 2) === 0x003E) { type = TYPE$2.CDC; offset = offset + 3; } else { // Otherwise, if the input stream starts with an identifier, ... if (isIdentifierStart$1(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } } } break; // U+002E FULL STOP (.) case 0x002E: // If the input stream starts with a number, ... if (isNumberStart$1(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+002F SOLIDUS (/) case 0x002F: // If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A ASTERISK (*), if (getCharCode(offset + 1) === 0x002A) { // ... consume them and all following code points up to and including the first U+002A ASTERISK (*) // followed by a U+002F SOLIDUS (/), or up to an EOF code point. type = TYPE$2.Comment; offset = source.indexOf('*/', offset + 2) + 2; if (offset === 1) { offset = source.length; } } else { type = TYPE$2.Delim; offset++; } break; // U+003A COLON (:) case 0x003A: // Return a <colon-token>. type = TYPE$2.Colon; offset++; break; // U+003B SEMICOLON (;) case 0x003B: // Return a <semicolon-token>. type = TYPE$2.Semicolon; offset++; break; // U+003C LESS-THAN SIGN (<) case 0x003C: // If the next 3 input code points are U+0021 EXCLAMATION MARK U+002D HYPHEN-MINUS U+002D HYPHEN-MINUS (!--), ... if (getCharCode(offset + 1) === 0x0021 && getCharCode(offset + 2) === 0x002D && getCharCode(offset + 3) === 0x002D) { // ... consume them and return a <CDO-token>. type = TYPE$2.CDO; offset = offset + 4; } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+0040 COMMERCIAL AT (@) case 0x0040: // If the next 3 input code points would start an identifier, ... if (isIdentifierStart$1(getCharCode(offset + 1), getCharCode(offset + 2), getCharCode(offset + 3))) { // ... consume a name, create an <at-keyword-token> with its value set to the returned value, and return it. type = TYPE$2.AtKeyword; offset = consumeName$1(source, offset + 1); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+005B LEFT SQUARE BRACKET ([) case 0x005B: // Return a <[-token>. type = TYPE$2.LeftSquareBracket; offset++; break; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the input stream starts with a valid escape, ... if (isValidEscape$2(code, getCharCode(offset + 1))) { // ... reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); } else { // Otherwise, this is a parse error. Return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } break; // U+005D RIGHT SQUARE BRACKET (]) case 0x005D: // Return a <]-token>. type = TYPE$2.RightSquareBracket; offset++; break; // U+007B LEFT CURLY BRACKET ({) case 0x007B: // Return a <{-token>. type = TYPE$2.LeftCurlyBracket; offset++; break; // U+007D RIGHT CURLY BRACKET (}) case 0x007D: // Return a <}-token>. type = TYPE$2.RightCurlyBracket; offset++; break; // digit case charCodeCategory$1.Digit: // Reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); break; // name-start code point case charCodeCategory$1.NameStart: // Reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); break; // EOF case charCodeCategory$1.Eof: // Return an <EOF-token>. break; // anything else default: // Return a <delim-token> with its value set to the current input code point. type = TYPE$2.Delim; offset++; } switch (type) { case balanceCloseType: balancePrev = balanceStart & OFFSET_MASK$1; balanceStart = balance[balancePrev]; balanceCloseType = balanceStart >> TYPE_SHIFT$1; balance[tokenCount] = balancePrev; balance[balancePrev++] = tokenCount; for (; balancePrev < tokenCount; balancePrev++) { if (balance[balancePrev] === sourceLength) { balance[balancePrev] = tokenCount; } } break; case TYPE$2.LeftParenthesis: case TYPE$2.Function: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$2.RightParenthesis; balanceStart = (balanceCloseType << TYPE_SHIFT$1) | tokenCount; break; case TYPE$2.LeftSquareBracket: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$2.RightSquareBracket; balanceStart = (balanceCloseType << TYPE_SHIFT$1) | tokenCount; break; case TYPE$2.LeftCurlyBracket: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$2.RightCurlyBracket; balanceStart = (balanceCloseType << TYPE_SHIFT$1) | tokenCount; break; } offsetAndType[tokenCount++] = (type << TYPE_SHIFT$1) | offset; } // finalize buffers offsetAndType[tokenCount] = (TYPE$2.EOF << TYPE_SHIFT$1) | offset; // <EOF-token> balance[tokenCount] = sourceLength; balance[sourceLength] = sourceLength; // prevents false positive balance match with any token while (balanceStart !== 0) { balancePrev = balanceStart & OFFSET_MASK$1; balanceStart = balance[balancePrev]; balance[balancePrev] = sourceLength; } // update stream stream.source = source; stream.firstCharOffset = start; stream.offsetAndType = offsetAndType; stream.tokenCount = tokenCount; stream.balance = balance; stream.reset(); stream.next(); return stream; } // extend tokenizer with constants Object.keys(_const).forEach(function(key) { tokenize[key] = _const[key]; }); // extend tokenizer with static methods from utils Object.keys(charCodeDefinitions).forEach(function(key) { tokenize[key] = charCodeDefinitions[key]; }); Object.keys(utils).forEach(function(key) { tokenize[key] = utils[key]; }); var tokenizer = tokenize; var isDigit$2 = tokenizer.isDigit; var cmpChar$1 = tokenizer.cmpChar; var TYPE$3 = tokenizer.TYPE; var DELIM = TYPE$3.Delim; var WHITESPACE$1 = TYPE$3.WhiteSpace; var COMMENT$1 = TYPE$3.Comment; var IDENT = TYPE$3.Ident; var NUMBER = TYPE$3.Number; var DIMENSION = TYPE$3.Dimension; var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$1 = 0x002D; // U+002D HYPHEN-MINUS (-) var N = 0x006E; // U+006E LATIN SMALL LETTER N (n) var DISALLOW_SIGN = true; var ALLOW_SIGN = false; function isDelim(token, code) { return token !== null && token.type === DELIM && token.value.charCodeAt(0) === code; } function skipSC(token, offset, getNextToken) { while (token !== null && (token.type === WHITESPACE$1 || token.type === COMMENT$1)) { token = getNextToken(++offset); } return offset; } function checkInteger(token, valueOffset, disallowSign, offset) { if (!token) { return 0; } var code = token.value.charCodeAt(valueOffset); if (code === PLUSSIGN || code === HYPHENMINUS$1) { if (disallowSign) { // Number sign is not allowed return 0; } valueOffset++; } for (; valueOffset < token.value.length; valueOffset++) { if (!isDigit$2(token.value.charCodeAt(valueOffset))) { // Integer is expected return 0; } } return offset + 1; } // ... <signed-integer> // ... ['+' | '-'] <signless-integer> function consumeB(token, offset_, getNextToken) { var sign = false; var offset = skipSC(token, offset_, getNextToken); token = getNextToken(offset); if (token === null) { return offset_; } if (token.type !== NUMBER) { if (isDelim(token, PLUSSIGN) || isDelim(token, HYPHENMINUS$1)) { sign = true; offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); if (token === null && token.type !== NUMBER) { return 0; } } else { return offset_; } } if (!sign) { var code = token.value.charCodeAt(0); if (code !== PLUSSIGN && code !== HYPHENMINUS$1) { // Number sign is expected return 0; } } return checkInteger(token, sign ? 0 : 1, sign, offset); } // An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb var genericAnPlusB = function anPlusB(token, getNextToken) { /* eslint-disable brace-style*/ var offset = 0; if (!token) { return 0; } // <integer> if (token.type === NUMBER) { return checkInteger(token, 0, ALLOW_SIGN, offset); // b } // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> // -n- <signless-integer> // <dashndashdigit-ident> else if (token.type === IDENT && token.value.charCodeAt(0) === HYPHENMINUS$1) { // expect 1st char is N if (!cmpChar$1(token.value, 1, N)) { return 0; } switch (token.value.length) { // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> case 2: return consumeB(getNextToken(++offset), offset, getNextToken); // -n- <signless-integer> case 3: if (token.value.charCodeAt(2) !== HYPHENMINUS$1) { return 0; } offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger(token, 0, DISALLOW_SIGN, offset); // <dashndashdigit-ident> default: if (token.value.charCodeAt(2) !== HYPHENMINUS$1) { return 0; } return checkInteger(token, 3, DISALLOW_SIGN, offset); } } // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> // '+'? n- <signless-integer> // '+'? <ndashdigit-ident> else if (token.type === IDENT || (isDelim(token, PLUSSIGN) && getNextToken(offset + 1).type === IDENT)) { // just ignore a plus if (token.type !== IDENT) { token = getNextToken(++offset); } if (token === null || !cmpChar$1(token.value, 0, N)) { return 0; } switch (token.value.length) { // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> case 1: return consumeB(getNextToken(++offset), offset, getNextToken); // '+'? n- <signless-integer> case 2: if (token.value.charCodeAt(1) !== HYPHENMINUS$1) { return 0; } offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger(token, 0, DISALLOW_SIGN, offset); // '+'? <ndashdigit-ident> default: if (token.value.charCodeAt(1) !== HYPHENMINUS$1) { return 0; } return checkInteger(token, 2, DISALLOW_SIGN, offset); } } // <ndashdigit-dimension> // <ndash-dimension> <signless-integer> // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> else if (token.type === DIMENSION) { var code = token.value.charCodeAt(0); var sign = code === PLUSSIGN || code === HYPHENMINUS$1 ? 1 : 0; for (var i = sign; i < token.value.length; i++) { if (!isDigit$2(token.value.charCodeAt(i))) { break; } } if (i === sign) { // Integer is expected return 0; } if (!cmpChar$1(token.value, i, N)) { return 0; } // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> if (i + 1 === token.value.length) { return consumeB(getNextToken(++offset), offset, getNextToken); } else { if (token.value.charCodeAt(i + 1) !== HYPHENMINUS$1) { return 0; } // <ndash-dimension> <signless-integer> if (i + 2 === token.value.length) { offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger(token, 0, DISALLOW_SIGN, offset); } // <ndashdigit-dimension> else { return checkInteger(token, i + 2, DISALLOW_SIGN, offset); } } } return 0; }; var isHexDigit$2 = tokenizer.isHexDigit; var cmpChar$2 = tokenizer.cmpChar; var TYPE$4 = tokenizer.TYPE; var IDENT$1 = TYPE$4.Ident; var DELIM$1 = TYPE$4.Delim; var NUMBER$1 = TYPE$4.Number; var DIMENSION$1 = TYPE$4.Dimension; var PLUSSIGN$1 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$2 = 0x002D; // U+002D HYPHEN-MINUS (-) var QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?) var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u) function isDelim$1(token, code) { return token !== null && token.type === DELIM$1 && token.value.charCodeAt(0) === code; } function startsWith(token, code) { return token.value.charCodeAt(0) === code; } function hexSequence(token, offset, allowDash) { for (var pos = offset, hexlen = 0; pos < token.value.length; pos++) { var code = token.value.charCodeAt(pos); if (code === HYPHENMINUS$2 && allowDash && hexlen !== 0) { if (hexSequence(token, offset + hexlen + 1, false) > 0) { return 6; // dissallow following question marks } return 0; // dash at the ending of a hex sequence is not allowed } if (!isHexDigit$2(code)) { return 0; // not a hex digit } if (++hexlen > 6) { return 0; // too many hex digits } } return hexlen; } function withQuestionMarkSequence(consumed, length, getNextToken) { if (!consumed) { return 0; // nothing consumed } while (isDelim$1(getNextToken(length), QUESTIONMARK)) { if (++consumed > 6) { return 0; // too many question marks } length++; } return length; } // https://drafts.csswg.org/css-syntax/#urange // Informally, the <urange> production has three forms: // U+0001 // Defines a range consisting of a single code point, in this case the code point "1". // U+0001-00ff // Defines a range of codepoints between the first and the second value, in this case // the range between "1" and "ff" (255 in decimal) inclusive. // U+00?? // Defines a range of codepoints where the "?" characters range over all hex digits, // in this case defining the same as the value U+0000-00ff. // In each form, a maximum of 6 digits is allowed for each hexadecimal number (if you treat "?" as a hexadecimal digit). // // <urange> = // u '+' <ident-token> '?'* | // u <dimension-token> '?'* | // u <number-token> '?'* | // u <number-token> <dimension-token> | // u <number-token> <number-token> | // u '+' '?'+ var genericUrange = function urange(token, getNextToken) { var length = 0; // should start with `u` or `U` if (token === null || token.type !== IDENT$1 || !cmpChar$2(token.value, 0, U)) { return 0; } token = getNextToken(++length); if (token === null) { return 0; } // u '+' <ident-token> '?'* // u '+' '?'+ if (isDelim$1(token, PLUSSIGN$1)) { token = getNextToken(++length); if (token === null) { return 0; } if (token.type === IDENT$1) { // u '+' <ident-token> '?'* return withQuestionMarkSequence(hexSequence(token, 0, true), ++length, getNextToken); } if (isDelim$1(token, QUESTIONMARK)) { // u '+' '?'+ return withQuestionMarkSequence(1, ++length, getNextToken); } // Hex digit or question mark is expected return 0; } // u <number-token> '?'* // u <number-token> <dimension-token> // u <number-token> <number-token> if (token.type === NUMBER$1) { if (!startsWith(token, PLUSSIGN$1)) { return 0; } var consumedHexLength = hexSequence(token, 1, true); if (consumedHexLength === 0) { return 0; } token = getNextToken(++length); if (token === null) { // u <number-token> <eof> return length; } if (token.type === DIMENSION$1 || token.type === NUMBER$1) { // u <number-token> <dimension-token> // u <number-token> <number-token> if (!startsWith(token, HYPHENMINUS$2) || !hexSequence(token, 1, false)) { return 0; } return length + 1; } // u <number-token> '?'* return withQuestionMarkSequence(consumedHexLength, length, getNextToken); } // u <dimension-token> '?'* if (token.type === DIMENSION$1) { if (!startsWith(token, PLUSSIGN$1)) { return 0; } return withQuestionMarkSequence(hexSequence(token, 1, true), ++length, getNextToken); } return 0; }; var isIdentifierStart$2 = tokenizer.isIdentifierStart; var isHexDigit$3 = tokenizer.isHexDigit; var isDigit$3 = tokenizer.isDigit; var cmpStr$3 = tokenizer.cmpStr; var consumeNumber$2 = tokenizer.consumeNumber; var TYPE$5 = tokenizer.TYPE; var cssWideKeywords = ['unset', 'initial', 'inherit']; var calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc(']; // https://www.w3.org/TR/css-values-3/#lengths var LENGTH = { // absolute length units 'px': true, 'mm': true, 'cm': true, 'in': true, 'pt': true, 'pc': true, 'q': true, // relative length units 'em': true, 'ex': true, 'ch': true, 'rem': true, // viewport-percentage lengths 'vh': true, 'vw': true, 'vmin': true, 'vmax': true, 'vm': true }; var ANGLE = { 'deg': true, 'grad': true, 'rad': true, 'turn': true }; var TIME = { 's': true, 'ms': true }; var FREQUENCY = { 'hz': true, 'khz': true }; // https://www.w3.org/TR/css-values-3/#resolution (https://drafts.csswg.org/css-values/#resolution) var RESOLUTION = { 'dpi': true, 'dpcm': true, 'dppx': true, 'x': true // https://github.com/w3c/csswg-drafts/issues/461 }; // https://drafts.csswg.org/css-grid/#fr-unit var FLEX = { 'fr': true }; // https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume var DECIBEL = { 'db': true }; // https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch var SEMITONES = { 'st': true }; // safe char code getter function charCode(str, index) { return index < str.length ? str.charCodeAt(index) : 0; } function eqStr(actual, expected) { return cmpStr$3(actual, 0, actual.length, expected); } function eqStrAny(actual, expected) { for (var i = 0; i < expected.length; i++) { if (eqStr(actual, expected[i])) { return true; } } return false; } // IE postfix hack, i.e. 123\0 or 123px\9 function isPostfixIeHack(str, offset) { if (offset !== str.length - 2) { return false; } return ( str.charCodeAt(offset) === 0x005C && // U+005C REVERSE SOLIDUS (\) isDigit$3(str.charCodeAt(offset + 1)) ); } function outOfRange(opts, value, numEnd) { if (opts && opts.type === 'Range') { var num = Number( numEnd !== undefined && numEnd !== value.length ? value.substr(0, numEnd) : value ); if (isNaN(num)) { return true; } if (opts.min !== null && num < opts.min) { return true; } if (opts.max !== null && num > opts.max) { return true; } } return false; } function consumeFunction(token, getNextToken) { var startIdx = token.index; var length = 0; // balanced token consuming do { length++; if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // TODO: implement // can be used wherever <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> values are allowed // https://drafts.csswg.org/css-values/#calc-notation function calc(next) { return function(token, getNextToken, opts) { if (token === null) { return 0; } if (token.type === TYPE$5.Function && eqStrAny(token.value, calcFunctionNames)) { return consumeFunction(token, getNextToken); } return next(token, getNextToken, opts); }; } function tokenType(expectedTokenType) { return function(token) { if (token === null || token.type !== expectedTokenType) { return 0; } return 1; }; } function func(name) { name = name + '('; return function(token, getNextToken) { if (token !== null && eqStr(token.value, name)) { return consumeFunction(token, getNextToken); } return 0; }; } // ========================= // Complex types // // https://drafts.csswg.org/css-values-4/#custom-idents // 4.2. Author-defined Identifiers: the <custom-ident> type // Some properties accept arbitrary author-defined identifiers as a component value. // This generic data type is denoted by <custom-ident>, and represents any valid CSS identifier // that would not be misinterpreted as a pre-defined keyword in that property’s value definition. // // See also: https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident function customIdent(token) { if (token === null || token.type !== TYPE$5.Ident) { return 0; } var name = token.value.toLowerCase(); // The CSS-wide keywords are not valid <custom-ident>s if (eqStrAny(name, cssWideKeywords)) { return 0; } // The default keyword is reserved and is also not a valid <custom-ident> if (eqStr(name, 'default')) { return 0; } // TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident) // Specifications using <custom-ident> must specify clearly what other keywords // are excluded from <custom-ident>, if any—for example by saying that any pre-defined keywords // in that property’s value definition are excluded. Excluded keywords are excluded // in all ASCII case permutations. return 1; } // https://drafts.csswg.org/css-variables/#typedef-custom-property-name // A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo. // The <custom-property-name> production corresponds to this: it’s defined as any valid identifier // that starts with two dashes, except -- itself, which is reserved for future use by CSS. // NOTE: Current implementation treat `--` as a valid name since most (all?) major browsers treat it as valid. function customPropertyName(token) { // ... defined as any valid identifier if (token === null || token.type !== TYPE$5.Ident) { return 0; } // ... that starts with two dashes (U+002D HYPHEN-MINUS) if (charCode(token.value, 0) !== 0x002D || charCode(token.value, 1) !== 0x002D) { return 0; } return 1; } // https://drafts.csswg.org/css-color-4/#hex-notation // The syntax of a <hex-color> is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits. // In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or // letters a-f (the case of the letters doesn’t matter - #00ff00 is identical to #00FF00). function hexColor(token) { if (token === null || token.type !== TYPE$5.Hash) { return 0; } var length = token.value.length; // valid values (length): #rgb (4), #rgba (5), #rrggbb (7), #rrggbbaa (9) if (length !== 4 && length !== 5 && length !== 7 && length !== 9) { return 0; } for (var i = 1; i < length; i++) { if (!isHexDigit$3(token.value.charCodeAt(i))) { return 0; } } return 1; } function idSelector(token) { if (token === null || token.type !== TYPE$5.Hash) { return 0; } if (!isIdentifierStart$2(charCode(token.value, 1), charCode(token.value, 2), charCode(token.value, 3))) { return 0; } return 1; } // https://drafts.csswg.org/css-syntax/#any-value // It represents the entirety of what a valid declaration can have as its value. function declarationValue(token, getNextToken) { if (!token) { return 0; } var length = 0; var level = 0; var startIdx = token.index; // The <declaration-value> production matches any sequence of one or more tokens, // so long as the sequence ... scan: do { switch (token.type) { // ... does not contain <bad-string-token>, <bad-url-token>, case TYPE$5.BadString: case TYPE$5.BadUrl: break scan; // ... unmatched <)-token>, <]-token>, or <}-token>, case TYPE$5.RightCurlyBracket: case TYPE$5.RightParenthesis: case TYPE$5.RightSquareBracket: if (token.balance > token.index || token.balance < startIdx) { break scan; } level--; break; // ... or top-level <semicolon-token> tokens case TYPE$5.Semicolon: if (level === 0) { break scan; } break; // ... or <delim-token> tokens with a value of "!" case TYPE$5.Delim: if (token.value === '!' && level === 0) { break scan; } break; case TYPE$5.Function: case TYPE$5.LeftParenthesis: case TYPE$5.LeftSquareBracket: case TYPE$5.LeftCurlyBracket: level++; break; } length++; // until balance closing if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // https://drafts.csswg.org/css-syntax/#any-value // The <any-value> production is identical to <declaration-value>, but also // allows top-level <semicolon-token> tokens and <delim-token> tokens // with a value of "!". It represents the entirety of what valid CSS can be in any context. function anyValue(token, getNextToken) { if (!token) { return 0; } var startIdx = token.index; var length = 0; // The <any-value> production matches any sequence of one or more tokens, // so long as the sequence ... scan: do { switch (token.type) { // ... does not contain <bad-string-token>, <bad-url-token>, case TYPE$5.BadString: case TYPE$5.BadUrl: break scan; // ... unmatched <)-token>, <]-token>, or <}-token>, case TYPE$5.RightCurlyBracket: case TYPE$5.RightParenthesis: case TYPE$5.RightSquareBracket: if (token.balance > token.index || token.balance < startIdx) { break scan; } break; } length++; // until balance closing if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // ========================= // Dimensions // function dimension(type) { return function(token, getNextToken, opts) { if (token === null || token.type !== TYPE$5.Dimension) { return 0; } var numberEnd = consumeNumber$2(token.value, 0); // check unit if (type !== null) { // check for IE postfix hack, i.e. 123px\0 or 123px\9 var reverseSolidusOffset = token.value.indexOf('\\', numberEnd); var unit = reverseSolidusOffset === -1 || !isPostfixIeHack(token.value, reverseSolidusOffset) ? token.value.substr(numberEnd) : token.value.substring(numberEnd, reverseSolidusOffset); if (type.hasOwnProperty(unit.toLowerCase()) === false) { return 0; } } // check range if specified if (outOfRange(opts, token.value, numberEnd)) { return 0; } return 1; }; } // ========================= // Percentage // // §5.5. Percentages: the <percentage> type // https://drafts.csswg.org/css-values-4/#percentages function percentage(token, getNextToken, opts) { // ... corresponds to the <percentage-token> production if (token === null || token.type !== TYPE$5.Percentage) { return 0; } // check range if specified if (outOfRange(opts, token.value, token.value.length - 1)) { return 0; } return 1; } // ========================= // Numeric // // https://drafts.csswg.org/css-values-4/#numbers // The value <zero> represents a literal number with the value 0. Expressions that merely // evaluate to a <number> with the value 0 (for example, calc(0)) do not match <zero>; // only literal <number-token>s do. function zero(next) { if (typeof next !== 'function') { next = function() { return 0; }; } return function(token, getNextToken, opts) { if (token !== null && token.type === TYPE$5.Number) { if (Number(token.value) === 0) { return 1; } } return next(token, getNextToken, opts); }; } // § 5.3. Real Numbers: the <number> type // https://drafts.csswg.org/css-values-4/#numbers // Number values are denoted by <number>, and represent real numbers, possibly with a fractional component. // ... It corresponds to the <number-token> production function number(token, getNextToken, opts) { if (token === null) { return 0; } var numberEnd = consumeNumber$2(token.value, 0); var isNumber = numberEnd === token.value.length; if (!isNumber && !isPostfixIeHack(token.value, numberEnd)) { return 0; } // check range if specified if (outOfRange(opts, token.value, numberEnd)) { return 0; } return 1; } // §5.2. Integers: the <integer> type // https://drafts.csswg.org/css-values-4/#integers function integer(token, getNextToken, opts) { // ... corresponds to a subset of the <number-token> production if (token === null || token.type !== TYPE$5.Number) { return 0; } // The first digit of an integer may be immediately preceded by `-` or `+` to indicate the integer’s sign. var i = token.value.charCodeAt(0) === 0x002B || // U+002B PLUS SIGN (+) token.value.charCodeAt(0) === 0x002D ? 1 : 0; // U+002D HYPHEN-MINUS (-) // When written literally, an integer is one or more decimal digits 0 through 9 ... for (; i < token.value.length; i++) { if (!isDigit$3(token.value.charCodeAt(i))) { return 0; } } // check range if specified if (outOfRange(opts, token.value, i)) { return 0; } return 1; } var generic = { // token types 'ident-token': tokenType(TYPE$5.Ident), 'function-token': tokenType(TYPE$5.Function), 'at-keyword-token': tokenType(TYPE$5.AtKeyword), 'hash-token': tokenType(TYPE$5.Hash), 'string-token': tokenType(TYPE$5.String), 'bad-string-token': tokenType(TYPE$5.BadString), 'url-token': tokenType(TYPE$5.Url), 'bad-url-token': tokenType(TYPE$5.BadUrl), 'delim-token': tokenType(TYPE$5.Delim), 'number-token': tokenType(TYPE$5.Number), 'percentage-token': tokenType(TYPE$5.Percentage), 'dimension-token': tokenType(TYPE$5.Dimension), 'whitespace-token': tokenType(TYPE$5.WhiteSpace), 'CDO-token': tokenType(TYPE$5.CDO), 'CDC-token': tokenType(TYPE$5.CDC), 'colon-token': tokenType(TYPE$5.Colon), 'semicolon-token': tokenType(TYPE$5.Semicolon), 'comma-token': tokenType(TYPE$5.Comma), '[-token': tokenType(TYPE$5.LeftSquareBracket), ']-token': tokenType(TYPE$5.RightSquareBracket), '(-token': tokenType(TYPE$5.LeftParenthesis), ')-token': tokenType(TYPE$5.RightParenthesis), '{-token': tokenType(TYPE$5.LeftCurlyBracket), '}-token': tokenType(TYPE$5.RightCurlyBracket), // token type aliases 'string': tokenType(TYPE$5.String), 'ident': tokenType(TYPE$5.Ident), // complex types 'custom-ident': customIdent, 'custom-property-name': customPropertyName, 'hex-color': hexColor, 'id-selector': idSelector, // element( <id-selector> ) 'an-plus-b': genericAnPlusB, 'urange': genericUrange, 'declaration-value': declarationValue, 'any-value': anyValue, // dimensions 'dimension': calc(dimension(null)), 'angle': calc(dimension(ANGLE)), 'decibel': calc(dimension(DECIBEL)), 'frequency': calc(dimension(FREQUENCY)), 'flex': calc(dimension(FLEX)), 'length': calc(zero(dimension(LENGTH))), 'resolution': calc(dimension(RESOLUTION)), 'semitones': calc(dimension(SEMITONES)), 'time': calc(dimension(TIME)), // percentage 'percentage': calc(percentage), // numeric 'zero': zero(), 'number': calc(number), 'integer': calc(integer), // old IE stuff '-ms-legacy-expression': func('expression') }; var _SyntaxError$1 = function SyntaxError(message, input, offset) { var error = createCustomError('SyntaxError', message); error.input = input; error.offset = offset; error.rawMessage = message; error.message = error.rawMessage + '\n' + ' ' + error.input + '\n' + '--' + new Array((error.offset || error.input.length) + 1).join('-') + '^'; return error; }; var TAB = 9; var N$1 = 10; var F = 12; var R = 13; var SPACE = 32; var Tokenizer = function(str) { this.str = str; this.pos = 0; }; Tokenizer.prototype = { charCodeAt: function(pos) { return pos < this.str.length ? this.str.charCodeAt(pos) : 0; }, charCode: function() { return this.charCodeAt(this.pos); }, nextCharCode: function() { return this.charCodeAt(this.pos + 1); }, nextNonWsCode: function(pos) { return this.charCodeAt(this.findWsEnd(pos)); }, findWsEnd: function(pos) { for (; pos < this.str.length; pos++) { var code = this.str.charCodeAt(pos); if (code !== R && code !== N$1 && code !== F && code !== SPACE && code !== TAB) { break; } } return pos; }, substringToPos: function(end) { return this.str.substring(this.pos, this.pos = end); }, eat: function(code) { if (this.charCode() !== code) { this.error('Expect `' + String.fromCharCode(code) + '`'); } this.pos++; }, peek: function() { return this.pos < this.str.length ? this.str.charAt(this.pos++) : ''; }, error: function(message) { throw new _SyntaxError$1(message, this.str, this.pos); } }; var tokenizer$1 = Tokenizer; var TAB$1 = 9; var N$2 = 10; var F$1 = 12; var R$1 = 13; var SPACE$1 = 32; var EXCLAMATIONMARK = 33; // ! var NUMBERSIGN = 35; // # var AMPERSAND = 38; // & var APOSTROPHE = 39; // ' var LEFTPARENTHESIS = 40; // ( var RIGHTPARENTHESIS = 41; // ) var ASTERISK = 42; // * var PLUSSIGN$2 = 43; // + var COMMA = 44; // , var HYPERMINUS = 45; // - var LESSTHANSIGN = 60; // < var GREATERTHANSIGN = 62; // > var QUESTIONMARK$1 = 63; // ? var COMMERCIALAT = 64; // @ var LEFTSQUAREBRACKET = 91; // [ var RIGHTSQUAREBRACKET = 93; // ] var LEFTCURLYBRACKET = 123; // { var VERTICALLINE = 124; // | var RIGHTCURLYBRACKET = 125; // } var INFINITY = 8734; // ∞ var NAME_CHAR = createCharMap(function(ch) { return /[a-zA-Z0-9\-]/.test(ch); }); var COMBINATOR_PRECEDENCE = { ' ': 1, '&&': 2, '||': 3, '|': 4 }; function createCharMap(fn) { var array = typeof Uint32Array === 'function' ? new Uint32Array(128) : new Array(128); for (var i = 0; i < 128; i++) { array[i] = fn(String.fromCharCode(i)) ? 1 : 0; } return array; } function scanSpaces(tokenizer) { return tokenizer.substringToPos( tokenizer.findWsEnd(tokenizer.pos) ); } function scanWord(tokenizer) { var end = tokenizer.pos; for (; end < tokenizer.str.length; end++) { var code = tokenizer.str.charCodeAt(end); if (code >= 128 || NAME_CHAR[code] === 0) { break; } } if (tokenizer.pos === end) { tokenizer.error('Expect a keyword'); } return tokenizer.substringToPos(end); } function scanNumber(tokenizer) { var end = tokenizer.pos; for (; end < tokenizer.str.length; end++) { var code = tokenizer.str.charCodeAt(end); if (code < 48 || code > 57) { break; } } if (tokenizer.pos === end) { tokenizer.error('Expect a number'); } return tokenizer.substringToPos(end); } function scanString(tokenizer) { var end = tokenizer.str.indexOf('\'', tokenizer.pos + 1); if (end === -1) { tokenizer.pos = tokenizer.str.length; tokenizer.error('Expect an apostrophe'); } return tokenizer.substringToPos(end + 1); } function readMultiplierRange(tokenizer) { var min = null; var max = null; tokenizer.eat(LEFTCURLYBRACKET); min = scanNumber(tokenizer); if (tokenizer.charCode() === COMMA) { tokenizer.pos++; if (tokenizer.charCode() !== RIGHTCURLYBRACKET) { max = scanNumber(tokenizer); } } else { max = min; } tokenizer.eat(RIGHTCURLYBRACKET); return { min: Number(min), max: max ? Number(max) : 0 }; } function readMultiplier(tokenizer) { var range = null; var comma = false; switch (tokenizer.charCode()) { case ASTERISK: tokenizer.pos++; range = { min: 0, max: 0 }; break; case PLUSSIGN$2: tokenizer.pos++; range = { min: 1, max: 0 }; break; case QUESTIONMARK$1: tokenizer.pos++; range = { min: 0, max: 1 }; break; case NUMBERSIGN: tokenizer.pos++; comma = true; if (tokenizer.charCode() === LEFTCURLYBRACKET) { range = readMultiplierRange(tokenizer); } else { range = { min: 1, max: 0 }; } break; case LEFTCURLYBRACKET: range = readMultiplierRange(tokenizer); break; default: return null; } return { type: 'Multiplier', comma: comma, min: range.min, max: range.max, term: null }; } function maybeMultiplied(tokenizer, node) { var multiplier = readMultiplier(tokenizer); if (multiplier !== null) { multiplier.term = node; return multiplier; } return node; } function maybeToken(tokenizer) { var ch = tokenizer.peek(); if (ch === '') { return null; } return { type: 'Token', value: ch }; } function readProperty(tokenizer) { var name; tokenizer.eat(LESSTHANSIGN); tokenizer.eat(APOSTROPHE); name = scanWord(tokenizer); tokenizer.eat(APOSTROPHE); tokenizer.eat(GREATERTHANSIGN); return maybeMultiplied(tokenizer, { type: 'Property', name: name }); } // https://drafts.csswg.org/css-values-3/#numeric-ranges // 4.1. Range Restrictions and Range Definition Notation // // Range restrictions can be annotated in the numeric type notation using CSS bracketed // range notation—[min,max]—within the angle brackets, after the identifying keyword, // indicating a closed range between (and including) min and max. // For example, <integer [0, 10]> indicates an integer between 0 and 10, inclusive. function readTypeRange(tokenizer) { // use null for Infinity to make AST format JSON serializable/deserializable var min = null; // -Infinity var max = null; // Infinity var sign = 1; tokenizer.eat(LEFTSQUAREBRACKET); if (tokenizer.charCode() === HYPERMINUS) { tokenizer.peek(); sign = -1; } if (sign == -1 && tokenizer.charCode() === INFINITY) { tokenizer.peek(); } else { min = sign * Number(scanNumber(tokenizer)); } scanSpaces(tokenizer); tokenizer.eat(COMMA); scanSpaces(tokenizer); if (tokenizer.charCode() === INFINITY) { tokenizer.peek(); } else { sign = 1; if (tokenizer.charCode() === HYPERMINUS) { tokenizer.peek(); sign = -1; } max = sign * Number(scanNumber(tokenizer)); } tokenizer.eat(RIGHTSQUAREBRACKET); // If no range is indicated, either by using the bracketed range notation // or in the property description, then [−∞,∞] is assumed. if (min === null && max === null) { return null; } return { type: 'Range', min: min, max: max }; } function readType(tokenizer) { var name; var opts = null; tokenizer.eat(LESSTHANSIGN); name = scanWord(tokenizer); if (tokenizer.charCode() === LEFTPARENTHESIS && tokenizer.nextCharCode() === RIGHTPARENTHESIS) { tokenizer.pos += 2; name += '()'; } if (tokenizer.charCodeAt(tokenizer.findWsEnd(tokenizer.pos)) === LEFTSQUAREBRACKET) { scanSpaces(tokenizer); opts = readTypeRange(tokenizer); } tokenizer.eat(GREATERTHANSIGN); return maybeMultiplied(tokenizer, { type: 'Type', name: name, opts: opts }); } function readKeywordOrFunction(tokenizer) { var name; name = scanWord(tokenizer); if (tokenizer.charCode() === LEFTPARENTHESIS) { tokenizer.pos++; return { type: 'Function', name: name }; } return maybeMultiplied(tokenizer, { type: 'Keyword', name: name }); } function regroupTerms(terms, combinators) { function createGroup(terms, combinator) { return { type: 'Group', terms: terms, combinator: combinator, disallowEmpty: false, explicit: false }; } combinators = Object.keys(combinators).sort(function(a, b) { return COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b]; }); while (combinators.length > 0) { var combinator = combinators.shift(); for (var i = 0, subgroupStart = 0; i < terms.length; i++) { var term = terms[i]; if (term.type === 'Combinator') { if (term.value === combinator) { if (subgroupStart === -1) { subgroupStart = i - 1; } terms.splice(i, 1); i--; } else { if (subgroupStart !== -1 && i - subgroupStart > 1) { terms.splice( subgroupStart, i - subgroupStart, createGroup(terms.slice(subgroupStart, i), combinator) ); i = subgroupStart + 1; } subgroupStart = -1; } } } if (subgroupStart !== -1 && combinators.length) { terms.splice( subgroupStart, i - subgroupStart, createGroup(terms.slice(subgroupStart, i), combinator) ); } } return combinator; } function readImplicitGroup(tokenizer) { var terms = []; var combinators = {}; var token; var prevToken = null; var prevTokenPos = tokenizer.pos; while (token = peek(tokenizer)) { if (token.type !== 'Spaces') { if (token.type === 'Combinator') { // check for combinator in group beginning and double combinator sequence if (prevToken === null || prevToken.type === 'Combinator') { tokenizer.pos = prevTokenPos; tokenizer.error('Unexpected combinator'); } combinators[token.value] = true; } else if (prevToken !== null && prevToken.type !== 'Combinator') { combinators[' '] = true; // a b terms.push({ type: 'Combinator', value: ' ' }); } terms.push(token); prevToken = token; prevTokenPos = tokenizer.pos; } } // check for combinator in group ending if (prevToken !== null && prevToken.type === 'Combinator') { tokenizer.pos -= prevTokenPos; tokenizer.error('Unexpected combinator'); } return { type: 'Group', terms: terms, combinator: regroupTerms(terms, combinators) || ' ', disallowEmpty: false, explicit: false }; } function readGroup(tokenizer) { var result; tokenizer.eat(LEFTSQUAREBRACKET); result = readImplicitGroup(tokenizer); tokenizer.eat(RIGHTSQUAREBRACKET); result.explicit = true; if (tokenizer.charCode() === EXCLAMATIONMARK) { tokenizer.pos++; result.disallowEmpty = true; } return result; } function peek(tokenizer) { var code = tokenizer.charCode(); if (code < 128 && NAME_CHAR[code] === 1) { return readKeywordOrFunction(tokenizer); } switch (code) { case RIGHTSQUAREBRACKET: // don't eat, stop scan a group break; case LEFTSQUAREBRACKET: return maybeMultiplied(tokenizer, readGroup(tokenizer)); case LESSTHANSIGN: return tokenizer.nextCharCode() === APOSTROPHE ? readProperty(tokenizer) : readType(tokenizer); case VERTICALLINE: return { type: 'Combinator', value: tokenizer.substringToPos( tokenizer.nextCharCode() === VERTICALLINE ? tokenizer.pos + 2 : tokenizer.pos + 1 ) }; case AMPERSAND: tokenizer.pos++; tokenizer.eat(AMPERSAND); return { type: 'Combinator', value: '&&' }; case COMMA: tokenizer.pos++; return { type: 'Comma' }; case APOSTROPHE: return maybeMultiplied(tokenizer, { type: 'String', value: scanString(tokenizer) }); case SPACE$1: case TAB$1: case N$2: case R$1: case F$1: return { type: 'Spaces', value: scanSpaces(tokenizer) }; case COMMERCIALAT: code = tokenizer.nextCharCode(); if (code < 128 && NAME_CHAR[code] === 1) { tokenizer.pos++; return { type: 'AtKeyword', name: scanWord(tokenizer) }; } return maybeToken(tokenizer); case ASTERISK: case PLUSSIGN$2: case QUESTIONMARK$1: case NUMBERSIGN: case EXCLAMATIONMARK: // prohibited tokens (used as a multiplier start) break; case LEFTCURLYBRACKET: // LEFTCURLYBRACKET is allowed since mdn/data uses it w/o quoting // check next char isn't a number, because it's likely a disjoined multiplier code = tokenizer.nextCharCode(); if (code < 48 || code > 57) { return maybeToken(tokenizer); } break; default: return maybeToken(tokenizer); } } function parse(source) { var tokenizer = new tokenizer$1(source); var result = readImplicitGroup(tokenizer); if (tokenizer.pos !== source.length) { tokenizer.error('Unexpected input'); } // reduce redundant groups with single group term if (result.terms.length === 1 && result.terms[0].type === 'Group') { result = result.terms[0]; } return result; } // warm up parse to elimitate code branches that never execute // fix soft deoptimizations (insufficient type feedback) parse('[a&&<b>#|<\'c\'>*||e() f{2} /,(% g#{1,2} h{2,})]!'); var parse_1 = parse; var noop$2 = function() {}; function ensureFunction(value) { return typeof value === 'function' ? value : noop$2; } var walk$1 = function(node, options, context) { function walk(node) { enter.call(context, node); switch (node.type) { case 'Group': node.terms.forEach(walk); break; case 'Multiplier': walk(node.term); break; case 'Type': case 'Property': case 'Keyword': case 'AtKeyword': case 'Function': case 'String': case 'Token': case 'Comma': break; default: throw new Error('Unknown type: ' + node.type); } leave.call(context, node); } var enter = noop$2; var leave = noop$2; if (typeof options === 'function') { enter = options; } else if (options) { enter = ensureFunction(options.enter); leave = ensureFunction(options.leave); } if (enter === noop$2 && leave === noop$2) { throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function'); } walk(node); }; var tokenStream = new TokenStream_1(); var astToTokens = { decorator: function(handlers) { var curNode = null; var prev = { len: 0, node: null }; var nodes = [prev]; var buffer = ''; return { children: handlers.children, node: function(node) { var tmp = curNode; curNode = node; handlers.node.call(this, node); curNode = tmp; }, chunk: function(chunk) { buffer += chunk; if (prev.node !== curNode) { nodes.push({ len: chunk.length, node: curNode }); } else { prev.len += chunk.length; } }, result: function() { return prepareTokens(buffer, nodes); } }; } }; function prepareTokens(str, nodes) { var tokens = []; var nodesOffset = 0; var nodesIndex = 0; var currentNode = nodes ? nodes[nodesIndex].node : null; tokenizer(str, tokenStream); while (!tokenStream.eof) { if (nodes) { while (nodesIndex < nodes.length && nodesOffset + nodes[nodesIndex].len <= tokenStream.tokenStart) { nodesOffset += nodes[nodesIndex++].len; currentNode = nodes[nodesIndex].node; } } tokens.push({ type: tokenStream.tokenType, value: tokenStream.getTokenValue(), index: tokenStream.tokenIndex, // TODO: remove it, temporary solution balance: tokenStream.balance[tokenStream.tokenIndex], // TODO: remove it, temporary solution node: currentNode }); tokenStream.next(); // console.log({ ...tokens[tokens.length - 1], node: undefined }); } return tokens; } var prepareTokens_1 = function(value, syntax) { if (typeof value === 'string') { return prepareTokens(value, null); } return syntax.generate(value, astToTokens); }; var MATCH = { type: 'Match' }; var MISMATCH = { type: 'Mismatch' }; var DISALLOW_EMPTY = { type: 'DisallowEmpty' }; var LEFTPARENTHESIS$1 = 40; // ( var RIGHTPARENTHESIS$1 = 41; // ) function createCondition(match, thenBranch, elseBranch) { // reduce node count if (thenBranch === MATCH && elseBranch === MISMATCH) { return match; } if (match === MATCH && thenBranch === MATCH && elseBranch === MATCH) { return match; } if (match.type === 'If' && match.else === MISMATCH && thenBranch === MATCH) { thenBranch = match.then; match = match.match; } return { type: 'If', match: match, then: thenBranch, else: elseBranch }; } function isFunctionType(name) { return ( name.length > 2 && name.charCodeAt(name.length - 2) === LEFTPARENTHESIS$1 && name.charCodeAt(name.length - 1) === RIGHTPARENTHESIS$1 ); } function isEnumCapatible(term) { return ( term.type === 'Keyword' || term.type === 'AtKeyword' || term.type === 'Function' || term.type === 'Type' && isFunctionType(term.name) ); } function buildGroupMatchGraph(combinator, terms, atLeastOneTermMatched) { switch (combinator) { case ' ': // Juxtaposing components means that all of them must occur, in the given order. // // a b c // = // match a // then match b // then match c // then MATCH // else MISMATCH // else MISMATCH // else MISMATCH var result = MATCH; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; result = createCondition( term, result, MISMATCH ); } return result; case '|': // A bar (|) separates two or more alternatives: exactly one of them must occur. // // a | b | c // = // match a // then MATCH // else match b // then MATCH // else match c // then MATCH // else MISMATCH var result = MISMATCH; var map = null; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; // reduce sequence of keywords into a Enum if (isEnumCapatible(term)) { if (map === null && i > 0 && isEnumCapatible(terms[i - 1])) { map = Object.create(null); result = createCondition( { type: 'Enum', map: map }, MATCH, result ); } if (map !== null) { var key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase(); if (key in map === false) { map[key] = term; continue; } } } map = null; // create a new conditonal node result = createCondition( term, MATCH, result ); } return result; case '&&': // A double ampersand (&&) separates two or more components, // all of which must occur, in any order. // Use MatchOnce for groups with a large number of terms, // since &&-groups produces at least N!-node trees if (terms.length > 5) { return { type: 'MatchOnce', terms: terms, all: true }; } // Use a combination tree for groups with small number of terms // // a && b && c // = // match a // then [b && c] // else match b // then [a && c] // else match c // then [a && b] // else MISMATCH // // a && b // = // match a // then match b // then MATCH // else MISMATCH // else match b // then match a // then MATCH // else MISMATCH // else MISMATCH var result = MISMATCH; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; var thenClause; if (terms.length > 1) { thenClause = buildGroupMatchGraph( combinator, terms.filter(function(newGroupTerm) { return newGroupTerm !== term; }), false ); } else { thenClause = MATCH; } result = createCondition( term, thenClause, result ); } return result; case '||': // A double bar (||) separates two or more options: // one or more of them must occur, in any order. // Use MatchOnce for groups with a large number of terms, // since ||-groups produces at least N!-node trees if (terms.length > 5) { return { type: 'MatchOnce', terms: terms, all: false }; } // Use a combination tree for groups with small number of terms // // a || b || c // = // match a // then [b || c] // else match b // then [a || c] // else match c // then [a || b] // else MISMATCH // // a || b // = // match a // then match b // then MATCH // else MATCH // else match b // then match a // then MATCH // else MATCH // else MISMATCH var result = atLeastOneTermMatched ? MATCH : MISMATCH; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; var thenClause; if (terms.length > 1) { thenClause = buildGroupMatchGraph( combinator, terms.filter(function(newGroupTerm) { return newGroupTerm !== term; }), true ); } else { thenClause = MATCH; } result = createCondition( term, thenClause, result ); } return result; } } function buildMultiplierMatchGraph(node) { var result = MATCH; var matchTerm = buildMatchGraph(node.term); if (node.max === 0) { // disable repeating of empty match to prevent infinite loop matchTerm = createCondition( matchTerm, DISALLOW_EMPTY, MISMATCH ); // an occurrence count is not limited, make a cycle; // to collect more terms on each following matching mismatch result = createCondition( matchTerm, null, // will be a loop MISMATCH ); result.then = createCondition( MATCH, MATCH, result // make a loop ); if (node.comma) { result.then.else = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH ); } } else { // create a match node chain for [min .. max] interval with optional matches for (var i = node.min || 1; i <= node.max; i++) { if (node.comma && result !== MATCH) { result = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH ); } result = createCondition( matchTerm, createCondition( MATCH, MATCH, result ), MISMATCH ); } } if (node.min === 0) { // allow zero match result = createCondition( MATCH, MATCH, result ); } else { // create a match node chain to collect [0 ... min - 1] required matches for (var i = 0; i < node.min - 1; i++) { if (node.comma && result !== MATCH) { result = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH ); } result = createCondition( matchTerm, result, MISMATCH ); } } return result; } function buildMatchGraph(node) { if (typeof node === 'function') { return { type: 'Generic', fn: node }; } switch (node.type) { case 'Group': var result = buildGroupMatchGraph( node.combinator, node.terms.map(buildMatchGraph), false ); if (node.disallowEmpty) { result = createCondition( result, DISALLOW_EMPTY, MISMATCH ); } return result; case 'Multiplier': return buildMultiplierMatchGraph(node); case 'Type': case 'Property': return { type: node.type, name: node.name, syntax: node }; case 'Keyword': return { type: node.type, name: node.name.toLowerCase(), syntax: node }; case 'AtKeyword': return { type: node.type, name: '@' + node.name.toLowerCase(), syntax: node }; case 'Function': return { type: node.type, name: node.name.toLowerCase() + '(', syntax: node }; case 'String': // convert a one char length String to a Token if (node.value.length === 3) { return { type: 'Token', value: node.value.charAt(1), syntax: node }; } // otherwise use it as is return { type: node.type, value: node.value.substr(1, node.value.length - 2).replace(/\\'/g, '\''), syntax: node }; case 'Token': return { type: node.type, value: node.value, syntax: node }; case 'Comma': return { type: node.type, syntax: node }; default: throw new Error('Unknown node type:', node.type); } } var matchGraph = { MATCH: MATCH, MISMATCH: MISMATCH, DISALLOW_EMPTY: DISALLOW_EMPTY, buildMatchGraph: function(syntaxTree, ref) { if (typeof syntaxTree === 'string') { syntaxTree = parse_1(syntaxTree); } return { type: 'MatchGraph', match: buildMatchGraph(syntaxTree), syntax: ref || null, source: syntaxTree }; } }; var hasOwnProperty$1 = Object.prototype.hasOwnProperty; var MATCH$1 = matchGraph.MATCH; var MISMATCH$1 = matchGraph.MISMATCH; var DISALLOW_EMPTY$1 = matchGraph.DISALLOW_EMPTY; var TYPE$6 = _const.TYPE; var STUB = 0; var TOKEN = 1; var OPEN_SYNTAX = 2; var CLOSE_SYNTAX = 3; var EXIT_REASON_MATCH = 'Match'; var EXIT_REASON_MISMATCH = 'Mismatch'; var EXIT_REASON_ITERATION_LIMIT = 'Maximum iteration number exceeded (please fill an issue on https://github.com/csstree/csstree/issues)'; var ITERATION_LIMIT = 15000; var totalIterationCount = 0; function reverseList(list) { var prev = null; var next = null; var item = list; while (item !== null) { next = item.prev; item.prev = prev; prev = item; item = next; } return prev; } function areStringsEqualCaseInsensitive(testStr, referenceStr) { if (testStr.length !== referenceStr.length) { return false; } for (var i = 0; i < testStr.length; i++) { var testCode = testStr.charCodeAt(i); var referenceCode = referenceStr.charCodeAt(i); // testCode.toLowerCase() for U+0041 LATIN CAPITAL LETTER A (A) .. U+005A LATIN CAPITAL LETTER Z (Z). if (testCode >= 0x0041 && testCode <= 0x005A) { testCode = testCode | 32; } if (testCode !== referenceCode) { return false; } } return true; } function isCommaContextStart(token) { if (token === null) { return true; } return ( token.type === TYPE$6.Comma || token.type === TYPE$6.Function || token.type === TYPE$6.LeftParenthesis || token.type === TYPE$6.LeftSquareBracket || token.type === TYPE$6.LeftCurlyBracket || token.type === TYPE$6.Delim ); } function isCommaContextEnd(token) { if (token === null) { return true; } return ( token.type === TYPE$6.RightParenthesis || token.type === TYPE$6.RightSquareBracket || token.type === TYPE$6.RightCurlyBracket || token.type === TYPE$6.Delim ); } function internalMatch(tokens, state, syntaxes) { function moveToNextToken() { do { tokenIndex++; token = tokenIndex < tokens.length ? tokens[tokenIndex] : null; } while (token !== null && (token.type === TYPE$6.WhiteSpace || token.type === TYPE$6.Comment)); } function getNextToken(offset) { var nextIndex = tokenIndex + offset; return nextIndex < tokens.length ? tokens[nextIndex] : null; } function stateSnapshotFromSyntax(nextState, prev) { return { nextState: nextState, matchStack: matchStack, syntaxStack: syntaxStack, thenStack: thenStack, tokenIndex: tokenIndex, prev: prev }; } function pushThenStack(nextState) { thenStack = { nextState: nextState, matchStack: matchStack, syntaxStack: syntaxStack, prev: thenStack }; } function pushElseStack(nextState) { elseStack = stateSnapshotFromSyntax(nextState, elseStack); } function addTokenToMatch() { matchStack = { type: TOKEN, syntax: state.syntax, token: token, prev: matchStack }; moveToNextToken(); syntaxStash = null; if (tokenIndex > longestMatch) { longestMatch = tokenIndex; } } function openSyntax() { syntaxStack = { syntax: state.syntax, opts: state.syntax.opts || (syntaxStack !== null && syntaxStack.opts) || null, prev: syntaxStack }; matchStack = { type: OPEN_SYNTAX, syntax: state.syntax, token: matchStack.token, prev: matchStack }; } function closeSyntax() { if (matchStack.type === OPEN_SYNTAX) { matchStack = matchStack.prev; } else { matchStack = { type: CLOSE_SYNTAX, syntax: syntaxStack.syntax, token: matchStack.token, prev: matchStack }; } syntaxStack = syntaxStack.prev; } var syntaxStack = null; var thenStack = null; var elseStack = null; // null – stashing allowed, nothing stashed // false – stashing disabled, nothing stashed // anithing else – fail stashable syntaxes, some syntax stashed var syntaxStash = null; var iterationCount = 0; // count iterations and prevent infinite loop var exitReason = null; var token = null; var tokenIndex = -1; var longestMatch = 0; var matchStack = { type: STUB, syntax: null, token: null, prev: null }; moveToNextToken(); while (exitReason === null && ++iterationCount < ITERATION_LIMIT) { // function mapList(list, fn) { // var result = []; // while (list) { // result.unshift(fn(list)); // list = list.prev; // } // return result; // } // console.log('--\n', // '#' + iterationCount, // require('util').inspect({ // match: mapList(matchStack, x => x.type === TOKEN ? x.token && x.token.value : x.syntax ? ({ [OPEN_SYNTAX]: '<', [CLOSE_SYNTAX]: '</' }[x.type] || x.type) + '!' + x.syntax.name : null), // token: token && token.value, // tokenIndex, // syntax: syntax.type + (syntax.id ? ' #' + syntax.id : '') // }, { depth: null }) // ); switch (state.type) { case 'Match': if (thenStack === null) { // turn to MISMATCH when some tokens left unmatched if (token !== null) { // doesn't mismatch if just one token left and it's an IE hack if (tokenIndex !== tokens.length - 1 || (token.value !== '\\0' && token.value !== '\\9')) { state = MISMATCH$1; break; } } // break the main loop, return a result - MATCH exitReason = EXIT_REASON_MATCH; break; } // go to next syntax (`then` branch) state = thenStack.nextState; // check match is not empty if (state === DISALLOW_EMPTY$1) { if (thenStack.matchStack === matchStack) { state = MISMATCH$1; break; } else { state = MATCH$1; } } // close syntax if needed while (thenStack.syntaxStack !== syntaxStack) { closeSyntax(); } // pop stack thenStack = thenStack.prev; break; case 'Mismatch': // when some syntax is stashed if (syntaxStash !== null && syntaxStash !== false) { // there is no else branches or a branch reduce match stack if (elseStack === null || tokenIndex > elseStack.tokenIndex) { // restore state from the stash elseStack = syntaxStash; syntaxStash = false; // disable stashing } } else if (elseStack === null) { // no else branches -> break the main loop // return a result - MISMATCH exitReason = EXIT_REASON_MISMATCH; break; } // go to next syntax (`else` branch) state = elseStack.nextState; // restore all the rest stack states thenStack = elseStack.thenStack; syntaxStack = elseStack.syntaxStack; matchStack = elseStack.matchStack; tokenIndex = elseStack.tokenIndex; token = tokenIndex < tokens.length ? tokens[tokenIndex] : null; // pop stack elseStack = elseStack.prev; break; case 'MatchGraph': state = state.match; break; case 'If': // IMPORTANT: else stack push must go first, // since it stores the state of thenStack before changes if (state.else !== MISMATCH$1) { pushElseStack(state.else); } if (state.then !== MATCH$1) { pushThenStack(state.then); } state = state.match; break; case 'MatchOnce': state = { type: 'MatchOnceBuffer', syntax: state, index: 0, mask: 0 }; break; case 'MatchOnceBuffer': var terms = state.syntax.terms; if (state.index === terms.length) { // no matches at all or it's required all terms to be matched if (state.mask === 0 || state.syntax.all) { state = MISMATCH$1; break; } // a partial match is ok state = MATCH$1; break; } // all terms are matched if (state.mask === (1 << terms.length) - 1) { state = MATCH$1; break; } for (; state.index < terms.length; state.index++) { var matchFlag = 1 << state.index; if ((state.mask & matchFlag) === 0) { // IMPORTANT: else stack push must go first, // since it stores the state of thenStack before changes pushElseStack(state); pushThenStack({ type: 'AddMatchOnce', syntax: state.syntax, mask: state.mask | matchFlag }); // match state = terms[state.index++]; break; } } break; case 'AddMatchOnce': state = { type: 'MatchOnceBuffer', syntax: state.syntax, index: 0, mask: state.mask }; break; case 'Enum': if (token !== null) { var name = token.value.toLowerCase(); // drop \0 and \9 hack from keyword name if (name.indexOf('\\') !== -1) { name = name.replace(/\\[09].*$/, ''); } if (hasOwnProperty$1.call(state.map, name)) { state = state.map[name]; break; } } state = MISMATCH$1; break; case 'Generic': var opts = syntaxStack !== null ? syntaxStack.opts : null; var lastTokenIndex = tokenIndex + Math.floor(state.fn(token, getNextToken, opts)); if (!isNaN(lastTokenIndex) && lastTokenIndex > tokenIndex) { while (tokenIndex < lastTokenIndex) { addTokenToMatch(); } state = MATCH$1; } else { state = MISMATCH$1; } break; case 'Type': case 'Property': var syntaxDict = state.type === 'Type' ? 'types' : 'properties'; var dictSyntax = hasOwnProperty$1.call(syntaxes, syntaxDict) ? syntaxes[syntaxDict][state.name] : null; if (!dictSyntax || !dictSyntax.match) { throw new Error( 'Bad syntax reference: ' + (state.type === 'Type' ? '<' + state.name + '>' : '<\'' + state.name + '\'>') ); } // stash a syntax for types with low priority if (syntaxStash !== false && token !== null && state.type === 'Type') { var lowPriorityMatching = // https://drafts.csswg.org/css-values-4/#custom-idents // When parsing positionally-ambiguous keywords in a property value, a <custom-ident> production // can only claim the keyword if no other unfulfilled production can claim it. (state.name === 'custom-ident' && token.type === TYPE$6.Ident) || // https://drafts.csswg.org/css-values-4/#lengths // ... if a `0` could be parsed as either a <number> or a <length> in a property (such as line-height), // it must parse as a <number> (state.name === 'length' && token.value === '0'); if (lowPriorityMatching) { if (syntaxStash === null) { syntaxStash = stateSnapshotFromSyntax(state, elseStack); } state = MISMATCH$1; break; } } openSyntax(); state = dictSyntax.match; break; case 'Keyword': var name = state.name; if (token !== null) { var keywordName = token.value; // drop \0 and \9 hack from keyword name if (keywordName.indexOf('\\') !== -1) { keywordName = keywordName.replace(/\\[09].*$/, ''); } if (areStringsEqualCaseInsensitive(keywordName, name)) { addTokenToMatch(); state = MATCH$1; break; } } state = MISMATCH$1; break; case 'AtKeyword': case 'Function': if (token !== null && areStringsEqualCaseInsensitive(token.value, state.name)) { addTokenToMatch(); state = MATCH$1; break; } state = MISMATCH$1; break; case 'Token': if (token !== null && token.value === state.value) { addTokenToMatch(); state = MATCH$1; break; } state = MISMATCH$1; break; case 'Comma': if (token !== null && token.type === TYPE$6.Comma) { if (isCommaContextStart(matchStack.token)) { state = MISMATCH$1; } else { addTokenToMatch(); state = isCommaContextEnd(token) ? MISMATCH$1 : MATCH$1; } } else { state = isCommaContextStart(matchStack.token) || isCommaContextEnd(token) ? MATCH$1 : MISMATCH$1; } break; case 'String': var string = ''; for (var lastTokenIndex = tokenIndex; lastTokenIndex < tokens.length && string.length < state.value.length; lastTokenIndex++) { string += tokens[lastTokenIndex].value; } if (areStringsEqualCaseInsensitive(string, state.value)) { while (tokenIndex < lastTokenIndex) { addTokenToMatch(); } state = MATCH$1; } else { state = MISMATCH$1; } break; default: throw new Error('Unknown node type: ' + state.type); } } totalIterationCount += iterationCount; switch (exitReason) { case null: console.warn('[csstree-match] BREAK after ' + ITERATION_LIMIT + ' iterations'); exitReason = EXIT_REASON_ITERATION_LIMIT; matchStack = null; break; case EXIT_REASON_MATCH: while (syntaxStack !== null) { closeSyntax(); } break; default: matchStack = null; } return { tokens: tokens, reason: exitReason, iterations: iterationCount, match: matchStack, longestMatch: longestMatch }; } function matchAsList(tokens, matchGraph, syntaxes) { var matchResult = internalMatch(tokens, matchGraph, syntaxes || {}); if (matchResult.match !== null) { var item = reverseList(matchResult.match).prev; matchResult.match = []; while (item !== null) { switch (item.type) { case STUB: break; case OPEN_SYNTAX: case CLOSE_SYNTAX: matchResult.match.push({ type: item.type, syntax: item.syntax }); break; default: matchResult.match.push({ token: item.token.value, node: item.token.node }); break; } item = item.prev; } } return matchResult; } function matchAsTree(tokens, matchGraph, syntaxes) { var matchResult = internalMatch(tokens, matchGraph, syntaxes || {}); if (matchResult.match === null) { return matchResult; } var item = matchResult.match; var host = matchResult.match = { syntax: matchGraph.syntax || null, match: [] }; var hostStack = [host]; // revert a list and start with 2nd item since 1st is a stub item item = reverseList(item).prev; // build a tree while (item !== null) { switch (item.type) { case OPEN_SYNTAX: host.match.push(host = { syntax: item.syntax, match: [] }); hostStack.push(host); break; case CLOSE_SYNTAX: hostStack.pop(); host = hostStack[hostStack.length - 1]; break; default: host.match.push({ syntax: item.syntax || null, token: item.token.value, node: item.token.node }); } item = item.prev; } return matchResult; } var match = { matchAsList: matchAsList, matchAsTree: matchAsTree, getTotalIterationCount: function() { return totalIterationCount; } }; function getTrace(node) { function shouldPutToTrace(syntax) { if (syntax === null) { return false; } return ( syntax.type === 'Type' || syntax.type === 'Property' || syntax.type === 'Keyword' ); } function hasMatch(matchNode) { if (Array.isArray(matchNode.match)) { // use for-loop for better perfomance for (var i = 0; i < matchNode.match.length; i++) { if (hasMatch(matchNode.match[i])) { if (shouldPutToTrace(matchNode.syntax)) { result.unshift(matchNode.syntax); } return true; } } } else if (matchNode.node === node) { result = shouldPutToTrace(matchNode.syntax) ? [matchNode.syntax] : []; return true; } return false; } var result = null; if (this.matched !== null) { hasMatch(this.matched); } return result; } function testNode(match, node, fn) { var trace = getTrace.call(match, node); if (trace === null) { return false; } return trace.some(fn); } function isType(node, type) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Type' && matchNode.name === type; }); } function isProperty(node, property) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Property' && matchNode.name === property; }); } function isKeyword(node) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Keyword'; }); } var trace = { getTrace: getTrace, isType: isType, isProperty: isProperty, isKeyword: isKeyword }; function getFirstMatchNode(matchNode) { if ('node' in matchNode) { return matchNode.node; } return getFirstMatchNode(matchNode.match[0]); } function getLastMatchNode(matchNode) { if ('node' in matchNode) { return matchNode.node; } return getLastMatchNode(matchNode.match[matchNode.match.length - 1]); } function matchFragments(lexer, ast, match, type, name) { function findFragments(matchNode) { if (matchNode.syntax !== null && matchNode.syntax.type === type && matchNode.syntax.name === name) { var start = getFirstMatchNode(matchNode); var end = getLastMatchNode(matchNode); lexer.syntax.walk(ast, function(node, item, list) { if (node === start) { var nodes = new List_1(); do { nodes.appendData(item.data); if (item.data === end) { break; } item = item.next; } while (item !== null); fragments.push({ parent: list, nodes: nodes }); } }); } if (Array.isArray(matchNode.match)) { matchNode.match.forEach(findFragments); } } var fragments = []; if (match.matched !== null) { findFragments(match.matched); } return fragments; } var search = { matchFragments: matchFragments }; var hasOwnProperty$2 = Object.prototype.hasOwnProperty; function isValidNumber(value) { // Number.isInteger(value) && value >= 0 return ( typeof value === 'number' && isFinite(value) && Math.floor(value) === value && value >= 0 ); } function isValidLocation(loc) { return ( Boolean(loc) && isValidNumber(loc.offset) && isValidNumber(loc.line) && isValidNumber(loc.column) ); } function createNodeStructureChecker(type, fields) { return function checkNode(node, warn) { if (!node || node.constructor !== Object) { return warn(node, 'Type of node should be an Object'); } for (var key in node) { var valid = true; if (hasOwnProperty$2.call(node, key) === false) { continue; } if (key === 'type') { if (node.type !== type) { warn(node, 'Wrong node type `' + node.type + '`, expected `' + type + '`'); } } else if (key === 'loc') { if (node.loc === null) { continue; } else if (node.loc && node.loc.constructor === Object) { if (typeof node.loc.source !== 'string') { key += '.source'; } else if (!isValidLocation(node.loc.start)) { key += '.start'; } else if (!isValidLocation(node.loc.end)) { key += '.end'; } else { continue; } } valid = false; } else if (fields.hasOwnProperty(key)) { for (var i = 0, valid = false; !valid && i < fields[key].length; i++) { var fieldType = fields[key][i]; switch (fieldType) { case String: valid = typeof node[key] === 'string'; break; case Boolean: valid = typeof node[key] === 'boolean'; break; case null: valid = node[key] === null; break; default: if (typeof fieldType === 'string') { valid = node[key] && node[key].type === fieldType; } else if (Array.isArray(fieldType)) { valid = node[key] instanceof List_1; } } } } else { warn(node, 'Unknown field `' + key + '` for ' + type + ' node type'); } if (!valid) { warn(node, 'Bad value for `' + type + '.' + key + '`'); } } for (var key in fields) { if (hasOwnProperty$2.call(fields, key) && hasOwnProperty$2.call(node, key) === false) { warn(node, 'Field `' + type + '.' + key + '` is missed'); } } }; } function processStructure(name, nodeType) { var structure = nodeType.structure; var fields = { type: String, loc: true }; var docs = { type: '"' + name + '"' }; for (var key in structure) { if (hasOwnProperty$2.call(structure, key) === false) { continue; } var docsTypes = []; var fieldTypes = fields[key] = Array.isArray(structure[key]) ? structure[key].slice() : [structure[key]]; for (var i = 0; i < fieldTypes.length; i++) { var fieldType = fieldTypes[i]; if (fieldType === String || fieldType === Boolean) { docsTypes.push(fieldType.name); } else if (fieldType === null) { docsTypes.push('null'); } else if (typeof fieldType === 'string') { docsTypes.push('<' + fieldType + '>'); } else if (Array.isArray(fieldType)) { docsTypes.push('List'); // TODO: use type enum } else { throw new Error('Wrong value `' + fieldType + '` in `' + name + '.' + key + '` structure definition'); } } docs[key] = docsTypes.join(' | '); } return { docs: docs, check: createNodeStructureChecker(name, fields) }; } var structure = { getStructureFromConfig: function(config) { var structure = {}; if (config.node) { for (var name in config.node) { if (hasOwnProperty$2.call(config.node, name)) { var nodeType = config.node[name]; if (nodeType.structure) { structure[name] = processStructure(name, nodeType); } else { throw new Error('Missed `structure` field in `' + name + '` node type definition'); } } } } return structure; } }; var SyntaxReferenceError$1 = error.SyntaxReferenceError; var MatchError$1 = error.MatchError; var buildMatchGraph$1 = matchGraph.buildMatchGraph; var matchAsTree$1 = match.matchAsTree; var getStructureFromConfig = structure.getStructureFromConfig; var cssWideKeywords$1 = buildMatchGraph$1('inherit | initial | unset'); var cssWideKeywordsWithExpression = buildMatchGraph$1('inherit | initial | unset | <-ms-legacy-expression>'); function dumpMapSyntax(map, compact, syntaxAsAst) { var result = {}; for (var name in map) { if (map[name].syntax) { result[name] = syntaxAsAst ? map[name].syntax : generate_1(map[name].syntax, { compact: compact }); } } return result; } function valueHasVar(tokens) { for (var i = 0; i < tokens.length; i++) { if (tokens[i].value.toLowerCase() === 'var(') { return true; } } return false; } function buildMatchResult(match, error, iterations) { return { matched: match, iterations: iterations, error: error, getTrace: trace.getTrace, isType: trace.isType, isProperty: trace.isProperty, isKeyword: trace.isKeyword }; } function matchSyntax(lexer, syntax, value, useCommon) { var tokens = prepareTokens_1(value, lexer.syntax); var result; if (valueHasVar(tokens)) { return buildMatchResult(null, new Error('Matching for a tree with var() is not supported')); } if (useCommon) { result = matchAsTree$1(tokens, lexer.valueCommonSyntax, lexer); } if (!useCommon || !result.match) { result = matchAsTree$1(tokens, syntax.match, lexer); if (!result.match) { return buildMatchResult( null, new MatchError$1(result.reason, syntax.syntax, value, result), result.iterations ); } } return buildMatchResult(result.match, null, result.iterations); } var Lexer = function(config, syntax, structure) { this.valueCommonSyntax = cssWideKeywords$1; this.syntax = syntax; this.generic = false; this.atrules = {}; this.properties = {}; this.types = {}; this.structure = structure || getStructureFromConfig(config); if (config) { if (config.types) { for (var name in config.types) { this.addType_(name, config.types[name]); } } if (config.generic) { this.generic = true; for (var name in generic) { this.addType_(name, generic[name]); } } if (config.atrules) { for (var name in config.atrules) { this.addAtrule_(name, config.atrules[name]); } } if (config.properties) { for (var name in config.properties) { this.addProperty_(name, config.properties[name]); } } } }; Lexer.prototype = { structure: {}, checkStructure: function(ast) { function collectWarning(node, message) { warns.push({ node: node, message: message }); } var structure = this.structure; var warns = []; this.syntax.walk(ast, function(node) { if (structure.hasOwnProperty(node.type)) { structure[node.type].check(node, collectWarning); } else { collectWarning(node, 'Unknown node type `' + node.type + '`'); } }); return warns.length ? warns : false; }, createDescriptor: function(syntax, type, name) { var ref = { type: type, name: name }; var descriptor = { type: type, name: name, syntax: null, match: null }; if (typeof syntax === 'function') { descriptor.match = buildMatchGraph$1(syntax, ref); } else { if (typeof syntax === 'string') { // lazy parsing on first access Object.defineProperty(descriptor, 'syntax', { get: function() { Object.defineProperty(descriptor, 'syntax', { value: parse_1(syntax) }); return descriptor.syntax; } }); } else { descriptor.syntax = syntax; } // lazy graph build on first access Object.defineProperty(descriptor, 'match', { get: function() { Object.defineProperty(descriptor, 'match', { value: buildMatchGraph$1(descriptor.syntax, ref) }); return descriptor.match; } }); } return descriptor; }, addAtrule_: function(name, syntax) { this.atrules[name] = { prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null, descriptors: syntax.descriptors ? Object.keys(syntax.descriptors).reduce((res, name) => { res[name] = this.createDescriptor(syntax.descriptors[name], 'AtruleDescriptor', name); return res; }, {}) : null }; }, addProperty_: function(name, syntax) { this.properties[name] = this.createDescriptor(syntax, 'Property', name); }, addType_: function(name, syntax) { this.types[name] = this.createDescriptor(syntax, 'Type', name); if (syntax === generic['-ms-legacy-expression']) { this.valueCommonSyntax = cssWideKeywordsWithExpression; } }, matchAtrulePrelude: function(atruleName, prelude) { var atrule = names.keyword(atruleName); var atrulePreludeSyntax = atrule.vendor ? this.getAtrulePrelude(atrule.name) || this.getAtrulePrelude(atrule.basename) : this.getAtrulePrelude(atrule.name); if (!atrulePreludeSyntax) { if (atrule.basename in this.atrules) { return buildMatchResult(null, new Error('At-rule `' + atruleName + '` should not contain a prelude')); } return buildMatchResult(null, new SyntaxReferenceError$1('Unknown at-rule', atruleName)); } return matchSyntax(this, atrulePreludeSyntax, prelude, true); }, matchAtruleDescriptor: function(atruleName, descriptorName, value) { var atrule = names.keyword(atruleName); var descriptor = names.keyword(descriptorName); var atruleEntry = atrule.vendor ? this.atrules[atrule.name] || this.atrules[atrule.basename] : this.atrules[atrule.name]; if (!atruleEntry) { return buildMatchResult(null, new SyntaxReferenceError$1('Unknown at-rule', atruleName)); } if (!atruleEntry.descriptors) { return buildMatchResult(null, new Error('At-rule `' + atruleName + '` has no known descriptors')); } var atruleDescriptorSyntax = descriptor.vendor ? atruleEntry.descriptors[descriptor.name] || atruleEntry.descriptors[descriptor.basename] : atruleEntry.descriptors[descriptor.name]; if (!atruleDescriptorSyntax) { return buildMatchResult(null, new SyntaxReferenceError$1('Unknown at-rule descriptor', descriptorName)); } return matchSyntax(this, atruleDescriptorSyntax, value, true); }, matchDeclaration: function(node) { if (node.type !== 'Declaration') { return buildMatchResult(null, new Error('Not a Declaration node')); } return this.matchProperty(node.property, node.value); }, matchProperty: function(propertyName, value) { var property = names.property(propertyName); // don't match syntax for a custom property if (property.custom) { return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties')); } var propertySyntax = property.vendor ? this.getProperty(property.name) || this.getProperty(property.basename) : this.getProperty(property.name); if (!propertySyntax) { return buildMatchResult(null, new SyntaxReferenceError$1('Unknown property', propertyName)); } return matchSyntax(this, propertySyntax, value, true); }, matchType: function(typeName, value) { var typeSyntax = this.getType(typeName); if (!typeSyntax) { return buildMatchResult(null, new SyntaxReferenceError$1('Unknown type', typeName)); } return matchSyntax(this, typeSyntax, value, false); }, match: function(syntax, value) { if (typeof syntax !== 'string' && (!syntax || !syntax.type)) { return buildMatchResult(null, new SyntaxReferenceError$1('Bad syntax')); } if (typeof syntax === 'string' || !syntax.match) { syntax = this.createDescriptor(syntax, 'Type', 'anonymous'); } return matchSyntax(this, syntax, value, false); }, findValueFragments: function(propertyName, value, type, name) { return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name); }, findDeclarationValueFragments: function(declaration, type, name) { return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name); }, findAllFragments: function(ast, type, name) { var result = []; this.syntax.walk(ast, { visit: 'Declaration', enter: function(declaration) { result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name)); }.bind(this) }); return result; }, getAtrulePrelude: function(atruleName) { return this.atrules.hasOwnProperty(atruleName) ? this.atrules[atruleName].prelude : null; }, getAtruleDescriptor: function(atruleName, name) { return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators ? this.atrules[atruleName].declarators[name] || null : null; }, getProperty: function(name) { return this.properties.hasOwnProperty(name) ? this.properties[name] : null; }, getType: function(name) { return this.types.hasOwnProperty(name) ? this.types[name] : null; }, validate: function() { function validate(syntax, name, broken, descriptor) { if (broken.hasOwnProperty(name)) { return broken[name]; } broken[name] = false; if (descriptor.syntax !== null) { walk$1(descriptor.syntax, function(node) { if (node.type !== 'Type' && node.type !== 'Property') { return; } var map = node.type === 'Type' ? syntax.types : syntax.properties; var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties; if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) { broken[name] = true; } }, this); } } var brokenTypes = {}; var brokenProperties = {}; for (var key in this.types) { validate(this, key, brokenTypes, this.types[key]); } for (var key in this.properties) { validate(this, key, brokenProperties, this.properties[key]); } brokenTypes = Object.keys(brokenTypes).filter(function(name) { return brokenTypes[name]; }); brokenProperties = Object.keys(brokenProperties).filter(function(name) { return brokenProperties[name]; }); if (brokenTypes.length || brokenProperties.length) { return { types: brokenTypes, properties: brokenProperties }; } return null; }, dump: function(syntaxAsAst, pretty) { return { generic: this.generic, types: dumpMapSyntax(this.types, !pretty, syntaxAsAst), properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst) }; }, toString: function() { return JSON.stringify(this.dump()); } }; var Lexer_1 = Lexer; var definitionSyntax = { SyntaxError: _SyntaxError$1, parse: parse_1, generate: generate_1, walk: walk$1 }; var isBOM$2 = tokenizer.isBOM; var N$3 = 10; var F$2 = 12; var R$2 = 13; function computeLinesAndColumns(host, source) { var sourceLength = source.length; var lines = adoptBuffer(host.lines, sourceLength); // +1 var line = host.startLine; var columns = adoptBuffer(host.columns, sourceLength); var column = host.startColumn; var startOffset = source.length > 0 ? isBOM$2(source.charCodeAt(0)) : 0; for (var i = startOffset; i < sourceLength; i++) { // -1 var code = source.charCodeAt(i); lines[i] = line; columns[i] = column++; if (code === N$3 || code === R$2 || code === F$2) { if (code === R$2 && i + 1 < sourceLength && source.charCodeAt(i + 1) === N$3) { i++; lines[i] = line; columns[i] = column; } line++; column = 1; } } lines[i] = line; columns[i] = column; host.lines = lines; host.columns = columns; } var OffsetToLocation = function() { this.lines = null; this.columns = null; this.linesAndColumnsComputed = false; }; OffsetToLocation.prototype = { setSource: function(source, startOffset, startLine, startColumn) { this.source = source; this.startOffset = typeof startOffset === 'undefined' ? 0 : startOffset; this.startLine = typeof startLine === 'undefined' ? 1 : startLine; this.startColumn = typeof startColumn === 'undefined' ? 1 : startColumn; this.linesAndColumnsComputed = false; }, ensureLinesAndColumnsComputed: function() { if (!this.linesAndColumnsComputed) { computeLinesAndColumns(this, this.source); this.linesAndColumnsComputed = true; } }, getLocation: function(offset, filename) { this.ensureLinesAndColumnsComputed(); return { source: filename, offset: this.startOffset + offset, line: this.lines[offset], column: this.columns[offset] }; }, getLocationRange: function(start, end, filename) { this.ensureLinesAndColumnsComputed(); return { source: filename, start: { offset: this.startOffset + start, line: this.lines[start], column: this.columns[start] }, end: { offset: this.startOffset + end, line: this.lines[end], column: this.columns[end] } }; } }; var OffsetToLocation_1 = OffsetToLocation; var TYPE$7 = tokenizer.TYPE; var WHITESPACE$2 = TYPE$7.WhiteSpace; var COMMENT$2 = TYPE$7.Comment; var sequence = function readSequence(recognizer) { var children = this.createList(); var child = null; var context = { recognizer: recognizer, space: null, ignoreWS: false, ignoreWSAfter: false }; this.scanner.skipSC(); while (!this.scanner.eof) { switch (this.scanner.tokenType) { case COMMENT$2: this.scanner.next(); continue; case WHITESPACE$2: if (context.ignoreWS) { this.scanner.next(); } else { context.space = this.WhiteSpace(); } continue; } child = recognizer.getNode.call(this, context); if (child === undefined) { break; } if (context.space !== null) { children.push(context.space); context.space = null; } children.push(child); if (context.ignoreWSAfter) { context.ignoreWSAfter = false; context.ignoreWS = true; } else { context.ignoreWS = false; } } return children; }; var findWhiteSpaceStart$1 = utils.findWhiteSpaceStart; var noop$3 = function() {}; var TYPE$8 = _const.TYPE; var NAME$2 = _const.NAME; var WHITESPACE$3 = TYPE$8.WhiteSpace; var IDENT$2 = TYPE$8.Ident; var FUNCTION = TYPE$8.Function; var URL$1 = TYPE$8.Url; var HASH = TYPE$8.Hash; var PERCENTAGE = TYPE$8.Percentage; var NUMBER$2 = TYPE$8.Number; var NUMBERSIGN$1 = 0x0023; // U+0023 NUMBER SIGN (#) var NULL = 0; function createParseContext(name) { return function() { return this[name](); }; } function processConfig(config) { var parserConfig = { context: {}, scope: {}, atrule: {}, pseudo: {} }; if (config.parseContext) { for (var name in config.parseContext) { switch (typeof config.parseContext[name]) { case 'function': parserConfig.context[name] = config.parseContext[name]; break; case 'string': parserConfig.context[name] = createParseContext(config.parseContext[name]); break; } } } if (config.scope) { for (var name in config.scope) { parserConfig.scope[name] = config.scope[name]; } } if (config.atrule) { for (var name in config.atrule) { var atrule = config.atrule[name]; if (atrule.parse) { parserConfig.atrule[name] = atrule.parse; } } } if (config.pseudo) { for (var name in config.pseudo) { var pseudo = config.pseudo[name]; if (pseudo.parse) { parserConfig.pseudo[name] = pseudo.parse; } } } if (config.node) { for (var name in config.node) { parserConfig[name] = config.node[name].parse; } } return parserConfig; } var create$1 = function createParser(config) { var parser = { scanner: new TokenStream_1(), locationMap: new OffsetToLocation_1(), filename: '<unknown>', needPositions: false, onParseError: noop$3, onParseErrorThrow: false, parseAtrulePrelude: true, parseRulePrelude: true, parseValue: true, parseCustomProperty: false, readSequence: sequence, createList: function() { return new List_1(); }, createSingleNodeList: function(node) { return new List_1().appendData(node); }, getFirstListNode: function(list) { return list && list.first(); }, getLastListNode: function(list) { return list.last(); }, parseWithFallback: function(consumer, fallback) { var startToken = this.scanner.tokenIndex; try { return consumer.call(this); } catch (e) { if (this.onParseErrorThrow) { throw e; } var fallbackNode = fallback.call(this, startToken); this.onParseErrorThrow = true; this.onParseError(e, fallbackNode); this.onParseErrorThrow = false; return fallbackNode; } }, lookupNonWSType: function(offset) { do { var type = this.scanner.lookupType(offset++); if (type !== WHITESPACE$3) { return type; } } while (type !== NULL); return NULL; }, eat: function(tokenType) { if (this.scanner.tokenType !== tokenType) { var offset = this.scanner.tokenStart; var message = NAME$2[tokenType] + ' is expected'; // tweak message and offset switch (tokenType) { case IDENT$2: // when identifier is expected but there is a function or url if (this.scanner.tokenType === FUNCTION || this.scanner.tokenType === URL$1) { offset = this.scanner.tokenEnd - 1; message = 'Identifier is expected but function found'; } else { message = 'Identifier is expected'; } break; case HASH: if (this.scanner.isDelim(NUMBERSIGN$1)) { this.scanner.next(); offset++; message = 'Name is expected'; } break; case PERCENTAGE: if (this.scanner.tokenType === NUMBER$2) { offset = this.scanner.tokenEnd; message = 'Percent sign is expected'; } break; default: // when test type is part of another token show error for current position + 1 // e.g. eat(HYPHENMINUS) will fail on "-foo", but pointing on "-" is odd if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === tokenType) { offset = offset + 1; } } this.error(message, offset); } this.scanner.next(); }, consume: function(tokenType) { var value = this.scanner.getTokenValue(); this.eat(tokenType); return value; }, consumeFunctionName: function() { var name = this.scanner.source.substring(this.scanner.tokenStart, this.scanner.tokenEnd - 1); this.eat(FUNCTION); return name; }, getLocation: function(start, end) { if (this.needPositions) { return this.locationMap.getLocationRange( start, end, this.filename ); } return null; }, getLocationFromList: function(list) { if (this.needPositions) { var head = this.getFirstListNode(list); var tail = this.getLastListNode(list); return this.locationMap.getLocationRange( head !== null ? head.loc.start.offset - this.locationMap.startOffset : this.scanner.tokenStart, tail !== null ? tail.loc.end.offset - this.locationMap.startOffset : this.scanner.tokenStart, this.filename ); } return null; }, error: function(message, offset) { var location = typeof offset !== 'undefined' && offset < this.scanner.source.length ? this.locationMap.getLocation(offset) : this.scanner.eof ? this.locationMap.getLocation(findWhiteSpaceStart$1(this.scanner.source, this.scanner.source.length - 1)) : this.locationMap.getLocation(this.scanner.tokenStart); throw new _SyntaxError( message || 'Unexpected input', this.scanner.source, location.offset, location.line, location.column ); } }; config = processConfig(config || {}); for (var key in config) { parser[key] = config[key]; } return function(source, options) { options = options || {}; var context = options.context || 'default'; var ast; tokenizer(source, parser.scanner); parser.locationMap.setSource( source, options.offset, options.line, options.column ); parser.filename = options.filename || '<unknown>'; parser.needPositions = Boolean(options.positions); parser.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop$3; parser.onParseErrorThrow = false; parser.parseAtrulePrelude = 'parseAtrulePrelude' in options ? Boolean(options.parseAtrulePrelude) : true; parser.parseRulePrelude = 'parseRulePrelude' in options ? Boolean(options.parseRulePrelude) : true; parser.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true; parser.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false; if (!parser.context.hasOwnProperty(context)) { throw new Error('Unknown context `' + context + '`'); } ast = parser.context[context].call(parser, options); if (!parser.scanner.eof) { parser.error(); } return ast; }; }; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); /** * Encode an integer in the range of 0 to 63 to a single base 64 digit. */ var encode = function (number) { if (0 <= number && number < intToCharMap.length) { return intToCharMap[number]; } throw new TypeError("Must be between 0 and 63: " + number); }; /** * Decode a single base 64 character code digit to an integer. Returns -1 on * failure. */ var decode = function (charCode) { var bigA = 65; // 'A' var bigZ = 90; // 'Z' var littleA = 97; // 'a' var littleZ = 122; // 'z' var zero = 48; // '0' var nine = 57; // '9' var plus = 43; // '+' var slash = 47; // '/' var littleOffset = 26; var numberOffset = 52; // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ if (bigA <= charCode && charCode <= bigZ) { return (charCode - bigA); } // 26 - 51: abcdefghijklmnopqrstuvwxyz if (littleA <= charCode && charCode <= littleZ) { return (charCode - littleA + littleOffset); } // 52 - 61: 0123456789 if (zero <= charCode && charCode <= nine) { return (charCode - zero + numberOffset); } // 62: + if (charCode == plus) { return 62; } // 63: / if (charCode == slash) { return 63; } // Invalid base64 digit. return -1; }; var base64 = { encode: encode, decode: decode }; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause * * Based on the Base 64 VLQ implementation in Closure Compiler: * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java * * Copyright 2011 The Closure Compiler Authors. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, // the next four bits are the actual value, and the 6th bit is the // continuation bit. The continuation bit tells us whether there are more // digits in this value following this digit. // // Continuation // | Sign // | | // V V // 101011 var VLQ_BASE_SHIFT = 5; // binary: 100000 var VLQ_BASE = 1 << VLQ_BASE_SHIFT; // binary: 011111 var VLQ_BASE_MASK = VLQ_BASE - 1; // binary: 100000 var VLQ_CONTINUATION_BIT = VLQ_BASE; /** * Converts from a two-complement value to a value where the sign bit is * placed in the least significant bit. For example, as decimals: * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) */ function toVLQSigned(aValue) { return aValue < 0 ? ((-aValue) << 1) + 1 : (aValue << 1) + 0; } /** * Converts to a two-complement value from a value where the sign bit is * placed in the least significant bit. For example, as decimals: * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 */ function fromVLQSigned(aValue) { var isNegative = (aValue & 1) === 1; var shifted = aValue >> 1; return isNegative ? -shifted : shifted; } /** * Returns the base 64 VLQ encoded value. */ var encode$1 = function base64VLQ_encode(aValue) { var encoded = ""; var digit; var vlq = toVLQSigned(aValue); do { digit = vlq & VLQ_BASE_MASK; vlq >>>= VLQ_BASE_SHIFT; if (vlq > 0) { // There are still more digits in this value, so we must make sure the // continuation bit is marked. digit |= VLQ_CONTINUATION_BIT; } encoded += base64.encode(digit); } while (vlq > 0); return encoded; }; /** * Decodes the next base 64 VLQ value from the given string and returns the * value and the rest of the string via the out parameter. */ var decode$1 = function base64VLQ_decode(aStr, aIndex, aOutParam) { var strLen = aStr.length; var result = 0; var shift = 0; var continuation, digit; do { if (aIndex >= strLen) { throw new Error("Expected more digits in base 64 VLQ value."); } digit = base64.decode(aStr.charCodeAt(aIndex++)); if (digit === -1) { throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); } continuation = !!(digit & VLQ_CONTINUATION_BIT); digit &= VLQ_BASE_MASK; result = result + (digit << shift); shift += VLQ_BASE_SHIFT; } while (continuation); aOutParam.value = fromVLQSigned(result); aOutParam.rest = aIndex; }; var base64Vlq = { encode: encode$1, decode: decode$1 }; var util = createCommonjsModule(function (module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ /** * This is a helper function for getting values from parameter/options * objects. * * @param args The object we are extracting values from * @param name The name of the property we are getting. * @param defaultValue An optional value to return if the property is missing * from the object. If this is not specified and the property is missing, an * error will be thrown. */ function getArg(aArgs, aName, aDefaultValue) { if (aName in aArgs) { return aArgs[aName]; } else if (arguments.length === 3) { return aDefaultValue; } else { throw new Error('"' + aName + '" is a required argument.'); } } exports.getArg = getArg; var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/; var dataUrlRegexp = /^data:.+\,.+$/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); if (!match) { return null; } return { scheme: match[1], auth: match[2], host: match[3], port: match[4], path: match[5] }; } exports.urlParse = urlParse; function urlGenerate(aParsedUrl) { var url = ''; if (aParsedUrl.scheme) { url += aParsedUrl.scheme + ':'; } url += '//'; if (aParsedUrl.auth) { url += aParsedUrl.auth + '@'; } if (aParsedUrl.host) { url += aParsedUrl.host; } if (aParsedUrl.port) { url += ":" + aParsedUrl.port; } if (aParsedUrl.path) { url += aParsedUrl.path; } return url; } exports.urlGenerate = urlGenerate; /** * Normalizes a path, or the path portion of a URL: * * - Replaces consecutive slashes with one slash. * - Removes unnecessary '.' parts. * - Removes unnecessary '<dir>/..' parts. * * Based on code in the Node.js 'path' core module. * * @param aPath The path or url to normalize. */ function normalize(aPath) { var path = aPath; var url = urlParse(aPath); if (url) { if (!url.path) { return aPath; } path = url.path; } var isAbsolute = exports.isAbsolute(path); var parts = path.split(/\/+/); for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { part = parts[i]; if (part === '.') { parts.splice(i, 1); } else if (part === '..') { up++; } else if (up > 0) { if (part === '') { // The first part is blank if the path is absolute. Trying to go // above the root is a no-op. Therefore we can remove all '..' parts // directly after the root. parts.splice(i + 1, up); up = 0; } else { parts.splice(i, 2); up--; } } } path = parts.join('/'); if (path === '') { path = isAbsolute ? '/' : '.'; } if (url) { url.path = path; return urlGenerate(url); } return path; } exports.normalize = normalize; /** * Joins two paths/URLs. * * @param aRoot The root path or URL. * @param aPath The path or URL to be joined with the root. * * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a * scheme-relative URL: Then the scheme of aRoot, if any, is prepended * first. * - Otherwise aPath is a path. If aRoot is a URL, then its path portion * is updated with the result and aRoot is returned. Otherwise the result * is returned. * - If aPath is absolute, the result is aPath. * - Otherwise the two paths are joined with a slash. * - Joining for example 'http://' and 'www.example.com' is also supported. */ function join(aRoot, aPath) { if (aRoot === "") { aRoot = "."; } if (aPath === "") { aPath = "."; } var aPathUrl = urlParse(aPath); var aRootUrl = urlParse(aRoot); if (aRootUrl) { aRoot = aRootUrl.path || '/'; } // `join(foo, '//www.example.org')` if (aPathUrl && !aPathUrl.scheme) { if (aRootUrl) { aPathUrl.scheme = aRootUrl.scheme; } return urlGenerate(aPathUrl); } if (aPathUrl || aPath.match(dataUrlRegexp)) { return aPath; } // `join('http://', 'www.example.com')` if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { aRootUrl.host = aPath; return urlGenerate(aRootUrl); } var joined = aPath.charAt(0) === '/' ? aPath : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); if (aRootUrl) { aRootUrl.path = joined; return urlGenerate(aRootUrl); } return joined; } exports.join = join; exports.isAbsolute = function (aPath) { return aPath.charAt(0) === '/' || urlRegexp.test(aPath); }; /** * Make a path relative to a URL or another path. * * @param aRoot The root path or URL. * @param aPath The path or URL to be made relative to aRoot. */ function relative(aRoot, aPath) { if (aRoot === "") { aRoot = "."; } aRoot = aRoot.replace(/\/$/, ''); // It is possible for the path to be above the root. In this case, simply // checking whether the root is a prefix of the path won't work. Instead, we // need to remove components from the root one by one, until either we find // a prefix that fits, or we run out of components to remove. var level = 0; while (aPath.indexOf(aRoot + '/') !== 0) { var index = aRoot.lastIndexOf("/"); if (index < 0) { return aPath; } // If the only part of the root that is left is the scheme (i.e. http://, // file:///, etc.), one or more slashes (/), or simply nothing at all, we // have exhausted all components, so the path is not relative to the root. aRoot = aRoot.slice(0, index); if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { return aPath; } ++level; } // Make sure we add a "../" for each component we removed from the root. return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); } exports.relative = relative; var supportsNullProto = (function () { var obj = Object.create(null); return !('__proto__' in obj); }()); function identity (s) { return s; } /** * Because behavior goes wacky when you set `__proto__` on objects, we * have to prefix all the strings in our set with an arbitrary character. * * See https://github.com/mozilla/source-map/pull/31 and * https://github.com/mozilla/source-map/issues/30 * * @param String aStr */ function toSetString(aStr) { if (isProtoString(aStr)) { return '$' + aStr; } return aStr; } exports.toSetString = supportsNullProto ? identity : toSetString; function fromSetString(aStr) { if (isProtoString(aStr)) { return aStr.slice(1); } return aStr; } exports.fromSetString = supportsNullProto ? identity : fromSetString; function isProtoString(s) { if (!s) { return false; } var length = s.length; if (length < 9 /* "__proto__".length */) { return false; } if (s.charCodeAt(length - 1) !== 95 /* '_' */ || s.charCodeAt(length - 2) !== 95 /* '_' */ || s.charCodeAt(length - 3) !== 111 /* 'o' */ || s.charCodeAt(length - 4) !== 116 /* 't' */ || s.charCodeAt(length - 5) !== 111 /* 'o' */ || s.charCodeAt(length - 6) !== 114 /* 'r' */ || s.charCodeAt(length - 7) !== 112 /* 'p' */ || s.charCodeAt(length - 8) !== 95 /* '_' */ || s.charCodeAt(length - 9) !== 95 /* '_' */) { return false; } for (var i = length - 10; i >= 0; i--) { if (s.charCodeAt(i) !== 36 /* '$' */) { return false; } } return true; } /** * Comparator between two mappings where the original positions are compared. * * Optionally pass in `true` as `onlyCompareGenerated` to consider two * mappings with the same original source/line/column, but different generated * line and column the same. Useful when searching for a mapping with a * stubbed out mapping. */ function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { var cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0 || onlyCompareOriginal) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByOriginalPositions = compareByOriginalPositions; /** * Comparator between two mappings with deflated source and name indices where * the generated positions are compared. * * Optionally pass in `true` as `onlyCompareGenerated` to consider two * mappings with the same generated line and column, but different * source/name/original line and column the same. Useful when searching for a * mapping with a stubbed out mapping. */ function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { var cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0 || onlyCompareGenerated) { return cmp; } cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; function strcmp(aStr1, aStr2) { if (aStr1 === aStr2) { return 0; } if (aStr1 === null) { return 1; // aStr2 !== null } if (aStr2 === null) { return -1; // aStr1 !== null } if (aStr1 > aStr2) { return 1; } return -1; } /** * Comparator between two mappings with inflated source and name strings where * the generated positions are compared. */ function compareByGeneratedPositionsInflated(mappingA, mappingB) { var cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0) { return cmp; } cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; /** * Strip any JSON XSSI avoidance prefix from the string (as documented * in the source maps specification), and then parse the string as * JSON. */ function parseSourceMapInput(str) { return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, '')); } exports.parseSourceMapInput = parseSourceMapInput; /** * Compute the URL of a source given the the source root, the source's * URL, and the source map's URL. */ function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) { sourceURL = sourceURL || ''; if (sourceRoot) { // This follows what Chrome does. if (sourceRoot[sourceRoot.length - 1] !== '/' && sourceURL[0] !== '/') { sourceRoot += '/'; } // The spec says: // Line 4: An optional source root, useful for relocating source // files on a server or removing repeated values in the // “sources” entry. This value is prepended to the individual // entries in the “source” field. sourceURL = sourceRoot + sourceURL; } // Historically, SourceMapConsumer did not take the sourceMapURL as // a parameter. This mode is still somewhat supported, which is why // this code block is conditional. However, it's preferable to pass // the source map URL to SourceMapConsumer, so that this function // can implement the source URL resolution algorithm as outlined in // the spec. This block is basically the equivalent of: // new URL(sourceURL, sourceMapURL).toString() // ... except it avoids using URL, which wasn't available in the // older releases of node still supported by this library. // // The spec says: // If the sources are not absolute URLs after prepending of the // “sourceRoot”, the sources are resolved relative to the // SourceMap (like resolving script src in a html document). if (sourceMapURL) { var parsed = urlParse(sourceMapURL); if (!parsed) { throw new Error("sourceMapURL could not be parsed"); } if (parsed.path) { // Strip the last path component, but keep the "/". var index = parsed.path.lastIndexOf('/'); if (index >= 0) { parsed.path = parsed.path.substring(0, index + 1); } } sourceURL = join(urlGenerate(parsed), sourceURL); } return normalize(sourceURL); } exports.computeSourceURL = computeSourceURL; }); var util_1 = util.getArg; var util_2 = util.urlParse; var util_3 = util.urlGenerate; var util_4 = util.normalize; var util_5 = util.join; var util_6 = util.isAbsolute; var util_7 = util.relative; var util_8 = util.toSetString; var util_9 = util.fromSetString; var util_10 = util.compareByOriginalPositions; var util_11 = util.compareByGeneratedPositionsDeflated; var util_12 = util.compareByGeneratedPositionsInflated; var util_13 = util.parseSourceMapInput; var util_14 = util.computeSourceURL; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; /** * A data structure which is a combination of an array and a set. Adding a new * member is O(1), testing for membership is O(1), and finding the index of an * element is O(1). Removing elements from the set is not supported. Only * strings are supported for membership. */ function ArraySet() { this._array = []; this._set = hasNativeMap ? new Map() : Object.create(null); } /** * Static method for creating ArraySet instances from an existing array. */ ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { var set = new ArraySet(); for (var i = 0, len = aArray.length; i < len; i++) { set.add(aArray[i], aAllowDuplicates); } return set; }; /** * Return how many unique items are in this ArraySet. If duplicates have been * added, than those do not count towards the size. * * @returns Number */ ArraySet.prototype.size = function ArraySet_size() { return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; }; /** * Add the given string to this set. * * @param String aStr */ ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { var sStr = hasNativeMap ? aStr : util.toSetString(aStr); var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); var idx = this._array.length; if (!isDuplicate || aAllowDuplicates) { this._array.push(aStr); } if (!isDuplicate) { if (hasNativeMap) { this._set.set(aStr, idx); } else { this._set[sStr] = idx; } } }; /** * Is the given string a member of this set? * * @param String aStr */ ArraySet.prototype.has = function ArraySet_has(aStr) { if (hasNativeMap) { return this._set.has(aStr); } else { var sStr = util.toSetString(aStr); return has.call(this._set, sStr); } }; /** * What is the index of the given string in the array? * * @param String aStr */ ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { if (hasNativeMap) { var idx = this._set.get(aStr); if (idx >= 0) { return idx; } } else { var sStr = util.toSetString(aStr); if (has.call(this._set, sStr)) { return this._set[sStr]; } } throw new Error('"' + aStr + '" is not in the set.'); }; /** * What is the element at the given index? * * @param Number aIdx */ ArraySet.prototype.at = function ArraySet_at(aIdx) { if (aIdx >= 0 && aIdx < this._array.length) { return this._array[aIdx]; } throw new Error('No element indexed by ' + aIdx); }; /** * Returns the array representation of this set (which has the proper indices * indicated by indexOf). Note that this is a copy of the internal array used * for storing the members so that no one can mess with internal state. */ ArraySet.prototype.toArray = function ArraySet_toArray() { return this._array.slice(); }; var ArraySet_1 = ArraySet; var arraySet = { ArraySet: ArraySet_1 }; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2014 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ /** * Determine whether mappingB is after mappingA with respect to generated * position. */ function generatedPositionAfter(mappingA, mappingB) { // Optimized for most common case var lineA = mappingA.generatedLine; var lineB = mappingB.generatedLine; var columnA = mappingA.generatedColumn; var columnB = mappingB.generatedColumn; return lineB > lineA || lineB == lineA && columnB >= columnA || util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; } /** * A data structure to provide a sorted view of accumulated mappings in a * performance conscious manner. It trades a neglibable overhead in general * case for a large speedup in case of mappings being added in order. */ function MappingList() { this._array = []; this._sorted = true; // Serves as infimum this._last = {generatedLine: -1, generatedColumn: 0}; } /** * Iterate through internal items. This method takes the same arguments that * `Array.prototype.forEach` takes. * * NOTE: The order of the mappings is NOT guaranteed. */ MappingList.prototype.unsortedForEach = function MappingList_forEach(aCallback, aThisArg) { this._array.forEach(aCallback, aThisArg); }; /** * Add the given source mapping. * * @param Object aMapping */ MappingList.prototype.add = function MappingList_add(aMapping) { if (generatedPositionAfter(this._last, aMapping)) { this._last = aMapping; this._array.push(aMapping); } else { this._sorted = false; this._array.push(aMapping); } }; /** * Returns the flat, sorted array of mappings. The mappings are sorted by * generated position. * * WARNING: This method returns internal data without copying, for * performance. The return value must NOT be mutated, and should be treated as * an immutable borrow. If you want to take ownership, you must make your own * copy. */ MappingList.prototype.toArray = function MappingList_toArray() { if (!this._sorted) { this._array.sort(util.compareByGeneratedPositionsInflated); this._sorted = true; } return this._array; }; var MappingList_1 = MappingList; var mappingList = { MappingList: MappingList_1 }; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var ArraySet$1 = arraySet.ArraySet; var MappingList$1 = mappingList.MappingList; /** * An instance of the SourceMapGenerator represents a source map which is * being built incrementally. You may pass an object with the following * properties: * * - file: The filename of the generated source. * - sourceRoot: A root for all relative URLs in this source map. */ function SourceMapGenerator(aArgs) { if (!aArgs) { aArgs = {}; } this._file = util.getArg(aArgs, 'file', null); this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); this._skipValidation = util.getArg(aArgs, 'skipValidation', false); this._sources = new ArraySet$1(); this._names = new ArraySet$1(); this._mappings = new MappingList$1(); this._sourcesContents = null; } SourceMapGenerator.prototype._version = 3; /** * Creates a new SourceMapGenerator based on a SourceMapConsumer * * @param aSourceMapConsumer The SourceMap. */ SourceMapGenerator.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { var sourceRoot = aSourceMapConsumer.sourceRoot; var generator = new SourceMapGenerator({ file: aSourceMapConsumer.file, sourceRoot: sourceRoot }); aSourceMapConsumer.eachMapping(function (mapping) { var newMapping = { generated: { line: mapping.generatedLine, column: mapping.generatedColumn } }; if (mapping.source != null) { newMapping.source = mapping.source; if (sourceRoot != null) { newMapping.source = util.relative(sourceRoot, newMapping.source); } newMapping.original = { line: mapping.originalLine, column: mapping.originalColumn }; if (mapping.name != null) { newMapping.name = mapping.name; } } generator.addMapping(newMapping); }); aSourceMapConsumer.sources.forEach(function (sourceFile) { var sourceRelative = sourceFile; if (sourceRoot !== null) { sourceRelative = util.relative(sourceRoot, sourceFile); } if (!generator._sources.has(sourceRelative)) { generator._sources.add(sourceRelative); } var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { generator.setSourceContent(sourceFile, content); } }); return generator; }; /** * Add a single mapping from original source line and column to the generated * source's line and column for this source map being created. The mapping * object should have the following properties: * * - generated: An object with the generated line and column positions. * - original: An object with the original line and column positions. * - source: The original source file (relative to the sourceRoot). * - name: An optional original token name for this mapping. */ SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { var generated = util.getArg(aArgs, 'generated'); var original = util.getArg(aArgs, 'original', null); var source = util.getArg(aArgs, 'source', null); var name = util.getArg(aArgs, 'name', null); if (!this._skipValidation) { this._validateMapping(generated, original, source, name); } if (source != null) { source = String(source); if (!this._sources.has(source)) { this._sources.add(source); } } if (name != null) { name = String(name); if (!this._names.has(name)) { this._names.add(name); } } this._mappings.add({ generatedLine: generated.line, generatedColumn: generated.column, originalLine: original != null && original.line, originalColumn: original != null && original.column, source: source, name: name }); }; /** * Set the source content for a source file. */ SourceMapGenerator.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { var source = aSourceFile; if (this._sourceRoot != null) { source = util.relative(this._sourceRoot, source); } if (aSourceContent != null) { // Add the source content to the _sourcesContents map. // Create a new _sourcesContents map if the property is null. if (!this._sourcesContents) { this._sourcesContents = Object.create(null); } this._sourcesContents[util.toSetString(source)] = aSourceContent; } else if (this._sourcesContents) { // Remove the source file from the _sourcesContents map. // If the _sourcesContents map is empty, set the property to null. delete this._sourcesContents[util.toSetString(source)]; if (Object.keys(this._sourcesContents).length === 0) { this._sourcesContents = null; } } }; /** * Applies the mappings of a sub-source-map for a specific source file to the * source map being generated. Each mapping to the supplied source file is * rewritten using the supplied source map. Note: The resolution for the * resulting mappings is the minimium of this map and the supplied map. * * @param aSourceMapConsumer The source map to be applied. * @param aSourceFile Optional. The filename of the source file. * If omitted, SourceMapConsumer's file property will be used. * @param aSourceMapPath Optional. The dirname of the path to the source map * to be applied. If relative, it is relative to the SourceMapConsumer. * This parameter is needed when the two source maps aren't in the same * directory, and the source map to be applied contains relative source * paths. If so, those relative source paths need to be rewritten * relative to the SourceMapGenerator. */ SourceMapGenerator.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { var sourceFile = aSourceFile; // If aSourceFile is omitted, we will use the file property of the SourceMap if (aSourceFile == null) { if (aSourceMapConsumer.file == null) { throw new Error( 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + 'or the source map\'s "file" property. Both were omitted.' ); } sourceFile = aSourceMapConsumer.file; } var sourceRoot = this._sourceRoot; // Make "sourceFile" relative if an absolute Url is passed. if (sourceRoot != null) { sourceFile = util.relative(sourceRoot, sourceFile); } // Applying the SourceMap can add and remove items from the sources and // the names array. var newSources = new ArraySet$1(); var newNames = new ArraySet$1(); // Find mappings for the "sourceFile" this._mappings.unsortedForEach(function (mapping) { if (mapping.source === sourceFile && mapping.originalLine != null) { // Check if it can be mapped by the source map, then update the mapping. var original = aSourceMapConsumer.originalPositionFor({ line: mapping.originalLine, column: mapping.originalColumn }); if (original.source != null) { // Copy mapping mapping.source = original.source; if (aSourceMapPath != null) { mapping.source = util.join(aSourceMapPath, mapping.source); } if (sourceRoot != null) { mapping.source = util.relative(sourceRoot, mapping.source); } mapping.originalLine = original.line; mapping.originalColumn = original.column; if (original.name != null) { mapping.name = original.name; } } } var source = mapping.source; if (source != null && !newSources.has(source)) { newSources.add(source); } var name = mapping.name; if (name != null && !newNames.has(name)) { newNames.add(name); } }, this); this._sources = newSources; this._names = newNames; // Copy sourcesContents of applied map. aSourceMapConsumer.sources.forEach(function (sourceFile) { var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { if (aSourceMapPath != null) { sourceFile = util.join(aSourceMapPath, sourceFile); } if (sourceRoot != null) { sourceFile = util.relative(sourceRoot, sourceFile); } this.setSourceContent(sourceFile, content); } }, this); }; /** * A mapping can have one of the three levels of data: * * 1. Just the generated position. * 2. The Generated position, original position, and original source. * 3. Generated and original position, original source, as well as a name * token. * * To maintain consistency, we validate that any new mapping being added falls * in to one of these categories. */ SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { // When aOriginal is truthy but has empty values for .line and .column, // it is most likely a programmer error. In this case we throw a very // specific error message to try to guide them the right way. // For example: https://github.com/Polymer/polymer-bundler/pull/519 if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { throw new Error( 'original.line and original.column are not numbers -- you probably meant to omit ' + 'the original mapping entirely and only map the generated position. If so, pass ' + 'null for the original mapping instead of an object with empty or null values.' ); } if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { // Case 1. return; } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { // Cases 2 and 3. return; } else { throw new Error('Invalid mapping: ' + JSON.stringify({ generated: aGenerated, source: aSource, original: aOriginal, name: aName })); } }; /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. */ SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { var previousGeneratedColumn = 0; var previousGeneratedLine = 1; var previousOriginalColumn = 0; var previousOriginalLine = 0; var previousName = 0; var previousSource = 0; var result = ''; var next; var mapping; var nameIdx; var sourceIdx; var mappings = this._mappings.toArray(); for (var i = 0, len = mappings.length; i < len; i++) { mapping = mappings[i]; next = ''; if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; while (mapping.generatedLine !== previousGeneratedLine) { next += ';'; previousGeneratedLine++; } } else { if (i > 0) { if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { continue; } next += ','; } } next += base64Vlq.encode(mapping.generatedColumn - previousGeneratedColumn); previousGeneratedColumn = mapping.generatedColumn; if (mapping.source != null) { sourceIdx = this._sources.indexOf(mapping.source); next += base64Vlq.encode(sourceIdx - previousSource); previousSource = sourceIdx; // lines are stored 0-based in SourceMap spec version 3 next += base64Vlq.encode(mapping.originalLine - 1 - previousOriginalLine); previousOriginalLine = mapping.originalLine - 1; next += base64Vlq.encode(mapping.originalColumn - previousOriginalColumn); previousOriginalColumn = mapping.originalColumn; if (mapping.name != null) { nameIdx = this._names.indexOf(mapping.name); next += base64Vlq.encode(nameIdx - previousName); previousName = nameIdx; } } result += next; } return result; }; SourceMapGenerator.prototype._generateSourcesContent = function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { return aSources.map(function (source) { if (!this._sourcesContents) { return null; } if (aSourceRoot != null) { source = util.relative(aSourceRoot, source); } var key = util.toSetString(source); return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) ? this._sourcesContents[key] : null; }, this); }; /** * Externalize the source map. */ SourceMapGenerator.prototype.toJSON = function SourceMapGenerator_toJSON() { var map = { version: this._version, sources: this._sources.toArray(), names: this._names.toArray(), mappings: this._serializeMappings() }; if (this._file != null) { map.file = this._file; } if (this._sourceRoot != null) { map.sourceRoot = this._sourceRoot; } if (this._sourcesContents) { map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); } return map; }; /** * Render the source map being generated to a string. */ SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() { return JSON.stringify(this.toJSON()); }; var SourceMapGenerator_1 = SourceMapGenerator; var sourceMapGenerator = { SourceMapGenerator: SourceMapGenerator_1 }; var SourceMapGenerator$1 = sourceMapGenerator.SourceMapGenerator; var trackNodes = { Atrule: true, Selector: true, Declaration: true }; var sourceMap = function generateSourceMap(handlers) { var map = new SourceMapGenerator$1(); var line = 1; var column = 0; var generated = { line: 1, column: 0 }; var original = { line: 0, // should be zero to add first mapping column: 0 }; var sourceMappingActive = false; var activatedGenerated = { line: 1, column: 0 }; var activatedMapping = { generated: activatedGenerated }; var handlersNode = handlers.node; handlers.node = function(node) { if (node.loc && node.loc.start && trackNodes.hasOwnProperty(node.type)) { var nodeLine = node.loc.start.line; var nodeColumn = node.loc.start.column - 1; if (original.line !== nodeLine || original.column !== nodeColumn) { original.line = nodeLine; original.column = nodeColumn; generated.line = line; generated.column = column; if (sourceMappingActive) { sourceMappingActive = false; if (generated.line !== activatedGenerated.line || generated.column !== activatedGenerated.column) { map.addMapping(activatedMapping); } } sourceMappingActive = true; map.addMapping({ source: node.loc.source, original: original, generated: generated }); } } handlersNode.call(this, node); if (sourceMappingActive && trackNodes.hasOwnProperty(node.type)) { activatedGenerated.line = line; activatedGenerated.column = column; } }; var handlersChunk = handlers.chunk; handlers.chunk = function(chunk) { for (var i = 0; i < chunk.length; i++) { if (chunk.charCodeAt(i) === 10) { // \n line++; column = 0; } else { column++; } } handlersChunk(chunk); }; var handlersResult = handlers.result; handlers.result = function() { if (sourceMappingActive) { map.addMapping(activatedMapping); } return { css: handlersResult(), map: map }; }; return handlers; }; var hasOwnProperty$3 = Object.prototype.hasOwnProperty; function processChildren(node, delimeter) { var list = node.children; var prev = null; if (typeof delimeter !== 'function') { list.forEach(this.node, this); } else { list.forEach(function(node) { if (prev !== null) { delimeter.call(this, prev); } this.node(node); prev = node; }, this); } } var create$2 = function createGenerator(config) { function processNode(node) { if (hasOwnProperty$3.call(types, node.type)) { types[node.type].call(this, node); } else { throw new Error('Unknown node type: ' + node.type); } } var types = {}; if (config.node) { for (var name in config.node) { types[name] = config.node[name].generate; } } return function(node, options) { var buffer = ''; var handlers = { children: processChildren, node: processNode, chunk: function(chunk) { buffer += chunk; }, result: function() { return buffer; } }; if (options) { if (typeof options.decorator === 'function') { handlers = options.decorator(handlers); } if (options.sourceMap) { handlers = sourceMap(handlers); } } handlers.node(node); return handlers.result(); }; }; var create$3 = function createConvertors(walk) { return { fromPlainObject: function(ast) { walk(ast, { enter: function(node) { if (node.children && node.children instanceof List_1 === false) { node.children = new List_1().fromArray(node.children); } } }); return ast; }, toPlainObject: function(ast) { walk(ast, { leave: function(node) { if (node.children && node.children instanceof List_1) { node.children = node.children.toArray(); } } }); return ast; } }; }; var hasOwnProperty$4 = Object.prototype.hasOwnProperty; var noop$4 = function() {}; function ensureFunction$1(value) { return typeof value === 'function' ? value : noop$4; } function invokeForType(fn, type) { return function(node, item, list) { if (node.type === type) { fn.call(this, node, item, list); } }; } function getWalkersFromStructure(name, nodeType) { var structure = nodeType.structure; var walkers = []; for (var key in structure) { if (hasOwnProperty$4.call(structure, key) === false) { continue; } var fieldTypes = structure[key]; var walker = { name: key, type: false, nullable: false }; if (!Array.isArray(structure[key])) { fieldTypes = [structure[key]]; } for (var i = 0; i < fieldTypes.length; i++) { var fieldType = fieldTypes[i]; if (fieldType === null) { walker.nullable = true; } else if (typeof fieldType === 'string') { walker.type = 'node'; } else if (Array.isArray(fieldType)) { walker.type = 'list'; } } if (walker.type) { walkers.push(walker); } } if (walkers.length) { return { context: nodeType.walkContext, fields: walkers }; } return null; } function getTypesFromConfig(config) { var types = {}; for (var name in config.node) { if (hasOwnProperty$4.call(config.node, name)) { var nodeType = config.node[name]; if (!nodeType.structure) { throw new Error('Missed `structure` field in `' + name + '` node type definition'); } types[name] = getWalkersFromStructure(name, nodeType); } } return types; } function createTypeIterator(config, reverse) { var fields = config.fields.slice(); var contextName = config.context; var useContext = typeof contextName === 'string'; if (reverse) { fields.reverse(); } return function(node, context, walk) { var prevContextValue; if (useContext) { prevContextValue = context[contextName]; context[contextName] = node; } for (var i = 0; i < fields.length; i++) { var field = fields[i]; var ref = node[field.name]; if (!field.nullable || ref) { if (field.type === 'list') { if (reverse) { ref.forEachRight(walk); } else { ref.forEach(walk); } } else { walk(ref); } } } if (useContext) { context[contextName] = prevContextValue; } }; } function createFastTraveralMap(iterators) { return { Atrule: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block }, Rule: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block }, Declaration: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block, DeclarationList: iterators.DeclarationList } }; } var create$4 = function createWalker(config) { var types = getTypesFromConfig(config); var iteratorsNatural = {}; var iteratorsReverse = {}; for (var name in types) { if (hasOwnProperty$4.call(types, name) && types[name] !== null) { iteratorsNatural[name] = createTypeIterator(types[name], false); iteratorsReverse[name] = createTypeIterator(types[name], true); } } var fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural); var fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse); var walk = function(root, options) { function walkNode(node, item, list) { enter.call(context, node, item, list); if (iterators.hasOwnProperty(node.type)) { iterators[node.type](node, context, walkNode); } leave.call(context, node, item, list); } var enter = noop$4; var leave = noop$4; var iterators = iteratorsNatural; var context = { root: root, stylesheet: null, atrule: null, atrulePrelude: null, rule: null, selector: null, block: null, declaration: null, function: null }; if (typeof options === 'function') { enter = options; } else if (options) { enter = ensureFunction$1(options.enter); leave = ensureFunction$1(options.leave); if (options.reverse) { iterators = iteratorsReverse; } if (options.visit) { if (fastTraversalIteratorsNatural.hasOwnProperty(options.visit)) { iterators = options.reverse ? fastTraversalIteratorsReverse[options.visit] : fastTraversalIteratorsNatural[options.visit]; } else if (!types.hasOwnProperty(options.visit)) { throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).join(', ') + ')'); } enter = invokeForType(enter, options.visit); leave = invokeForType(leave, options.visit); } } if (enter === noop$4 && leave === noop$4) { throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function'); } // swap handlers in reverse mode to invert visit order if (options.reverse) { var tmp = enter; enter = leave; leave = tmp; } walkNode(root); }; walk.find = function(ast, fn) { var found = null; walk(ast, function(node, item, list) { if (found === null && fn.call(this, node, item, list)) { found = node; } }); return found; }; walk.findLast = function(ast, fn) { var found = null; walk(ast, { reverse: true, enter: function(node, item, list) { if (found === null && fn.call(this, node, item, list)) { found = node; } } }); return found; }; walk.findAll = function(ast, fn) { var found = []; walk(ast, function(node, item, list) { if (fn.call(this, node, item, list)) { found.push(node); } }); return found; }; return walk; }; var clone = function clone(node) { var result = {}; for (var key in node) { var value = node[key]; if (value) { if (Array.isArray(value) || value instanceof List_1) { value = value.map(clone); } else if (value.constructor === Object) { value = clone(value); } } result[key] = value; } return result; }; var hasOwnProperty$5 = Object.prototype.hasOwnProperty; var shape = { generic: true, types: {}, atrules: {}, properties: {}, parseContext: {}, scope: {}, atrule: ['parse'], pseudo: ['parse'], node: ['name', 'structure', 'parse', 'generate', 'walkContext'] }; function isObject(value) { return value && value.constructor === Object; } function copy(value) { if (isObject(value)) { return Object.assign({}, value); } else { return value; } } function extend(dest, src) { for (var key in src) { if (hasOwnProperty$5.call(src, key)) { if (isObject(dest[key])) { extend(dest[key], copy(src[key])); } else { dest[key] = copy(src[key]); } } } } function mix(dest, src, shape) { for (var key in shape) { if (hasOwnProperty$5.call(shape, key) === false) { continue; } if (shape[key] === true) { if (key in src) { if (hasOwnProperty$5.call(src, key)) { dest[key] = copy(src[key]); } } } else if (shape[key]) { if (isObject(shape[key])) { var res = {}; extend(res, dest[key]); extend(res, src[key]); dest[key] = res; } else if (Array.isArray(shape[key])) { var res = {}; var innerShape = shape[key].reduce(function(s, k) { s[k] = true; return s; }, {}); for (var name in dest[key]) { if (hasOwnProperty$5.call(dest[key], name)) { res[name] = {}; if (dest[key] && dest[key][name]) { mix(res[name], dest[key][name], innerShape); } } } for (var name in src[key]) { if (hasOwnProperty$5.call(src[key], name)) { if (!res[name]) { res[name] = {}; } if (src[key] && src[key][name]) { mix(res[name], src[key][name], innerShape); } } } dest[key] = res; } } } return dest; } var mix_1 = function(dest, src) { return mix(dest, src, shape); }; function createSyntax(config) { var parse = create$1(config); var walk = create$4(config); var generate = create$2(config); var convert = create$3(walk); var syntax = { List: List_1, SyntaxError: _SyntaxError, TokenStream: TokenStream_1, Lexer: Lexer_1, vendorPrefix: names.vendorPrefix, keyword: names.keyword, property: names.property, isCustomProperty: names.isCustomProperty, definitionSyntax: definitionSyntax, lexer: null, createLexer: function(config) { return new Lexer_1(config, syntax, syntax.lexer.structure); }, tokenize: tokenizer, parse: parse, walk: walk, generate: generate, find: walk.find, findLast: walk.findLast, findAll: walk.findAll, clone: clone, fromPlainObject: convert.fromPlainObject, toPlainObject: convert.toPlainObject, createSyntax: function(config) { return createSyntax(mix_1({}, config)); }, fork: function(extension) { var base = mix_1({}, config); // copy of config return createSyntax( typeof extension === 'function' ? extension(base, Object.assign) : mix_1(base, extension) ); } }; syntax.lexer = new Lexer_1({ generic: true, types: config.types, atrules: config.atrules, properties: config.properties, node: config.node }, syntax); return syntax; } var create_1 = function(config) { return createSyntax(mix_1({}, config)); }; var create$5 = { create: create_1 }; var atRules = { "@charset": { syntax: "@charset \"<charset>\";", groups: [ "CSS Charsets" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@charset" }, "@counter-style": { syntax: "@counter-style <counter-style-name> {\n [ system: <counter-system>; ] ||\n [ symbols: <counter-symbols>; ] ||\n [ additive-symbols: <additive-symbols>; ] ||\n [ negative: <negative-symbol>; ] ||\n [ prefix: <prefix>; ] ||\n [ suffix: <suffix>; ] ||\n [ range: <range>; ] ||\n [ pad: <padding>; ] ||\n [ speak-as: <speak-as>; ] ||\n [ fallback: <counter-style-name>; ]\n}", interfaces: [ "CSSCounterStyleRule" ], groups: [ "CSS Counter Styles" ], descriptors: { "additive-symbols": { syntax: "[ <integer> && <symbol> ]#", media: "all", initial: "N/A", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, fallback: { syntax: "<counter-style-name>", media: "all", initial: "decimal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, negative: { syntax: "<symbol> <symbol>?", media: "all", initial: "\"-\" hyphen-minus", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, pad: { syntax: "<integer> && <symbol>", media: "all", initial: "0 \"\"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, prefix: { syntax: "<symbol>", media: "all", initial: "\"\"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, range: { syntax: "[ [ <integer> | infinite ]{2} ]# | auto", media: "all", initial: "auto", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "speak-as": { syntax: "auto | bullets | numbers | words | spell-out | <counter-style-name>", media: "all", initial: "auto", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, suffix: { syntax: "<symbol>", media: "all", initial: "\". \"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, symbols: { syntax: "<symbol>+", media: "all", initial: "N/A", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, system: { syntax: "cyclic | numeric | alphabetic | symbolic | additive | [ fixed <integer>? ] | [ extends <counter-style-name> ]", media: "all", initial: "symbolic", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@counter-style" }, "@document": { syntax: "@document [ <url> | url-prefix(<string>) | domain(<string>) | media-document(<string>) | regexp(<string>) ]# {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule" ], groups: [ "CSS Conditional Rules" ], status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@document" }, "@font-face": { syntax: "@font-face {\n [ font-family: <family-name>; ] ||\n [ src: <src>; ] ||\n [ unicode-range: <unicode-range>; ] ||\n [ font-variant: <font-variant>; ] ||\n [ font-feature-settings: <font-feature-settings>; ] ||\n [ font-variation-settings: <font-variation-settings>; ] ||\n [ font-stretch: <font-stretch>; ] ||\n [ font-weight: <font-weight>; ] ||\n [ font-style: <font-style>; ]\n}", interfaces: [ "CSSFontFaceRule" ], groups: [ "CSS Fonts" ], descriptors: { "font-display": { syntax: "[ auto | block | swap | fallback | optional ]", media: "visual", percentages: "no", initial: "auto", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, "font-family": { syntax: "<family-name>", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-feature-settings": { syntax: "normal | <feature-tag-value>#", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "font-variation-settings": { syntax: "normal | [ <string> <number> ]#", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "font-stretch": { syntax: "<font-stretch-absolute>{1,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-style": { syntax: "normal | italic | oblique <angle>{0,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-weight": { syntax: "<font-weight-absolute>{1,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-variant": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> || stylistic(<feature-value-name>) || historical-forms || styleset(<feature-value-name>#) || character-variant(<feature-value-name>#) || swash(<feature-value-name>) || ornaments(<feature-value-name>) || annotation(<feature-value-name>) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero || <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, src: { syntax: "[ <url> [ format( <string># ) ]? | local( <family-name> ) ]#", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "unicode-range": { syntax: "<unicode-range>#", media: "all", initial: "U+0-10FFFF", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@font-face" }, "@font-feature-values": { syntax: "@font-feature-values <family-name># {\n <feature-value-block-list>\n}", interfaces: [ "CSSFontFeatureValuesRule" ], groups: [ "CSS Fonts" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@font-feature-values" }, "@import": { syntax: "@import [ <string> | <url> ] [ <media-query-list> ]?;", groups: [ "Media Queries" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@import" }, "@keyframes": { syntax: "@keyframes <keyframes-name> {\n <keyframe-block-list>\n}", interfaces: [ "CSSKeyframeRule", "CSSKeyframesRule" ], groups: [ "CSS Animations" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@keyframes" }, "@media": { syntax: "@media <media-query-list> {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule", "CSSMediaRule", "CSSCustomMediaRule" ], groups: [ "CSS Conditional Rules", "Media Queries" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@media" }, "@namespace": { syntax: "@namespace <namespace-prefix>? [ <string> | <url> ];", groups: [ "CSS Namespaces" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@namespace" }, "@page": { syntax: "@page <page-selector-list> {\n <page-body>\n}", interfaces: [ "CSSPageRule" ], groups: [ "CSS Pages" ], descriptors: { bleed: { syntax: "auto | <length>", media: [ "visual", "paged" ], initial: "auto", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, marks: { syntax: "none | [ crop || cross ]", media: [ "visual", "paged" ], initial: "none", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "experimental" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@page" }, "@supports": { syntax: "@supports <supports-condition> {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule", "CSSSupportsRule" ], groups: [ "CSS Conditional Rules" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@supports" }, "@viewport": { syntax: "@viewport {\n <group-rule-body>\n}", interfaces: [ "CSSViewportRule" ], groups: [ "CSS Device Adaptation" ], descriptors: { height: { syntax: "<viewport-length>{1,2}", media: [ "visual", "continuous" ], initial: [ "min-height", "max-height" ], percentages: [ "min-height", "max-height" ], computed: [ "min-height", "max-height" ], order: "orderOfAppearance", status: "standard" }, "max-height": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToHeightOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "max-width": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToWidthOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "max-zoom": { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" }, "min-height": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToHeightOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "min-width": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToWidthOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "min-zoom": { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" }, orientation: { syntax: "auto | portrait | landscape", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToSizeOfBoundingBox", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "user-zoom": { syntax: "zoom | fixed", media: [ "visual", "continuous" ], initial: "zoom", percentages: "referToSizeOfBoundingBox", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, width: { syntax: "<viewport-length>{1,2}", media: [ "visual", "continuous" ], initial: [ "min-width", "max-width" ], percentages: [ "min-width", "max-width" ], computed: [ "min-width", "max-width" ], order: "orderOfAppearance", status: "standard" }, zoom: { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@viewport" } }; var atRules$1 = /*#__PURE__*/Object.freeze({ __proto__: null, 'default': atRules }); var all = { syntax: "initial | inherit | unset | revert", media: "noPracticalMedia", inherited: false, animationType: "eachOfShorthandPropertiesExceptUnicodeBiDiAndDirection", percentages: "no", groups: [ "CSS Miscellaneous" ], initial: "noPracticalInitialValue", appliesto: "allElements", computed: "asSpecifiedAppliesToEachProperty", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/all" }; var animation = { syntax: "<single-animation>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-iteration-count", "animation-direction", "animation-fill-mode", "animation-play-state" ], appliesto: "allElementsAndPseudos", computed: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-direction", "animation-iteration-count", "animation-fill-mode", "animation-play-state" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation" }; var appearance = { syntax: "none | auto | button | textfield | <compat>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-appearance" }; var azimuth = { syntax: "<angle> | [ [ left-side | far-left | left | center-left | center | center-right | right | far-right | right-side ] || behind ] | leftwards | rightwards", media: "aural", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Speech" ], initial: "center", appliesto: "allElements", computed: "normalizedAngle", order: "orderOfAppearance", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/azimuth" }; var background = { syntax: "[ <bg-layer> , ]* <final-bg-layer>", media: "visual", inherited: false, animationType: [ "background-color", "background-image", "background-clip", "background-position", "background-size", "background-repeat", "background-attachment" ], percentages: [ "background-position", "background-size" ], groups: [ "CSS Backgrounds and Borders" ], initial: [ "background-image", "background-position", "background-size", "background-repeat", "background-origin", "background-clip", "background-attachment", "background-color" ], appliesto: "allElements", computed: [ "background-image", "background-position", "background-size", "background-repeat", "background-origin", "background-clip", "background-attachment", "background-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background" }; var border = { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-color", "border-style", "border-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-width", "border-style", "border-color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border" }; var bottom = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToContainingBlockHeight", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/bottom" }; var clear = { syntax: "none | left | right | both | inline-start | inline-end", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "none", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clear" }; var clip = { syntax: "<shape> | auto", media: "visual", inherited: false, animationType: "rectangle", percentages: "no", groups: [ "CSS Masking" ], initial: "auto", appliesto: "absolutelyPositionedElements", computed: "autoOrRectangle", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clip" }; var color = { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Color" ], initial: "variesFromBrowserToBrowser", appliesto: "allElements", computed: "translucentValuesRGBAOtherwiseRGB", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/color" }; var columns = { syntax: "<'column-width'> || <'column-count'>", media: "visual", inherited: false, animationType: [ "column-width", "column-count" ], percentages: "no", groups: [ "CSS Columns" ], initial: [ "column-width", "column-count" ], appliesto: "blockContainersExceptTableWrappers", computed: [ "column-width", "column-count" ], order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/columns" }; var contain = { syntax: "none | strict | content | [ size || layout || style || paint ]", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Containment" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/contain" }; var content = { syntax: "normal | none | [ <content-replacement> | <content-list> ] [/ <string> ]?", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Generated Content" ], initial: "normal", appliesto: "beforeAndAfterPseudos", computed: "normalOnElementsForPseudosNoneAbsoluteURIStringOrAsSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/content" }; var cursor = { syntax: "[ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing ] ]", media: [ "visual", "interactive" ], inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/cursor" }; var direction = { syntax: "ltr | rtl", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "ltr", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/direction" }; var display = { syntax: "[ <display-outside> || <display-inside> ] | <display-listitem> | <display-internal> | <display-box> | <display-legacy>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Display" ], initial: "inline", appliesto: "allElements", computed: "asSpecifiedExceptPositionedFloatingAndRootElementsKeywordMaybeDifferent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/display" }; var filter = { syntax: "none | <filter-function-list>", media: "visual", inherited: false, animationType: "filterList", percentages: "no", groups: [ "Filter Effects" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/filter" }; var flex = { syntax: "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]", media: "visual", inherited: false, animationType: [ "flex-grow", "flex-shrink", "flex-basis" ], percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: [ "flex-grow", "flex-shrink", "flex-basis" ], appliesto: "flexItemsAndInFlowPseudos", computed: [ "flex-grow", "flex-shrink", "flex-basis" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex" }; var float = { syntax: "left | right | none | inline-start | inline-end", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "none", appliesto: "allElementsNoEffectIfDisplayNone", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/float" }; var font = { syntax: "[ [ <'font-style'> || <font-variant-css21> || <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar", media: "visual", inherited: true, animationType: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], percentages: [ "font-size", "line-height" ], groups: [ "CSS Fonts" ], initial: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], appliesto: "allElements", computed: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font" }; var gap = { syntax: "<'row-gap'> <'column-gap'>?", media: "visual", inherited: false, animationType: [ "row-gap", "column-gap" ], percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "row-gap", "column-gap" ], appliesto: "gridContainers", computed: [ "row-gap", "column-gap" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/gap" }; var grid = { syntax: "<'grid-template'> | <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? | [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>", media: "visual", inherited: false, animationType: "discrete", percentages: [ "grid-template-rows", "grid-template-columns", "grid-auto-rows", "grid-auto-columns" ], groups: [ "CSS Grid Layout" ], initial: [ "grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-rows", "grid-auto-columns", "grid-auto-flow", "grid-column-gap", "grid-row-gap", "column-gap", "row-gap" ], appliesto: "gridContainers", computed: [ "grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-rows", "grid-auto-columns", "grid-auto-flow", "grid-column-gap", "grid-row-gap", "column-gap", "row-gap" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid" }; var height = { syntax: "[ <length> | <percentage> ] && [ border-box | content-box ]? | available | min-content | max-content | fit-content | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentagesRelativeToContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAutoOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/height" }; var hyphens = { syntax: "none | manual | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "manual", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/hyphens" }; var inset = { syntax: "<'top'>{1,4}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset" }; var isolation = { syntax: "auto | isolate", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "auto", appliesto: "allElementsSVGContainerGraphicsAndGraphicsReferencingElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/isolation" }; var left = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/left" }; var margin = { syntax: "[ <length> | <percentage> | auto ]{1,4}", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: [ "margin-bottom", "margin-left", "margin-right", "margin-top" ], appliesto: "allElementsExceptTableDisplayTypes", computed: [ "margin-bottom", "margin-left", "margin-right", "margin-top" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin" }; var mask = { syntax: "<mask-layer>#", media: "visual", inherited: false, animationType: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], percentages: [ "mask-position" ], groups: [ "CSS Masking" ], initial: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], appliesto: "allElementsSVGContainerElements", computed: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask" }; var offset = { syntax: "[ <'offset-position'>? [ <'offset-path'> [ <'offset-distance'> || <'offset-rotate'> ]? ]? ]! [ / <'offset-anchor'> ]?", media: "visual", inherited: false, animationType: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], percentages: [ "offset-position", "offset-distance", "offset-anchor" ], groups: [ "CSS Motion Path" ], initial: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], appliesto: "transformableElements", computed: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], order: "perGrammar", stacking: true, status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset" }; var opacity = { syntax: "<alpha-value>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Color" ], initial: "1.0", appliesto: "allElements", computed: "specifiedValueClipped0To1", order: "uniqueOrder", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/opacity" }; var order = { syntax: "<integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "0", appliesto: "flexItemsAndAbsolutelyPositionedFlexContainerChildren", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/order" }; var orphans = { syntax: "<integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "2", appliesto: "blockContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/orphans" }; var outline = { syntax: "[ <'outline-color'> || <'outline-style'> || <'outline-width'> ]", media: [ "visual", "interactive" ], inherited: false, animationType: [ "outline-color", "outline-width", "outline-style" ], percentages: "no", groups: [ "CSS Basic User Interface" ], initial: [ "outline-color", "outline-style", "outline-width" ], appliesto: "allElements", computed: [ "outline-color", "outline-width", "outline-style" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline" }; var overflow = { syntax: "[ visible | hidden | clip | scroll | auto ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow" }; var padding = { syntax: "[ <length> | <percentage> ]{1,4}", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: [ "padding-bottom", "padding-left", "padding-right", "padding-top" ], appliesto: "allElementsExceptInternalTableDisplayTypes", computed: [ "padding-bottom", "padding-left", "padding-right", "padding-top" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding" }; var perspective = { syntax: "none | <length>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "absoluteLengthOrNone", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/perspective" }; var position = { syntax: "static | relative | absolute | sticky | fixed", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "static", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/position" }; var quotes = { syntax: "none | auto | [ <string> <string> ]+", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Generated Content" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/quotes" }; var resize = { syntax: "none | both | horizontal | vertical | block | inline", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "none", appliesto: "elementsWithOverflowNotVisibleAndReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/resize" }; var right = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/right" }; var rotate = { syntax: "none | <angle> | [ x | y | z | <number>{3} ] && <angle>", media: "visual", inherited: false, animationType: "transform", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/rotate" }; var scale = { syntax: "none | <number>{1,3}", media: "visual", inherited: false, animationType: "transform", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scale" }; var top = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToContainingBlockHeight", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/top" }; var transform = { syntax: "none | <transform-list>", media: "visual", inherited: false, animationType: "transform", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform" }; var transition = { syntax: "<single-transition>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: [ "transition-delay", "transition-duration", "transition-property", "transition-timing-function" ], appliesto: "allElementsAndPseudos", computed: [ "transition-delay", "transition-duration", "transition-property", "transition-timing-function" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition" }; var translate = { syntax: "none | <length-percentage> [ <length-percentage> <length>? ]?", media: "visual", inherited: false, animationType: "transform", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/translate" }; var visibility = { syntax: "visible | hidden | collapse", media: "visual", inherited: true, animationType: "visibility", percentages: "no", groups: [ "CSS Box Model" ], initial: "visible", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/visibility" }; var widows = { syntax: "<integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "2", appliesto: "blockContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/widows" }; var width = { syntax: "[ <length> | <percentage> ] && [ border-box | content-box ]? | available | min-content | max-content | fit-content | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAutoOrAbsoluteLength", order: "lengthOrPercentageBeforeKeywordIfBothPresent", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/width" }; var zoom = { syntax: "normal | reset | <number> | <percentage>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/zoom" }; var properties$1 = { "--*": { syntax: "<declaration-value>", media: "all", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Variables" ], initial: "seeProse", appliesto: "allElements", computed: "asSpecifiedWithVarsSubstituted", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/--*" }, "-ms-accelerator": { syntax: "false | true", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "false", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-accelerator" }, "-ms-block-progression": { syntax: "tb | rl | bt | lr", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "tb", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-block-progression" }, "-ms-content-zoom-chaining": { syntax: "none | chained", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-chaining" }, "-ms-content-zooming": { syntax: "none | zoom", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "zoomForTheTopLevelNoneForTheRest", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zooming" }, "-ms-content-zoom-limit": { syntax: "<'-ms-content-zoom-limit-min'> <'-ms-content-zoom-limit-max'>", media: "interactive", inherited: false, animationType: "discrete", percentages: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], groups: [ "Microsoft Extensions" ], initial: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit" }, "-ms-content-zoom-limit-max": { syntax: "<percentage>", media: "interactive", inherited: false, animationType: "discrete", percentages: "maxZoomFactor", groups: [ "Microsoft Extensions" ], initial: "400%", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit-max" }, "-ms-content-zoom-limit-min": { syntax: "<percentage>", media: "interactive", inherited: false, animationType: "discrete", percentages: "minZoomFactor", groups: [ "Microsoft Extensions" ], initial: "100%", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit-min" }, "-ms-content-zoom-snap": { syntax: "<'-ms-content-zoom-snap-type'> || <'-ms-content-zoom-snap-points'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-content-zoom-snap-type", "-ms-content-zoom-snap-points" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-content-zoom-snap-type", "-ms-content-zoom-snap-points" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap" }, "-ms-content-zoom-snap-points": { syntax: "snapInterval( <percentage>, <percentage> ) | snapList( <percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0%, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap-points" }, "-ms-content-zoom-snap-type": { syntax: "none | proximity | mandatory", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap-type" }, "-ms-filter": { syntax: "<string>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "\"\"", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-filter" }, "-ms-flow-from": { syntax: "[ none | <custom-ident> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-flow-from" }, "-ms-flow-into": { syntax: "[ none | <custom-ident> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "iframeElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-flow-into" }, "-ms-high-contrast-adjust": { syntax: "auto | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-high-contrast-adjust" }, "-ms-hyphenate-limit-chars": { syntax: "auto | <integer>{1,3}", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-chars" }, "-ms-hyphenate-limit-lines": { syntax: "no-limit | <integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "no-limit", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-lines" }, "-ms-hyphenate-limit-zone": { syntax: "<percentage> | <length>", media: "visual", inherited: true, animationType: "discrete", percentages: "referToLineBoxWidth", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-zone" }, "-ms-ime-align": { syntax: "auto | after", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-ime-align" }, "-ms-overflow-style": { syntax: "auto | none | scrollbar | -ms-autohiding-scrollbar", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-overflow-style" }, "-ms-scrollbar-3dlight-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-3dlight-color" }, "-ms-scrollbar-arrow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ButtonText", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-arrow-color" }, "-ms-scrollbar-base-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-base-color" }, "-ms-scrollbar-darkshadow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDDarkShadow", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-darkshadow-color" }, "-ms-scrollbar-face-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDFace", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-face-color" }, "-ms-scrollbar-highlight-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDHighlight", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-highlight-color" }, "-ms-scrollbar-shadow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDDarkShadow", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-shadow-color" }, "-ms-scrollbar-track-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "Scrollbar", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-track-color" }, "-ms-scroll-chaining": { syntax: "chained | none", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "chained", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-chaining" }, "-ms-scroll-limit": { syntax: "<'-ms-scroll-limit-x-min'> <'-ms-scroll-limit-y-min'> <'-ms-scroll-limit-x-max'> <'-ms-scroll-limit-y-max'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-limit-x-min", "-ms-scroll-limit-y-min", "-ms-scroll-limit-x-max", "-ms-scroll-limit-y-max" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-limit-x-min", "-ms-scroll-limit-y-min", "-ms-scroll-limit-x-max", "-ms-scroll-limit-y-max" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit" }, "-ms-scroll-limit-x-max": { syntax: "auto | <length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-x-max" }, "-ms-scroll-limit-x-min": { syntax: "<length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-x-min" }, "-ms-scroll-limit-y-max": { syntax: "auto | <length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-y-max" }, "-ms-scroll-limit-y-min": { syntax: "<length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-y-min" }, "-ms-scroll-rails": { syntax: "none | railed", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "railed", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-rails" }, "-ms-scroll-snap-points-x": { syntax: "snapInterval( <length-percentage>, <length-percentage> ) | snapList( <length-percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0px, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-points-x" }, "-ms-scroll-snap-points-y": { syntax: "snapInterval( <length-percentage>, <length-percentage> ) | snapList( <length-percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0px, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-points-y" }, "-ms-scroll-snap-type": { syntax: "none | proximity | mandatory", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-type" }, "-ms-scroll-snap-x": { syntax: "<'-ms-scroll-snap-type'> <'-ms-scroll-snap-points-x'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-x" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-x" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-x" }, "-ms-scroll-snap-y": { syntax: "<'-ms-scroll-snap-type'> <'-ms-scroll-snap-points-y'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-y" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-y" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-y" }, "-ms-scroll-translation": { syntax: "none | vertical-to-horizontal", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-translation" }, "-ms-text-autospace": { syntax: "none | ideograph-alpha | ideograph-numeric | ideograph-parenthesis | ideograph-space", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-text-autospace" }, "-ms-touch-select": { syntax: "grippers | none", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "grippers", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-touch-select" }, "-ms-user-select": { syntax: "none | element | text", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "text", appliesto: "nonReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-user-select" }, "-ms-wrap-flow": { syntax: "auto | both | start | end | maximum | clear", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-flow" }, "-ms-wrap-margin": { syntax: "<length>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "exclusionElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-margin" }, "-ms-wrap-through": { syntax: "wrap | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "wrap", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-through" }, "-moz-appearance": { syntax: "none | button | button-arrow-down | button-arrow-next | button-arrow-previous | button-arrow-up | button-bevel | button-focus | caret | checkbox | checkbox-container | checkbox-label | checkmenuitem | dualbutton | groupbox | listbox | listitem | menuarrow | menubar | menucheckbox | menuimage | menuitem | menuitemtext | menulist | menulist-button | menulist-text | menulist-textfield | menupopup | menuradio | menuseparator | meterbar | meterchunk | progressbar | progressbar-vertical | progresschunk | progresschunk-vertical | radio | radio-container | radio-label | radiomenuitem | range | range-thumb | resizer | resizerpanel | scale-horizontal | scalethumbend | scalethumb-horizontal | scalethumbstart | scalethumbtick | scalethumb-vertical | scale-vertical | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical | searchfield | separator | sheet | spinner | spinner-downbutton | spinner-textfield | spinner-upbutton | splitter | statusbar | statusbarpanel | tab | tabpanel | tabpanels | tab-scroll-arrow-back | tab-scroll-arrow-forward | textfield | textfield-multiline | toolbar | toolbarbutton | toolbarbutton-dropdown | toolbargripper | toolbox | tooltip | treeheader | treeheadercell | treeheadersortarrow | treeitem | treeline | treetwisty | treetwistyopen | treeview | -moz-mac-unified-toolbar | -moz-win-borderless-glass | -moz-win-browsertabbar-toolbox | -moz-win-communicationstext | -moz-win-communications-toolbox | -moz-win-exclude-glass | -moz-win-glass | -moz-win-mediatext | -moz-win-media-toolbox | -moz-window-button-box | -moz-window-button-box-maximized | -moz-window-button-close | -moz-window-button-maximize | -moz-window-button-minimize | -moz-window-button-restore | -moz-window-frame-bottom | -moz-window-frame-left | -moz-window-frame-right | -moz-window-titlebar | -moz-window-titlebar-maximized", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "noneButOverriddenInUserAgentCSS", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-appearance" }, "-moz-binding": { syntax: "<url> | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElementsExceptGeneratedContentOrPseudoElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-binding" }, "-moz-border-bottom-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-bottom-colors" }, "-moz-border-left-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-left-colors" }, "-moz-border-right-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-right-colors" }, "-moz-border-top-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-top-colors" }, "-moz-context-properties": { syntax: "none | [ fill | fill-opacity | stroke | stroke-opacity ]#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElementsThatCanReferenceImages", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-context-properties" }, "-moz-float-edge": { syntax: "border-box | content-box | margin-box | padding-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "content-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-float-edge" }, "-moz-force-broken-image-icon": { syntax: "<integer>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "images", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-force-broken-image-icon" }, "-moz-image-region": { syntax: "<shape> | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "auto", appliesto: "xulImageElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-image-region" }, "-moz-orient": { syntax: "inline | block | horizontal | vertical", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "inline", appliesto: "anyElementEffectOnProgressAndMeter", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-orient" }, "-moz-outline-radius": { syntax: "<outline-radius>{1,4} [ / <outline-radius>{1,4} ]?", media: "visual", inherited: false, animationType: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], percentages: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], groups: [ "Mozilla Extensions" ], initial: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], appliesto: "allElements", computed: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius" }, "-moz-outline-radius-bottomleft": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-bottomleft" }, "-moz-outline-radius-bottomright": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-bottomright" }, "-moz-outline-radius-topleft": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-topleft" }, "-moz-outline-radius-topright": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-topright" }, "-moz-stack-sizing": { syntax: "ignore | stretch-to-fit", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "stretch-to-fit", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-stack-sizing" }, "-moz-text-blink": { syntax: "none | blink", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-text-blink" }, "-moz-user-focus": { syntax: "ignore | normal | select-after | select-before | select-menu | select-same | select-all | none", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-focus" }, "-moz-user-input": { syntax: "auto | none | enabled | disabled", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input" }, "-moz-user-modify": { syntax: "read-only | read-write | write-only", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "read-only", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-modify" }, "-moz-window-dragging": { syntax: "drag | no-drag", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "drag", appliesto: "allElementsCreatingNativeWindows", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-window-dragging" }, "-moz-window-shadow": { syntax: "default | menu | tooltip | sheet | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "default", appliesto: "allElementsCreatingNativeWindows", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-window-shadow" }, "-webkit-appearance": { syntax: "none | button | button-bevel | caret | checkbox | default-button | inner-spin-button | listbox | listitem | media-controls-background | media-controls-fullscreen-background | media-current-time-display | media-enter-fullscreen-button | media-exit-fullscreen-button | media-fullscreen-button | media-mute-button | media-overlay-play-button | media-play-button | media-seek-back-button | media-seek-forward-button | media-slider | media-sliderthumb | media-time-remaining-display | media-toggle-closed-captions-button | media-volume-slider | media-volume-slider-container | media-volume-sliderthumb | menulist | menulist-button | menulist-text | menulist-textfield | meter | progress-bar | progress-bar-value | push-button | radio | searchfield | searchfield-cancel-button | searchfield-decoration | searchfield-results-button | searchfield-results-decoration | slider-horizontal | slider-vertical | sliderthumb-horizontal | sliderthumb-vertical | square-button | textarea | textfield", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "noneButOverriddenInUserAgentCSS", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-appearance" }, "-webkit-border-before": { syntax: "<'border-width'> || <'border-style'> || <'color'>", media: "visual", inherited: true, animationType: "discrete", percentages: [ "-webkit-border-before-width" ], groups: [ "WebKit Extensions" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "color" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-border-before" }, "-webkit-border-before-color": { syntax: "<'color'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard" }, "-webkit-border-before-style": { syntax: "<'border-style'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard" }, "-webkit-border-before-width": { syntax: "<'border-width'>", media: "visual", inherited: true, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "WebKit Extensions" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "nonstandard" }, "-webkit-box-reflect": { syntax: "[ above | below | right | left ]? <length>? <image>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-box-reflect" }, "-webkit-line-clamp": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "WebKit Extensions", "CSS Overflow" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-line-clamp" }, "-webkit-mask": { syntax: "[ <mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> || [ <box> | border | padding | content | text ] || [ <box> | border | padding | content ] ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: [ "-webkit-mask-image", "-webkit-mask-repeat", "-webkit-mask-attachment", "-webkit-mask-position", "-webkit-mask-origin", "-webkit-mask-clip" ], appliesto: "allElements", computed: [ "-webkit-mask-image", "-webkit-mask-repeat", "-webkit-mask-attachment", "-webkit-mask-position", "-webkit-mask-origin", "-webkit-mask-clip" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask" }, "-webkit-mask-attachment": { syntax: "<attachment>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "scroll", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-attachment" }, "-webkit-mask-clip": { syntax: "[ <box> | border | padding | content | text ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "border", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-clip" }, "-webkit-mask-composite": { syntax: "<composite-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "source-over", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-composite" }, "-webkit-mask-image": { syntax: "<mask-reference>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "absoluteURIOrNone", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-image" }, "-webkit-mask-origin": { syntax: "[ <box> | border | padding | content ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "padding", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-origin" }, "-webkit-mask-position": { syntax: "<position>#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0% 0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-position" }, "-webkit-mask-position-x": { syntax: "[ <length-percentage> | left | center | right ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-position-x" }, "-webkit-mask-position-y": { syntax: "[ <length-percentage> | top | center | bottom ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-position-y" }, "-webkit-mask-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-repeat" }, "-webkit-mask-repeat-x": { syntax: "repeat | no-repeat | space | round", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-repeat-x" }, "-webkit-mask-repeat-y": { syntax: "repeat | no-repeat | space | round", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-repeat-y" }, "-webkit-mask-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "discrete", percentages: "relativeToBackgroundPositioningArea", groups: [ "WebKit Extensions" ], initial: "auto auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-size" }, "-webkit-overflow-scrolling": { syntax: "auto | touch", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-overflow-scrolling" }, "-webkit-tap-highlight-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "black", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-tap-highlight-color" }, "-webkit-text-fill-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-fill-color" }, "-webkit-text-stroke": { syntax: "<length> || <color>", media: "visual", inherited: true, animationType: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], percentages: "no", groups: [ "WebKit Extensions" ], initial: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], appliesto: "allElements", computed: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], order: "canonicalOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke" }, "-webkit-text-stroke-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke-color" }, "-webkit-text-stroke-width": { syntax: "<length>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "0", appliesto: "allElements", computed: "absoluteLength", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke-width" }, "-webkit-touch-callout": { syntax: "default | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "default", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-touch-callout" }, "-webkit-user-modify": { syntax: "read-only | read-write | read-write-plaintext-only", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "read-only", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard" }, "align-content": { syntax: "normal | <baseline-position> | <content-distribution> | <overflow-position>? <content-position>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multilineFlexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-content" }, "align-items": { syntax: "normal | stretch | <baseline-position> | [ <overflow-position>? <self-position> ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-items" }, "align-self": { syntax: "auto | normal | stretch | <baseline-position> | <overflow-position>? <self-position>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "auto", appliesto: "flexItemsGridItemsAndAbsolutelyPositionedBoxes", computed: "autoOnAbsolutelyPositionedElementsValueOfAlignItemsOnParent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-self" }, all: all, animation: animation, "animation-delay": { syntax: "<time>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-delay" }, "animation-direction": { syntax: "<single-animation-direction>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "normal", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-direction" }, "animation-duration": { syntax: "<time>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-duration" }, "animation-fill-mode": { syntax: "<single-animation-fill-mode>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "none", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-fill-mode" }, "animation-iteration-count": { syntax: "<single-animation-iteration-count>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "1", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-iteration-count" }, "animation-name": { syntax: "[ none | <keyframes-name> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "none", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-name" }, "animation-play-state": { syntax: "<single-animation-play-state>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "running", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-play-state" }, "animation-timing-function": { syntax: "<timing-function>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "ease", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-timing-function" }, appearance: appearance, "aspect-ratio": { syntax: "auto | <ratio>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElementsExceptInlineBoxesAndInternalRubyOrTableBoxes", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/aspect-ratio" }, azimuth: azimuth, "backdrop-filter": { syntax: "none | <filter-function-list>", media: "visual", inherited: false, animationType: "filterList", percentages: "no", groups: [ "Filter Effects" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/backdrop-filter" }, "backface-visibility": { syntax: "visible | hidden", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "visible", appliesto: "transformableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/backface-visibility" }, background: background, "background-attachment": { syntax: "<attachment>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "scroll", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-attachment" }, "background-blend-mode": { syntax: "<blend-mode>#", media: "none", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "normal", appliesto: "allElementsSVGContainerGraphicsAndGraphicsReferencingElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-blend-mode" }, "background-clip": { syntax: "<box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "border-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-clip" }, "background-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "transparent", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-color" }, "background-image": { syntax: "<bg-image>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-image" }, "background-origin": { syntax: "<box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "padding-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-origin" }, "background-position": { syntax: "<bg-position>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToSizeOfBackgroundPositioningAreaMinusBackgroundImageSize", groups: [ "CSS Backgrounds and Borders" ], initial: "0% 0%", appliesto: "allElements", computed: "listEachItemTwoKeywordsOriginOffsets", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position" }, "background-position-x": { syntax: "[ center | [ left | right | x-start | x-end ]? <length-percentage>? ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToWidthOfBackgroundPositioningAreaMinusBackgroundImageHeight", groups: [ "CSS Backgrounds and Borders" ], initial: "left", appliesto: "allElements", computed: "listEachItemConsistingOfAbsoluteLengthPercentageAndOrigin", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position-x" }, "background-position-y": { syntax: "[ center | [ top | bottom | y-start | y-end ]? <length-percentage>? ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToHeightOfBackgroundPositioningAreaMinusBackgroundImageHeight", groups: [ "CSS Backgrounds and Borders" ], initial: "top", appliesto: "allElements", computed: "listEachItemConsistingOfAbsoluteLengthPercentageAndOrigin", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position-y" }, "background-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "repeat", appliesto: "allElements", computed: "listEachItemHasTwoKeywordsOnePerDimension", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-repeat" }, "background-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "relativeToBackgroundPositioningArea", groups: [ "CSS Backgrounds and Borders" ], initial: "auto auto", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-size" }, "block-overflow": { syntax: "clip | ellipsis | <string>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "clip", appliesto: "blockContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "block-size": { syntax: "<'width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "sameAsWidthAndHeight", computed: "sameAsWidthAndHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/block-size" }, border: border, "border-block": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block" }, "border-block-color": { syntax: "<'border-top-color'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-color" }, "border-block-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-style" }, "border-block-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-width" }, "border-block-end": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end" }, "border-block-end-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-color" }, "border-block-end-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-style" }, "border-block-end-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-width" }, "border-block-start": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-block-start-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start" }, "border-block-start-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-color" }, "border-block-start-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-style" }, "border-block-start-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-width" }, "border-bottom": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-bottom-color", "border-bottom-style", "border-bottom-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-bottom-width", "border-bottom-style", "border-bottom-color" ], appliesto: "allElements", computed: [ "border-bottom-width", "border-bottom-style", "border-bottom-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom" }, "border-bottom-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-color" }, "border-bottom-left-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-left-radius" }, "border-bottom-right-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-right-radius" }, "border-bottom-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-style" }, "border-bottom-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderBottomStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-width" }, "border-collapse": { syntax: "collapse | separate", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "separate", appliesto: "tableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-collapse" }, "border-color": { syntax: "<color>{1,4}", media: "visual", inherited: false, animationType: [ "border-bottom-color", "border-left-color", "border-right-color", "border-top-color" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-color", "border-right-color", "border-bottom-color", "border-left-color" ], appliesto: "allElements", computed: [ "border-bottom-color", "border-left-color", "border-right-color", "border-top-color" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-color" }, "border-end-end-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-end-end-radius" }, "border-end-start-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-end-start-radius" }, "border-image": { syntax: "<'border-image-source'> || <'border-image-slice'> [ / <'border-image-width'> | / <'border-image-width'>? / <'border-image-outset'> ]? || <'border-image-repeat'>", media: "visual", inherited: false, animationType: "discrete", percentages: [ "border-image-slice", "border-image-width" ], groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-image-source", "border-image-slice", "border-image-width", "border-image-outset", "border-image-repeat" ], appliesto: "allElementsExceptTableElementsWhenCollapse", computed: [ "border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source", "border-image-width" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image" }, "border-image-outset": { syntax: "[ <length> | <number> ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-outset" }, "border-image-repeat": { syntax: "[ stretch | repeat | round | space ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "stretch", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-repeat" }, "border-image-slice": { syntax: "<number-percentage>{1,4} && fill?", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "referToSizeOfBorderImage", groups: [ "CSS Backgrounds and Borders" ], initial: "100%", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "oneToFourPercentagesOrAbsoluteLengthsPlusFill", order: "percentagesOrLengthsFollowedByFill", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-slice" }, "border-image-source": { syntax: "none | <image>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "noneOrImageWithAbsoluteURI", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-source" }, "border-image-width": { syntax: "[ <length-percentage> | <number> | auto ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "referToWidthOrHeightOfBorderImageArea", groups: [ "CSS Backgrounds and Borders" ], initial: "1", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-width" }, "border-inline": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline" }, "border-inline-end": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-inline-end-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end" }, "border-inline-color": { syntax: "<'border-top-color'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-color" }, "border-inline-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-style" }, "border-inline-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-width" }, "border-inline-end-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-color" }, "border-inline-end-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-style" }, "border-inline-end-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-width" }, "border-inline-start": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-inline-start-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start" }, "border-inline-start-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-color" }, "border-inline-start-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-style" }, "border-inline-start-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-width" }, "border-left": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-left-color", "border-left-style", "border-left-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-left-width", "border-left-style", "border-left-color" ], appliesto: "allElements", computed: [ "border-left-width", "border-left-style", "border-left-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left" }, "border-left-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-color" }, "border-left-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-style" }, "border-left-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderLeftStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-width" }, "border-radius": { syntax: "<length-percentage>{1,4} [ / <length-percentage>{1,4} ]?", media: "visual", inherited: false, animationType: [ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius" ], percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius" ], appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: [ "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-radius" }, "border-right": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-right-color", "border-right-style", "border-right-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-right-width", "border-right-style", "border-right-color" ], appliesto: "allElements", computed: [ "border-right-width", "border-right-style", "border-right-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right" }, "border-right-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-color" }, "border-right-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-style" }, "border-right-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderRightStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-width" }, "border-spacing": { syntax: "<length> <length>?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "0", appliesto: "tableElements", computed: "twoAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-spacing" }, "border-start-end-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-start-end-radius" }, "border-start-start-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-start-start-radius" }, "border-style": { syntax: "<line-style>{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-style", "border-right-style", "border-bottom-style", "border-left-style" ], appliesto: "allElements", computed: [ "border-bottom-style", "border-left-style", "border-right-style", "border-top-style" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-style" }, "border-top": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-top-color", "border-top-style", "border-top-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top" }, "border-top-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-color" }, "border-top-left-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-left-radius" }, "border-top-right-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-right-radius" }, "border-top-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-style" }, "border-top-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderTopStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-width" }, "border-width": { syntax: "<line-width>{1,4}", media: "visual", inherited: false, animationType: [ "border-bottom-width", "border-left-width", "border-right-width", "border-top-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-width", "border-right-width", "border-bottom-width", "border-left-width" ], appliesto: "allElements", computed: [ "border-bottom-width", "border-left-width", "border-right-width", "border-top-width" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-width" }, bottom: bottom, "box-align": { syntax: "start | center | end | baseline | stretch", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "stretch", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-align" }, "box-decoration-break": { syntax: "slice | clone", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "slice", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-decoration-break" }, "box-direction": { syntax: "normal | reverse | inherit", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "normal", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-direction" }, "box-flex": { syntax: "<number>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "0", appliesto: "directChildrenOfElementsWithDisplayMozBoxMozInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-flex" }, "box-flex-group": { syntax: "<integer>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "1", appliesto: "inFlowChildrenOfBoxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-flex-group" }, "box-lines": { syntax: "single | multiple", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "single", appliesto: "boxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-lines" }, "box-ordinal-group": { syntax: "<integer>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "1", appliesto: "childrenOfBoxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-ordinal-group" }, "box-orient": { syntax: "horizontal | vertical | inline-axis | block-axis | inherit", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "inlineAxisHorizontalInXUL", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-orient" }, "box-pack": { syntax: "start | center | end | justify", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "start", appliesto: "elementsWithDisplayMozBoxMozInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-pack" }, "box-shadow": { syntax: "none | <shadow>#", media: "visual", inherited: false, animationType: "shadowList", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "absoluteLengthsSpecifiedColorAsSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-shadow" }, "box-sizing": { syntax: "content-box | border-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "content-box", appliesto: "allElementsAcceptingWidthOrHeight", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-sizing" }, "break-after": { syntax: "auto | avoid | always | all | avoid-page | page | left | right | recto | verso | avoid-column | column | avoid-region | region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-after" }, "break-before": { syntax: "auto | avoid | always | all | avoid-page | page | left | right | recto | verso | avoid-column | column | avoid-region | region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-before" }, "break-inside": { syntax: "auto | avoid | avoid-page | avoid-column | avoid-region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-inside" }, "caption-side": { syntax: "top | bottom | block-start | block-end | inline-start | inline-end", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "top", appliesto: "tableCaptionElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/caption-side" }, "caret-color": { syntax: "auto | <color>", media: "interactive", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asAutoOrColor", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/caret-color" }, clear: clear, clip: clip, "clip-path": { syntax: "<clip-source> | [ <basic-shape> || <geometry-box> ] | none", media: "visual", inherited: false, animationType: "basicShapeOtherwiseNo", percentages: "referToReferenceBoxWhenSpecifiedOtherwiseBorderBox", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clip-path" }, color: color, "color-adjust": { syntax: "economy | exact", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Color" ], initial: "economy", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/color-adjust" }, "column-count": { syntax: "<integer> | auto", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Columns" ], initial: "auto", appliesto: "blockContainersExceptTableWrappers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-count" }, "column-fill": { syntax: "auto | balance | balance-all", media: "visualInContinuousMediaNoEffectInOverflowColumns", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "balance", appliesto: "multicolElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-fill" }, "column-gap": { syntax: "normal | <length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multiColumnElementsFlexContainersGridContainers", computed: "asSpecifiedWithLengthsAbsoluteAndNormalComputingToZeroExceptMultiColumn", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-gap" }, "column-rule": { syntax: "<'column-rule-width'> || <'column-rule-style'> || <'column-rule-color'>", media: "visual", inherited: false, animationType: [ "column-rule-color", "column-rule-style", "column-rule-width" ], percentages: "no", groups: [ "CSS Columns" ], initial: [ "column-rule-width", "column-rule-style", "column-rule-color" ], appliesto: "multicolElements", computed: [ "column-rule-color", "column-rule-style", "column-rule-width" ], order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule" }, "column-rule-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Columns" ], initial: "currentcolor", appliesto: "multicolElements", computed: "computedColor", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-color" }, "column-rule-style": { syntax: "<'border-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "none", appliesto: "multicolElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-style" }, "column-rule-width": { syntax: "<'border-width'>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Columns" ], initial: "medium", appliesto: "multicolElements", computed: "absoluteLength0IfColumnRuleStyleNoneOrHidden", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-width" }, "column-span": { syntax: "none | all", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "none", appliesto: "inFlowBlockLevelElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-span" }, "column-width": { syntax: "<length> | auto", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Columns" ], initial: "auto", appliesto: "blockContainersExceptTableWrappers", computed: "absoluteLengthZeroOrLarger", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-width" }, columns: columns, contain: contain, content: content, "counter-increment": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-increment" }, "counter-reset": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-reset" }, "counter-set": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-set" }, cursor: cursor, direction: direction, display: display, "empty-cells": { syntax: "show | hide", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "show", appliesto: "tableCellElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/empty-cells" }, filter: filter, flex: flex, "flex-basis": { syntax: "content | <'width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToFlexContainersInnerMainSize", groups: [ "CSS Flexible Box Layout" ], initial: "auto", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "lengthOrPercentageBeforeKeywordIfBothPresent", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-basis" }, "flex-direction": { syntax: "row | row-reverse | column | column-reverse", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "row", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-direction" }, "flex-flow": { syntax: "<'flex-direction'> || <'flex-wrap'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: [ "flex-direction", "flex-wrap" ], appliesto: "flexContainers", computed: [ "flex-direction", "flex-wrap" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-flow" }, "flex-grow": { syntax: "<number>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "0", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-grow" }, "flex-shrink": { syntax: "<number>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "1", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-shrink" }, "flex-wrap": { syntax: "nowrap | wrap | wrap-reverse", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "nowrap", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-wrap" }, float: float, font: font, "font-family": { syntax: "[ <family-name> | <generic-family> ]#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-family" }, "font-feature-settings": { syntax: "normal | <feature-tag-value>#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-feature-settings" }, "font-kerning": { syntax: "auto | normal | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-kerning" }, "font-language-override": { syntax: "normal | <string>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-language-override" }, "font-optical-sizing": { syntax: "auto | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-optical-sizing" }, "font-variation-settings": { syntax: "normal | [ <string> <number> ]#", media: "visual", inherited: true, animationType: "transform", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variation-settings" }, "font-size": { syntax: "<absolute-size> | <relative-size> | <length-percentage>", media: "visual", inherited: true, animationType: "length", percentages: "referToParentElementsFontSize", groups: [ "CSS Fonts" ], initial: "medium", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-size" }, "font-size-adjust": { syntax: "none | <number>", media: "visual", inherited: true, animationType: "number", percentages: "no", groups: [ "CSS Fonts" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-size-adjust" }, "font-stretch": { syntax: "<font-stretch-absolute>", media: "visual", inherited: true, animationType: "fontStretch", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-stretch" }, "font-style": { syntax: "normal | italic | oblique <angle>?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-style" }, "font-synthesis": { syntax: "none | [ weight || style ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "weight style", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-synthesis" }, "font-variant": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> || stylistic( <feature-value-name> ) || historical-forms || styleset( <feature-value-name># ) || character-variant( <feature-value-name># ) || swash( <feature-value-name> ) || ornaments( <feature-value-name> ) || annotation( <feature-value-name> ) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero || <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant" }, "font-variant-alternates": { syntax: "normal | [ stylistic( <feature-value-name> ) || historical-forms || styleset( <feature-value-name># ) || character-variant( <feature-value-name># ) || swash( <feature-value-name> ) || ornaments( <feature-value-name> ) || annotation( <feature-value-name> ) ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-alternates" }, "font-variant-caps": { syntax: "normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-caps" }, "font-variant-east-asian": { syntax: "normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-east-asian" }, "font-variant-ligatures": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-ligatures" }, "font-variant-numeric": { syntax: "normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-numeric" }, "font-variant-position": { syntax: "normal | sub | super", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-position" }, "font-weight": { syntax: "<font-weight-absolute> | bolder | lighter", media: "visual", inherited: true, animationType: "fontWeight", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "keywordOrNumericalValueBolderLighterTransformedToRealValue", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-weight" }, gap: gap, grid: grid, "grid-area": { syntax: "<grid-line> [ / <grid-line> ]{0,3}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-start", "grid-column-start", "grid-row-end", "grid-column-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-row-start", "grid-column-start", "grid-row-end", "grid-column-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-area" }, "grid-auto-columns": { syntax: "<track-size>+", media: "visual", inherited: false, animationType: "discrete", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-columns" }, "grid-auto-flow": { syntax: "[ row | column ] || dense", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "row", appliesto: "gridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-flow" }, "grid-auto-rows": { syntax: "<track-size>+", media: "visual", inherited: false, animationType: "discrete", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-rows" }, "grid-column": { syntax: "<grid-line> [ / <grid-line> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-column-start", "grid-column-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-column-start", "grid-column-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column" }, "grid-column-end": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column-end" }, "grid-column-gap": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "0", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-gap" }, "grid-column-start": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column-start" }, "grid-gap": { syntax: "<'grid-row-gap'> <'grid-column-gap'>?", media: "visual", inherited: false, animationType: [ "grid-row-gap", "grid-column-gap" ], percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-gap", "grid-column-gap" ], appliesto: "gridContainers", computed: [ "grid-row-gap", "grid-column-gap" ], order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/gap" }, "grid-row": { syntax: "<grid-line> [ / <grid-line> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-start", "grid-row-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-row-start", "grid-row-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row" }, "grid-row-end": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row-end" }, "grid-row-gap": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "0", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/row-gap" }, "grid-row-start": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row-start" }, "grid-template": { syntax: "none | [ <'grid-template-rows'> / <'grid-template-columns'> ] | [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: [ "grid-template-columns", "grid-template-rows" ], groups: [ "CSS Grid Layout" ], initial: [ "grid-template-columns", "grid-template-rows", "grid-template-areas" ], appliesto: "gridContainers", computed: [ "grid-template-columns", "grid-template-rows", "grid-template-areas" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template" }, "grid-template-areas": { syntax: "none | <string>+", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-areas" }, "grid-template-columns": { syntax: "none | <track-list> | <auto-track-list> | subgrid <line-name-list>?", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-columns" }, "grid-template-rows": { syntax: "none | <track-list> | <auto-track-list> | subgrid <line-name-list>?", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-rows" }, "hanging-punctuation": { syntax: "none | [ first || [ force-end | allow-end ] || last ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/hanging-punctuation" }, height: height, hyphens: hyphens, "image-orientation": { syntax: "from-image | <angle> | [ <angle>? flip ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "0deg", appliesto: "allElements", computed: "angleRoundedToNextQuarter", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/image-orientation" }, "image-rendering": { syntax: "auto | crisp-edges | pixelated", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/image-rendering" }, "image-resolution": { syntax: "[ from-image || <resolution> ] && snap?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "1dppx", appliesto: "allElements", computed: "asSpecifiedWithExceptionOfResolution", order: "uniqueOrder", status: "experimental" }, "ime-mode": { syntax: "auto | normal | active | inactive | disabled", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "textFields", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ime-mode" }, "initial-letter": { syntax: "normal | [ <number> <integer>? ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Inline" ], initial: "normal", appliesto: "firstLetterPseudoElementsAndInlineLevelFirstChildren", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/initial-letter" }, "initial-letter-align": { syntax: "[ auto | alphabetic | hanging | ideographic ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Inline" ], initial: "auto", appliesto: "firstLetterPseudoElementsAndInlineLevelFirstChildren", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/initial-letter-align" }, "inline-size": { syntax: "<'width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "sameAsWidthAndHeight", computed: "sameAsWidthAndHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inline-size" }, inset: inset, "inset-block": { syntax: "<'top'>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block" }, "inset-block-end": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block-end" }, "inset-block-start": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block-start" }, "inset-inline": { syntax: "<'top'>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline" }, "inset-inline-end": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline-end" }, "inset-inline-start": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline-start" }, isolation: isolation, "justify-content": { syntax: "normal | <content-distribution> | <overflow-position>? [ <content-position> | left | right ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-content" }, "justify-items": { syntax: "normal | stretch | <baseline-position> | <overflow-position>? [ <self-position> | left | right ] | legacy | legacy && [ left | right | center ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "legacy", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-items" }, "justify-self": { syntax: "auto | normal | stretch | <baseline-position> | <overflow-position>? [ <self-position> | left | right ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "auto", appliesto: "blockLevelBoxesAndAbsolutelyPositionedBoxesAndGridItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-self" }, left: left, "letter-spacing": { syntax: "normal | <length>", media: "visual", inherited: true, animationType: "length", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "optimumValueOfAbsoluteLengthOrNormal", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/letter-spacing" }, "line-break": { syntax: "auto | loose | normal | strict | anywhere", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-break" }, "line-clamp": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Overflow" ], initial: "none", appliesto: "blockContainersExceptMultiColumnContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "line-height": { syntax: "normal | <number> | <length> | <percentage>", media: "visual", inherited: true, animationType: "numberOrLength", percentages: "referToElementFontSize", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "absoluteLengthOrAsSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-height" }, "line-height-step": { syntax: "<length>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "0", appliesto: "blockContainers", computed: "absoluteLength", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-height-step" }, "list-style": { syntax: "<'list-style-type'> || <'list-style-position'> || <'list-style-image'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: [ "list-style-type", "list-style-position", "list-style-image" ], appliesto: "listItems", computed: [ "list-style-image", "list-style-position", "list-style-type" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style" }, "list-style-image": { syntax: "<url> | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "none", appliesto: "listItems", computed: "noneOrImageWithAbsoluteURI", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-image" }, "list-style-position": { syntax: "inside | outside", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "outside", appliesto: "listItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-position" }, "list-style-type": { syntax: "<counter-style> | <string> | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "disc", appliesto: "listItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-type" }, margin: margin, "margin-block": { syntax: "<'margin-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block" }, "margin-block-end": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block-end" }, "margin-block-start": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block-start" }, "margin-bottom": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-bottom" }, "margin-inline": { syntax: "<'margin-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline" }, "margin-inline-end": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline-end" }, "margin-inline-start": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline-start" }, "margin-left": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-left" }, "margin-right": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-right" }, "margin-top": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-top" }, mask: mask, "mask-border": { syntax: "<'mask-border-source'> || <'mask-border-slice'> [ / <'mask-border-width'>? [ / <'mask-border-outset'> ]? ]? || <'mask-border-repeat'> || <'mask-border-mode'>", media: "visual", inherited: false, animationType: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], percentages: [ "mask-border-slice", "mask-border-width" ], groups: [ "CSS Masking" ], initial: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], appliesto: "allElementsSVGContainerElements", computed: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], order: "perGrammar", stacking: true, status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border" }, "mask-border-mode": { syntax: "luminance | alpha", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "alpha", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-mode" }, "mask-border-outset": { syntax: "[ <length> | <number> ]{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "0", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-outset" }, "mask-border-repeat": { syntax: "[ stretch | repeat | round | space ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "stretch", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-repeat" }, "mask-border-slice": { syntax: "<number-percentage>{1,4} fill?", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfMaskBorderImage", groups: [ "CSS Masking" ], initial: "0", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-slice" }, "mask-border-source": { syntax: "none | <image>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-source" }, "mask-border-width": { syntax: "[ <length-percentage> | <number> | auto ]{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "relativeToMaskBorderImageArea", groups: [ "CSS Masking" ], initial: "auto", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-width" }, "mask-clip": { syntax: "[ <geometry-box> | no-clip ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "border-box", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-clip" }, "mask-composite": { syntax: "<compositing-operator>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "add", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-composite" }, "mask-image": { syntax: "<mask-reference>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-image" }, "mask-mode": { syntax: "<masking-mode>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "match-source", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-mode" }, "mask-origin": { syntax: "<geometry-box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "border-box", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-origin" }, "mask-position": { syntax: "<position>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToSizeOfMaskPaintingArea", groups: [ "CSS Masking" ], initial: "center", appliesto: "allElementsSVGContainerElements", computed: "consistsOfTwoKeywordsForOriginAndOffsets", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-position" }, "mask-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "no-repeat", appliesto: "allElementsSVGContainerElements", computed: "consistsOfTwoDimensionKeywords", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-repeat" }, "mask-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "no", groups: [ "CSS Masking" ], initial: "auto", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-size" }, "mask-type": { syntax: "luminance | alpha", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "luminance", appliesto: "maskElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-type" }, "max-block-size": { syntax: "<'max-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMaxWidthAndMaxHeight", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-block-size" }, "max-height": { syntax: "<length> | <percentage> | none | max-content | min-content | fit-content | fill-available", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentagesNone", groups: [ "CSS Box Model" ], initial: "none", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAsSpecifiedAbsoluteLengthOrNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-height" }, "max-inline-size": { syntax: "<'max-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMaxWidthAndMaxHeight", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-inline-size" }, "max-lines": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Overflow" ], initial: "none", appliesto: "blockContainersExceptMultiColumnContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "max-width": { syntax: "<length> | <percentage> | none | max-content | min-content | fit-content | fill-available", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "none", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAsSpecifiedAbsoluteLengthOrNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-width" }, "min-block-size": { syntax: "<'min-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMinWidthAndMinHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-block-size" }, "min-height": { syntax: "<length> | <percentage> | auto | max-content | min-content | fit-content | fill-available", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentages0", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-height" }, "min-inline-size": { syntax: "<'min-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMinWidthAndMinHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-inline-size" }, "min-width": { syntax: "<length> | <percentage> | auto | max-content | min-content | fit-content | fill-available", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-width" }, "mix-blend-mode": { syntax: "<blend-mode>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mix-blend-mode" }, "object-fit": { syntax: "fill | contain | cover | none | scale-down", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "fill", appliesto: "replacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/object-fit" }, "object-position": { syntax: "<position>", media: "visual", inherited: true, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToWidthAndHeightOfElement", groups: [ "CSS Images" ], initial: "50% 50%", appliesto: "replacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/object-position" }, offset: offset, "offset-anchor": { syntax: "auto | <position>", media: "visual", inherited: false, animationType: "position", percentages: "relativeToWidthAndHeight", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "experimental" }, "offset-distance": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToTotalPathLength", groups: [ "CSS Motion Path" ], initial: "0", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-distance" }, "offset-path": { syntax: "none | ray( [ <angle> && <size>? && contain? ] ) | <path()> | <url> | [ <basic-shape> || <geometry-box> ]", media: "visual", inherited: false, animationType: "angleOrBasicShapeOrPath", percentages: "no", groups: [ "CSS Motion Path" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-path" }, "offset-position": { syntax: "auto | <position>", media: "visual", inherited: false, animationType: "position", percentages: "referToSizeOfContainingBlock", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "experimental" }, "offset-rotate": { syntax: "[ auto | reverse ] || <angle>", media: "visual", inherited: false, animationType: "angleOrBasicShapeOrPath", percentages: "no", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-rotate" }, opacity: opacity, order: order, orphans: orphans, outline: outline, "outline-color": { syntax: "<color> | invert", media: [ "visual", "interactive" ], inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "invertOrCurrentColor", appliesto: "allElements", computed: "invertForTranslucentColorRGBAOtherwiseRGB", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-color" }, "outline-offset": { syntax: "<length>", media: [ "visual", "interactive" ], inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "0", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-offset" }, "outline-style": { syntax: "auto | <'border-style'>", media: [ "visual", "interactive" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-style" }, "outline-width": { syntax: "<line-width>", media: [ "visual", "interactive" ], inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "medium", appliesto: "allElements", computed: "absoluteLength0ForNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-width" }, overflow: overflow, "overflow-anchor": { syntax: "auto | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Anchoring" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "overflow-block": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "auto", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "overflow-clip-box": { syntax: "padding-box | content-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "padding-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Mozilla/CSS/overflow-clip-box" }, "overflow-inline": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "auto", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "overflow-wrap": { syntax: "normal | break-word | anywhere", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "nonReplacedInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-wrap" }, "overflow-x": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-x" }, "overflow-y": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-y" }, "overscroll-behavior": { syntax: "[ contain | none | auto ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior" }, "overscroll-behavior-x": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-x" }, "overscroll-behavior-y": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-y" }, padding: padding, "padding-block": { syntax: "<'padding-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block" }, "padding-block-end": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block-end" }, "padding-block-start": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block-start" }, "padding-bottom": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-bottom" }, "padding-inline": { syntax: "<'padding-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline" }, "padding-inline-end": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline-end" }, "padding-inline-start": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline-start" }, "padding-left": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-left" }, "padding-right": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-right" }, "padding-top": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-top" }, "page-break-after": { syntax: "auto | always | avoid | left | right | recto | verso", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-after" }, "page-break-before": { syntax: "auto | always | avoid | left | right | recto | verso", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-before" }, "page-break-inside": { syntax: "auto | avoid", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-inside" }, "paint-order": { syntax: "normal | [ fill || stroke || markers ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "textElements", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/paint-order" }, perspective: perspective, "perspective-origin": { syntax: "<position>", media: "visual", inherited: false, animationType: "simpleListOfLpc", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "50% 50%", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "oneOrTwoValuesLengthAbsoluteKeywordsPercentages", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/perspective-origin" }, "place-content": { syntax: "<'align-content'> <'justify-content'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multilineFlexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-content" }, "place-items": { syntax: "<'align-items'> <'justify-items'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "align-items", "justify-items" ], appliesto: "allElements", computed: [ "align-items", "justify-items" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-items" }, "place-self": { syntax: "<'align-self'> <'justify-self'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "align-self", "justify-self" ], appliesto: "blockLevelBoxesAndAbsolutelyPositionedBoxesAndGridItems", computed: [ "align-self", "justify-self" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-self" }, "pointer-events": { syntax: "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Pointer Events" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/pointer-events" }, position: position, quotes: quotes, resize: resize, right: right, rotate: rotate, "row-gap": { syntax: "normal | <length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multiColumnElementsFlexContainersGridContainers", computed: "asSpecifiedWithLengthsAbsoluteAndNormalComputingToZeroExceptMultiColumn", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/row-gap" }, "ruby-align": { syntax: "start | center | space-between | space-around", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "space-around", appliesto: "rubyBasesAnnotationsBaseAnnotationContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align" }, "ruby-merge": { syntax: "separate | collapse | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "separate", appliesto: "rubyAnnotationsContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, "ruby-position": { syntax: "over | under | inter-character", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "over", appliesto: "rubyAnnotationsContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ruby-position" }, scale: scale, "scrollbar-color": { syntax: "auto | dark | light | <color>{2}", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Scrollbars" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-color" }, "scrollbar-width": { syntax: "auto | thin | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scrollbars" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width" }, "scroll-behavior": { syntax: "auto | smooth", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSSOM View" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-behavior" }, "scroll-margin": { syntax: "<length>{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin" }, "scroll-margin-block": { syntax: "<length>{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block" }, "scroll-margin-block-start": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block-start" }, "scroll-margin-block-end": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block-end" }, "scroll-margin-bottom": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-bottom" }, "scroll-margin-inline": { syntax: "<length>{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline" }, "scroll-margin-inline-start": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline-start" }, "scroll-margin-inline-end": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline-end" }, "scroll-margin-left": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-left" }, "scroll-margin-right": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-right" }, "scroll-margin-top": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-top" }, "scroll-padding": { syntax: "[ auto | <length-percentage> ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding" }, "scroll-padding-block": { syntax: "[ auto | <length-percentage> ]{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block" }, "scroll-padding-block-start": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block-start" }, "scroll-padding-block-end": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block-end" }, "scroll-padding-bottom": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-bottom" }, "scroll-padding-inline": { syntax: "[ auto | <length-percentage> ]{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline" }, "scroll-padding-inline-start": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline-start" }, "scroll-padding-inline-end": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline-end" }, "scroll-padding-left": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-left" }, "scroll-padding-right": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-right" }, "scroll-padding-top": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-top" }, "scroll-snap-align": { syntax: "[ none | start | end | center ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-align" }, "scroll-snap-coordinate": { syntax: "none | <position>#", media: "interactive", inherited: false, animationType: "position", percentages: "referToBorderBox", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-coordinate" }, "scroll-snap-destination": { syntax: "<position>", media: "interactive", inherited: false, animationType: "position", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "0px 0px", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-destination" }, "scroll-snap-points-x": { syntax: "none | repeat( <length-percentage> )", media: "interactive", inherited: false, animationType: "discrete", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-points-x" }, "scroll-snap-points-y": { syntax: "none | repeat( <length-percentage> )", media: "interactive", inherited: false, animationType: "discrete", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-points-y" }, "scroll-snap-stop": { syntax: "normal | always", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-stop" }, "scroll-snap-type": { syntax: "none | [ x | y | block | inline | both ] [ mandatory | proximity ]?", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type" }, "scroll-snap-type-x": { syntax: "none | mandatory | proximity", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type-x" }, "scroll-snap-type-y": { syntax: "none | mandatory | proximity", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type-y" }, "shape-image-threshold": { syntax: "<alpha-value>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Shapes" ], initial: "0.0", appliesto: "floats", computed: "specifiedValueNumberClipped0To1", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-image-threshold" }, "shape-margin": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Shapes" ], initial: "0", appliesto: "floats", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-margin" }, "shape-outside": { syntax: "none | <shape-box> || <basic-shape> | <image>", media: "visual", inherited: false, animationType: "basicShapeOtherwiseNo", percentages: "no", groups: [ "CSS Shapes" ], initial: "none", appliesto: "floats", computed: "asDefinedForBasicShapeWithAbsoluteURIOtherwiseAsSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-outside" }, "tab-size": { syntax: "<integer> | <length>", media: "visual", inherited: true, animationType: "length", percentages: "no", groups: [ "CSS Text" ], initial: "8", appliesto: "blockContainers", computed: "specifiedIntegerOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/tab-size" }, "table-layout": { syntax: "auto | fixed", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "auto", appliesto: "tableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/table-layout" }, "text-align": { syntax: "start | end | left | right | center | justify | match-parent", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "startOrNamelessValueIfLTRRightIfRTL", appliesto: "blockContainers", computed: "asSpecifiedExceptMatchParent", order: "orderOfAppearance", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-align" }, "text-align-last": { syntax: "auto | start | end | left | right | center | justify", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "blockContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-align-last" }, "text-combine-upright": { syntax: "none | all | [ digits <integer>? ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "none", appliesto: "nonReplacedInlineElements", computed: "keywordPlusIntegerIfDigits", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-combine-upright" }, "text-decoration": { syntax: "<'text-decoration-line'> || <'text-decoration-style'> || <'text-decoration-color'> || <'text-decoration-thickness'>", media: "visual", inherited: false, animationType: [ "text-decoration-color", "text-decoration-style", "text-decoration-line", "text-decoration-thickness" ], percentages: "no", groups: [ "CSS Text Decoration" ], initial: [ "text-decoration-color", "text-decoration-style", "text-decoration-line" ], appliesto: "allElements", computed: [ "text-decoration-line", "text-decoration-style", "text-decoration-color", "text-decoration-thickness" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration" }, "text-decoration-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-color" }, "text-decoration-line": { syntax: "none | [ underline || overline || line-through || blink ] | spelling-error | grammar-error", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-line" }, "text-decoration-skip": { syntax: "none | [ objects || [ spaces | [ leading-spaces || trailing-spaces ] ] || edges || box-decoration ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "objects", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-skip" }, "text-decoration-skip-ink": { syntax: "auto | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-skip-ink" }, "text-decoration-style": { syntax: "solid | double | dotted | dashed | wavy", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "solid", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-style" }, "text-decoration-thickness": { syntax: "auto | from-font | <length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-thickness" }, "text-emphasis": { syntax: "<'text-emphasis-style'> || <'text-emphasis-color'>", media: "visual", inherited: false, animationType: [ "text-emphasis-color", "text-emphasis-style" ], percentages: "no", groups: [ "CSS Text Decoration" ], initial: [ "text-emphasis-style", "text-emphasis-color" ], appliesto: "allElements", computed: [ "text-emphasis-style", "text-emphasis-color" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis" }, "text-emphasis-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-color" }, "text-emphasis-position": { syntax: "[ over | under ] && [ right | left ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "over right", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-position" }, "text-emphasis-style": { syntax: "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | <string>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-style" }, "text-indent": { syntax: "<length-percentage> && hanging? && each-line?", media: "visual", inherited: true, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Text" ], initial: "0", appliesto: "blockContainers", computed: "percentageOrAbsoluteLengthPlusKeywords", order: "lengthOrPercentageBeforeKeywords", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-indent" }, "text-justify": { syntax: "auto | inter-character | inter-word | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "inlineLevelAndTableCellElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-justify" }, "text-orientation": { syntax: "mixed | upright | sideways", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "mixed", appliesto: "allElementsExceptTableRowGroupsRowsColumnGroupsAndColumns", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-orientation" }, "text-overflow": { syntax: "[ clip | ellipsis | <string> ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "clip", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-overflow" }, "text-rendering": { syntax: "auto | optimizeSpeed | optimizeLegibility | geometricPrecision", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Miscellaneous" ], initial: "auto", appliesto: "textElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-rendering" }, "text-shadow": { syntax: "none | <shadow-t>#", media: "visual", inherited: true, animationType: "shadowList", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "colorPlusThreeAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-shadow" }, "text-size-adjust": { syntax: "none | auto | <percentage>", media: "visual", inherited: true, animationType: "discrete", percentages: "referToSizeOfFont", groups: [ "CSS Text" ], initial: "autoForSmartphoneBrowsersSupportingInflation", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-size-adjust" }, "text-transform": { syntax: "none | capitalize | uppercase | lowercase | full-width | full-size-kana", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-transform" }, "text-underline-offset": { syntax: "auto | from-font | <length>", media: "visual", inherited: true, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-underline-offset" }, "text-underline-position": { syntax: "auto | [ under || [ left | right ] ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-underline-position" }, top: top, "touch-action": { syntax: "auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] || pinch-zoom ] | manipulation", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Pointer Events" ], initial: "auto", appliesto: "allElementsExceptNonReplacedInlineElementsTableRowsColumnsRowColumnGroups", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/touch-action" }, transform: transform, "transform-box": { syntax: "border-box | fill-box | view-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "border-box ", appliesto: "transformableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-box" }, "transform-origin": { syntax: "[ <length-percentage> | left | center | right | top | bottom ] | [ [ <length-percentage> | left | center | right ] && [ <length-percentage> | top | center | bottom ] ] <length>?", media: "visual", inherited: false, animationType: "simpleListOfLpc", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "50% 50% 0", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "oneOrTwoValuesLengthAbsoluteKeywordsPercentages", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-origin" }, "transform-style": { syntax: "flat | preserve-3d", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "flat", appliesto: "transformableElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-style" }, transition: transition, "transition-delay": { syntax: "<time>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-delay" }, "transition-duration": { syntax: "<time>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-duration" }, "transition-property": { syntax: "none | <single-transition-property>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "all", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-property" }, "transition-timing-function": { syntax: "<timing-function>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "ease", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-timing-function" }, translate: translate, "unicode-bidi": { syntax: "normal | embed | isolate | bidi-override | isolate-override | plaintext", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "normal", appliesto: "allElementsSomeValuesNoEffectOnNonInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/unicode-bidi" }, "user-select": { syntax: "auto | text | none | contain | all", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/user-select" }, "vertical-align": { syntax: "baseline | sub | super | text-top | text-bottom | middle | top | bottom | <percentage> | <length>", media: "visual", inherited: false, animationType: "length", percentages: "referToLineHeight", groups: [ "CSS Table" ], initial: "baseline", appliesto: "inlineLevelAndTableCellElements", computed: "absoluteLengthOrKeyword", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/vertical-align" }, visibility: visibility, "white-space": { syntax: "normal | pre | nowrap | pre-wrap | pre-line | break-spaces", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/white-space" }, widows: widows, width: width, "will-change": { syntax: "auto | <animateable-feature>#", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Will Change" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/will-change" }, "word-break": { syntax: "normal | break-all | keep-all | break-word", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/word-break" }, "word-spacing": { syntax: "normal | <length-percentage>", media: "visual", inherited: true, animationType: "length", percentages: "referToWidthOfAffectedGlyph", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "optimumMinAndMaxValueOfAbsoluteLengthPercentageOrNormal", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/word-spacing" }, "word-wrap": { syntax: "normal | break-word", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "nonReplacedInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-wrap" }, "writing-mode": { syntax: "horizontal-tb | vertical-rl | vertical-lr | sideways-rl | sideways-lr", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "horizontal-tb", appliesto: "allElementsExceptTableRowColumnGroupsTableRowsColumns", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/writing-mode" }, "z-index": { syntax: "auto | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/z-index" }, zoom: zoom }; var properties$2 = /*#__PURE__*/Object.freeze({ __proto__: null, all: all, animation: animation, appearance: appearance, azimuth: azimuth, background: background, border: border, bottom: bottom, clear: clear, clip: clip, color: color, columns: columns, contain: contain, content: content, cursor: cursor, direction: direction, display: display, filter: filter, flex: flex, float: float, font: font, gap: gap, grid: grid, height: height, hyphens: hyphens, inset: inset, isolation: isolation, left: left, margin: margin, mask: mask, offset: offset, opacity: opacity, order: order, orphans: orphans, outline: outline, overflow: overflow, padding: padding, perspective: perspective, position: position, quotes: quotes, resize: resize, right: right, rotate: rotate, scale: scale, top: top, transform: transform, transition: transition, translate: translate, visibility: visibility, widows: widows, width: width, zoom: zoom, 'default': properties$1 }); var attachment = { syntax: "scroll | fixed | local" }; var box = { syntax: "border-box | padding-box | content-box" }; var color$1 = { syntax: "<rgb()> | <rgba()> | <hsl()> | <hsla()> | <hex-color> | <named-color> | currentcolor | <deprecated-system-color>" }; var combinator = { syntax: "'>' | '+' | '~' | [ '||' ]" }; var compat = { syntax: "searchfield | textarea | push-button | button-bevel | slider-horizontal | checkbox | radio | square-button | menulist | menulist-button | listbox | meter | progress-bar" }; var gradient = { syntax: "<linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()> | <conic-gradient()>" }; var hue = { syntax: "<number> | <angle>" }; var image = { syntax: "<url> | <image()> | <image-set()> | <element()> | <paint()> | <cross-fade()> | <gradient>" }; var nth = { syntax: "<an-plus-b> | even | odd" }; var position$1 = { syntax: "[ [ left | center | right ] || [ top | center | bottom ] | [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]? | [ [ left | right ] <length-percentage> ] && [ [ top | bottom ] <length-percentage> ] ]" }; var quote = { syntax: "open-quote | close-quote | no-open-quote | no-close-quote" }; var shadow = { syntax: "inset? && <length>{2,4} && <color>?" }; var shape$1 = { syntax: "rect(<top>, <right>, <bottom>, <left>)" }; var size = { syntax: "closest-side | farthest-side | closest-corner | farthest-corner | <length> | <length-percentage>{2}" }; var symbol = { syntax: "<string> | <image> | <custom-ident>" }; var target = { syntax: "<target-counter()> | <target-counters()> | <target-text()>" }; var syntaxes = { "absolute-size": { syntax: "xx-small | x-small | small | medium | large | x-large | xx-large | xxx-large" }, "alpha-value": { syntax: "<number> | <percentage>" }, "angle-percentage": { syntax: "<angle> | <percentage>" }, "angular-color-hint": { syntax: "<angle-percentage>" }, "angular-color-stop": { syntax: "<color> && <color-stop-angle>?" }, "angular-color-stop-list": { syntax: "[ <angular-color-stop> [, <angular-color-hint>]? ]# , <angular-color-stop>" }, "animateable-feature": { syntax: "scroll-position | contents | <custom-ident>" }, attachment: attachment, "attr()": { syntax: "attr( <attr-name> <type-or-unit>? [, <attr-fallback> ]? )" }, "attr-matcher": { syntax: "[ '~' | '|' | '^' | '$' | '*' ]? '='" }, "attr-modifier": { syntax: "i | s" }, "attribute-selector": { syntax: "'[' <wq-name> ']' | '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'" }, "auto-repeat": { syntax: "repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )" }, "auto-track-list": { syntax: "[ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>? <auto-repeat>\n[ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?" }, "baseline-position": { syntax: "[ first | last ]? baseline" }, "basic-shape": { syntax: "<inset()> | <circle()> | <ellipse()> | <polygon()>" }, "bg-image": { syntax: "none | <image>" }, "bg-layer": { syntax: "<bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>" }, "bg-position": { syntax: "[ [ left | center | right | top | bottom | <length-percentage> ] | [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ] | [ center | [ left | right ] <length-percentage>? ] && [ center | [ top | bottom ] <length-percentage>? ] ]" }, "bg-size": { syntax: "[ <length-percentage> | auto ]{1,2} | cover | contain" }, "blur()": { syntax: "blur( <length> )" }, "blend-mode": { syntax: "normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity" }, box: box, "brightness()": { syntax: "brightness( <number-percentage> )" }, "calc()": { syntax: "calc( <calc-sum> )" }, "calc-sum": { syntax: "<calc-product> [ [ '+' | '-' ] <calc-product> ]*" }, "calc-product": { syntax: "<calc-value> [ '*' <calc-value> | '/' <number> ]*" }, "calc-value": { syntax: "<number> | <dimension> | <percentage> | ( <calc-sum> )" }, "cf-final-image": { syntax: "<image> | <color>" }, "cf-mixing-image": { syntax: "<percentage>? && <image>" }, "circle()": { syntax: "circle( [ <shape-radius> ]? [ at <position> ]? )" }, "clamp()": { syntax: "clamp( <calc-sum>#{3} )" }, "class-selector": { syntax: "'.' <ident-token>" }, "clip-source": { syntax: "<url>" }, color: color$1, "color-stop": { syntax: "<color-stop-length> | <color-stop-angle>" }, "color-stop-angle": { syntax: "<angle-percentage>{1,2}" }, "color-stop-length": { syntax: "<length-percentage>{1,2}" }, "color-stop-list": { syntax: "[ <linear-color-stop> [, <linear-color-hint>]? ]# , <linear-color-stop>" }, combinator: combinator, "common-lig-values": { syntax: "[ common-ligatures | no-common-ligatures ]" }, compat: compat, "composite-style": { syntax: "clear | copy | source-over | source-in | source-out | source-atop | destination-over | destination-in | destination-out | destination-atop | xor" }, "compositing-operator": { syntax: "add | subtract | intersect | exclude" }, "compound-selector": { syntax: "[ <type-selector>? <subclass-selector>* [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!" }, "compound-selector-list": { syntax: "<compound-selector>#" }, "complex-selector": { syntax: "<compound-selector> [ <combinator>? <compound-selector> ]*" }, "complex-selector-list": { syntax: "<complex-selector>#" }, "conic-gradient()": { syntax: "conic-gradient( [ from <angle> ]? [ at <position> ]?, <angular-color-stop-list> )" }, "contextual-alt-values": { syntax: "[ contextual | no-contextual ]" }, "content-distribution": { syntax: "space-between | space-around | space-evenly | stretch" }, "content-list": { syntax: "[ <string> | contents | <image> | <quote> | <target> | <leader()> ]+" }, "content-position": { syntax: "center | start | end | flex-start | flex-end" }, "content-replacement": { syntax: "<image>" }, "contrast()": { syntax: "contrast( [ <number-percentage> ] )" }, "counter()": { syntax: "counter( <custom-ident>, <counter-style>? )" }, "counter-style": { syntax: "<counter-style-name> | symbols()" }, "counter-style-name": { syntax: "<custom-ident>" }, "counters()": { syntax: "counters( <custom-ident>, <string>, <counter-style>? )" }, "cross-fade()": { syntax: "cross-fade( <cf-mixing-image> , <cf-final-image>? )" }, "cubic-bezier-timing-function": { syntax: "ease | ease-in | ease-out | ease-in-out | cubic-bezier(<number>, <number>, <number>, <number>)" }, "deprecated-system-color": { syntax: "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonFace | ButtonHighlight | ButtonShadow | ButtonText | CaptionText | GrayText | Highlight | HighlightText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, "discretionary-lig-values": { syntax: "[ discretionary-ligatures | no-discretionary-ligatures ]" }, "display-box": { syntax: "contents | none" }, "display-inside": { syntax: "flow | flow-root | table | flex | grid | ruby" }, "display-internal": { syntax: "table-row-group | table-header-group | table-footer-group | table-row | table-cell | table-column-group | table-column | table-caption | ruby-base | ruby-text | ruby-base-container | ruby-text-container" }, "display-legacy": { syntax: "inline-block | inline-list-item | inline-table | inline-flex | inline-grid" }, "display-listitem": { syntax: "<display-outside>? && [ flow | flow-root ]? && list-item" }, "display-outside": { syntax: "block | inline | run-in" }, "drop-shadow()": { syntax: "drop-shadow( <length>{2,3} <color>? )" }, "east-asian-variant-values": { syntax: "[ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]" }, "east-asian-width-values": { syntax: "[ full-width | proportional-width ]" }, "element()": { syntax: "element( <id-selector> )" }, "ellipse()": { syntax: "ellipse( [ <shape-radius>{2} ]? [ at <position> ]? )" }, "ending-shape": { syntax: "circle | ellipse" }, "env()": { syntax: "env( <custom-ident> , <declaration-value>? )" }, "explicit-track-list": { syntax: "[ <line-names>? <track-size> ]+ <line-names>?" }, "family-name": { syntax: "<string> | <custom-ident>+" }, "feature-tag-value": { syntax: "<string> [ <integer> | on | off ]?" }, "feature-type": { syntax: "@stylistic | @historical-forms | @styleset | @character-variant | @swash | @ornaments | @annotation" }, "feature-value-block": { syntax: "<feature-type> '{' <feature-value-declaration-list> '}'" }, "feature-value-block-list": { syntax: "<feature-value-block>+" }, "feature-value-declaration": { syntax: "<custom-ident>: <integer>+;" }, "feature-value-declaration-list": { syntax: "<feature-value-declaration>" }, "feature-value-name": { syntax: "<custom-ident>" }, "fill-rule": { syntax: "nonzero | evenodd" }, "filter-function": { syntax: "<blur()> | <brightness()> | <contrast()> | <drop-shadow()> | <grayscale()> | <hue-rotate()> | <invert()> | <opacity()> | <saturate()> | <sepia()>" }, "filter-function-list": { syntax: "[ <filter-function> | <url> ]+" }, "final-bg-layer": { syntax: "<'background-color'> || <bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>" }, "fit-content()": { syntax: "fit-content( [ <length> | <percentage> ] )" }, "fixed-breadth": { syntax: "<length-percentage>" }, "fixed-repeat": { syntax: "repeat( [ <positive-integer> ] , [ <line-names>? <fixed-size> ]+ <line-names>? )" }, "fixed-size": { syntax: "<fixed-breadth> | minmax( <fixed-breadth> , <track-breadth> ) | minmax( <inflexible-breadth> , <fixed-breadth> )" }, "font-stretch-absolute": { syntax: "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | <percentage>" }, "font-variant-css21": { syntax: "[ normal | small-caps ]" }, "font-weight-absolute": { syntax: "normal | bold | <number>" }, "frequency-percentage": { syntax: "<frequency> | <percentage>" }, "general-enclosed": { syntax: "[ <function-token> <any-value> ) ] | ( <ident> <any-value> )" }, "generic-family": { syntax: "serif | sans-serif | cursive | fantasy | monospace" }, "generic-name": { syntax: "serif | sans-serif | cursive | fantasy | monospace" }, "geometry-box": { syntax: "<shape-box> | fill-box | stroke-box | view-box" }, gradient: gradient, "grayscale()": { syntax: "grayscale( <number-percentage> )" }, "grid-line": { syntax: "auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]" }, "historical-lig-values": { syntax: "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { syntax: "hsl( <hue> <percentage> <percentage> [ / <alpha-value> ]? ) | hsl( <hue>, <percentage>, <percentage>, <alpha-value>? )" }, "hsla()": { syntax: "hsla( <hue> <percentage> <percentage> [ / <alpha-value> ]? ) | hsla( <hue>, <percentage>, <percentage>, <alpha-value>? )" }, hue: hue, "hue-rotate()": { syntax: "hue-rotate( <angle> )" }, "id-selector": { syntax: "<hash-token>" }, image: image, "image()": { syntax: "image( <image-tags>? [ <image-src>? , <color>? ]! )" }, "image-set()": { syntax: "image-set( <image-set-option># )" }, "image-set-option": { syntax: "[ <image> | <string> ] <resolution>" }, "image-src": { syntax: "<url> | <string>" }, "image-tags": { syntax: "ltr | rtl" }, "inflexible-breadth": { syntax: "<length> | <percentage> | min-content | max-content | auto" }, "inset()": { syntax: "inset( <length-percentage>{1,4} [ round <'border-radius'> ]? )" }, "invert()": { syntax: "invert( <number-percentage> )" }, "keyframes-name": { syntax: "<custom-ident> | <string>" }, "keyframe-block": { syntax: "<keyframe-selector># {\n <declaration-list>\n}" }, "keyframe-block-list": { syntax: "<keyframe-block>+" }, "keyframe-selector": { syntax: "from | to | <percentage>" }, "leader()": { syntax: "leader( <leader-type> )" }, "leader-type": { syntax: "dotted | solid | space | <string>" }, "length-percentage": { syntax: "<length> | <percentage>" }, "line-names": { syntax: "'[' <custom-ident>* ']'" }, "line-name-list": { syntax: "[ <line-names> | <name-repeat> ]+" }, "line-style": { syntax: "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset" }, "line-width": { syntax: "<length> | thin | medium | thick" }, "linear-color-hint": { syntax: "<length-percentage>" }, "linear-color-stop": { syntax: "<color> <color-stop-length>?" }, "linear-gradient()": { syntax: "linear-gradient( [ <angle> | to <side-or-corner> ]? , <color-stop-list> )" }, "mask-layer": { syntax: "<mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> || <geometry-box> || [ <geometry-box> | no-clip ] || <compositing-operator> || <masking-mode>" }, "mask-position": { syntax: "[ <length-percentage> | left | center | right ] [ <length-percentage> | top | center | bottom ]?" }, "mask-reference": { syntax: "none | <image> | <mask-source>" }, "mask-source": { syntax: "<url>" }, "masking-mode": { syntax: "alpha | luminance | match-source" }, "matrix()": { syntax: "matrix( <number>#{6} )" }, "matrix3d()": { syntax: "matrix3d( <number>#{16} )" }, "max()": { syntax: "max( <calc-sum># )" }, "media-and": { syntax: "<media-in-parens> [ and <media-in-parens> ]+" }, "media-condition": { syntax: "<media-not> | <media-and> | <media-or> | <media-in-parens>" }, "media-condition-without-or": { syntax: "<media-not> | <media-and> | <media-in-parens>" }, "media-feature": { syntax: "( [ <mf-plain> | <mf-boolean> | <mf-range> ] )" }, "media-in-parens": { syntax: "( <media-condition> ) | <media-feature> | <general-enclosed>" }, "media-not": { syntax: "not <media-in-parens>" }, "media-or": { syntax: "<media-in-parens> [ or <media-in-parens> ]+" }, "media-query": { syntax: "<media-condition> | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?" }, "media-query-list": { syntax: "<media-query>#" }, "media-type": { syntax: "<ident>" }, "mf-boolean": { syntax: "<mf-name>" }, "mf-name": { syntax: "<ident>" }, "mf-plain": { syntax: "<mf-name> : <mf-value>" }, "mf-range": { syntax: "<mf-name> [ '<' | '>' ]? '='? <mf-value>\n| <mf-value> [ '<' | '>' ]? '='? <mf-name>\n| <mf-value> '<' '='? <mf-name> '<' '='? <mf-value>\n| <mf-value> '>' '='? <mf-name> '>' '='? <mf-value>" }, "mf-value": { syntax: "<number> | <dimension> | <ident> | <ratio>" }, "min()": { syntax: "min( <calc-sum># )" }, "minmax()": { syntax: "minmax( [ <length> | <percentage> | <flex> | min-content | max-content | auto ] , [ <length> | <percentage> | <flex> | min-content | max-content | auto ] )" }, "named-color": { syntax: "transparent | aliceblue | antiquewhite | aqua | aquamarine | azure | beige | bisque | black | blanchedalmond | blue | blueviolet | brown | burlywood | cadetblue | chartreuse | chocolate | coral | cornflowerblue | cornsilk | crimson | cyan | darkblue | darkcyan | darkgoldenrod | darkgray | darkgreen | darkgrey | darkkhaki | darkmagenta | darkolivegreen | darkorange | darkorchid | darkred | darksalmon | darkseagreen | darkslateblue | darkslategray | darkslategrey | darkturquoise | darkviolet | deeppink | deepskyblue | dimgray | dimgrey | dodgerblue | firebrick | floralwhite | forestgreen | fuchsia | gainsboro | ghostwhite | gold | goldenrod | gray | green | greenyellow | grey | honeydew | hotpink | indianred | indigo | ivory | khaki | lavender | lavenderblush | lawngreen | lemonchiffon | lightblue | lightcoral | lightcyan | lightgoldenrodyellow | lightgray | lightgreen | lightgrey | lightpink | lightsalmon | lightseagreen | lightskyblue | lightslategray | lightslategrey | lightsteelblue | lightyellow | lime | limegreen | linen | magenta | maroon | mediumaquamarine | mediumblue | mediumorchid | mediumpurple | mediumseagreen | mediumslateblue | mediumspringgreen | mediumturquoise | mediumvioletred | midnightblue | mintcream | mistyrose | moccasin | navajowhite | navy | oldlace | olive | olivedrab | orange | orangered | orchid | palegoldenrod | palegreen | paleturquoise | palevioletred | papayawhip | peachpuff | peru | pink | plum | powderblue | purple | rebeccapurple | red | rosybrown | royalblue | saddlebrown | salmon | sandybrown | seagreen | seashell | sienna | silver | skyblue | slateblue | slategray | slategrey | snow | springgreen | steelblue | tan | teal | thistle | tomato | turquoise | violet | wheat | white | whitesmoke | yellow | yellowgreen" }, "namespace-prefix": { syntax: "<ident>" }, "ns-prefix": { syntax: "[ <ident-token> | '*' ]? '|'" }, "number-percentage": { syntax: "<number> | <percentage>" }, "numeric-figure-values": { syntax: "[ lining-nums | oldstyle-nums ]" }, "numeric-fraction-values": { syntax: "[ diagonal-fractions | stacked-fractions ]" }, "numeric-spacing-values": { syntax: "[ proportional-nums | tabular-nums ]" }, nth: nth, "opacity()": { syntax: "opacity( [ <number-percentage> ] )" }, "overflow-position": { syntax: "unsafe | safe" }, "outline-radius": { syntax: "<length> | <percentage>" }, "page-body": { syntax: "<declaration>? [ ; <page-body> ]? | <page-margin-box> <page-body>" }, "page-margin-box": { syntax: "<page-margin-box-type> '{' <declaration-list> '}'" }, "page-margin-box-type": { syntax: "@top-left-corner | @top-left | @top-center | @top-right | @top-right-corner | @bottom-left-corner | @bottom-left | @bottom-center | @bottom-right | @bottom-right-corner | @left-top | @left-middle | @left-bottom | @right-top | @right-middle | @right-bottom" }, "page-selector-list": { syntax: "[ <page-selector># ]?" }, "page-selector": { syntax: "<pseudo-page>+ | <ident> <pseudo-page>*" }, "paint()": { syntax: "paint( <ident>, <declaration-value>? )" }, "perspective()": { syntax: "perspective( <length> )" }, "polygon()": { syntax: "polygon( <fill-rule>? , [ <length-percentage> <length-percentage> ]# )" }, position: position$1, "pseudo-class-selector": { syntax: "':' <ident-token> | ':' <function-token> <any-value> ')'" }, "pseudo-element-selector": { syntax: "':' <pseudo-class-selector>" }, "pseudo-page": { syntax: ": [ left | right | first | blank ]" }, quote: quote, "radial-gradient()": { syntax: "radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )" }, "relative-selector": { syntax: "<combinator>? <complex-selector>" }, "relative-selector-list": { syntax: "<relative-selector>#" }, "relative-size": { syntax: "larger | smaller" }, "repeat-style": { syntax: "repeat-x | repeat-y | [ repeat | space | round | no-repeat ]{1,2}" }, "repeating-linear-gradient()": { syntax: "repeating-linear-gradient( [ <angle> | to <side-or-corner> ]? , <color-stop-list> )" }, "repeating-radial-gradient()": { syntax: "repeating-radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )" }, "rgb()": { syntax: "rgb( <percentage>{3} [ / <alpha-value> ]? ) | rgb( <number>{3} [ / <alpha-value> ]? ) | rgb( <percentage>#{3} , <alpha-value>? ) | rgb( <number>#{3} , <alpha-value>? )" }, "rgba()": { syntax: "rgba( <percentage>{3} [ / <alpha-value> ]? ) | rgba( <number>{3} [ / <alpha-value> ]? ) | rgba( <percentage>#{3} , <alpha-value>? ) | rgba( <number>#{3} , <alpha-value>? )" }, "rotate()": { syntax: "rotate( [ <angle> | <zero> ] )" }, "rotate3d()": { syntax: "rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )" }, "rotateX()": { syntax: "rotateX( [ <angle> | <zero> ] )" }, "rotateY()": { syntax: "rotateY( [ <angle> | <zero> ] )" }, "rotateZ()": { syntax: "rotateZ( [ <angle> | <zero> ] )" }, "saturate()": { syntax: "saturate( <number-percentage> )" }, "scale()": { syntax: "scale( <number> , <number>? )" }, "scale3d()": { syntax: "scale3d( <number> , <number> , <number> )" }, "scaleX()": { syntax: "scaleX( <number> )" }, "scaleY()": { syntax: "scaleY( <number> )" }, "scaleZ()": { syntax: "scaleZ( <number> )" }, "self-position": { syntax: "center | start | end | self-start | self-end | flex-start | flex-end" }, "shape-radius": { syntax: "<length-percentage> | closest-side | farthest-side" }, "skew()": { syntax: "skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )" }, "skewX()": { syntax: "skewX( [ <angle> | <zero> ] )" }, "skewY()": { syntax: "skewY( [ <angle> | <zero> ] )" }, "sepia()": { syntax: "sepia( <number-percentage> )" }, shadow: shadow, "shadow-t": { syntax: "[ <length>{2,3} && <color>? ]" }, shape: shape$1, "shape-box": { syntax: "<box> | margin-box" }, "side-or-corner": { syntax: "[ left | right ] || [ top | bottom ]" }, "single-animation": { syntax: "<time> || <timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ]" }, "single-animation-direction": { syntax: "normal | reverse | alternate | alternate-reverse" }, "single-animation-fill-mode": { syntax: "none | forwards | backwards | both" }, "single-animation-iteration-count": { syntax: "infinite | <number>" }, "single-animation-play-state": { syntax: "running | paused" }, "single-transition": { syntax: "[ none | <single-transition-property> ] || <time> || <timing-function> || <time>" }, "single-transition-property": { syntax: "all | <custom-ident>" }, size: size, "step-position": { syntax: "jump-start | jump-end | jump-none | jump-both | start | end" }, "step-timing-function": { syntax: "step-start | step-end | steps(<integer>[, <step-position>]?)" }, "subclass-selector": { syntax: "<id-selector> | <class-selector> | <attribute-selector> | <pseudo-class-selector>" }, "supports-condition": { syntax: "not <supports-in-parens> | <supports-in-parens> [ and <supports-in-parens> ]* | <supports-in-parens> [ or <supports-in-parens> ]*" }, "supports-in-parens": { syntax: "( <supports-condition> ) | <supports-feature> | <general-enclosed>" }, "supports-feature": { syntax: "<supports-decl> | <supports-selector-fn>" }, "supports-decl": { syntax: "( <declaration> )" }, "supports-selector-fn": { syntax: "selector( <complex-selector> )" }, symbol: symbol, target: target, "target-counter()": { syntax: "target-counter( [ <string> | <url> ] , <custom-ident> , <counter-style>? )" }, "target-counters()": { syntax: "target-counters( [ <string> | <url> ] , <custom-ident> , <string> , <counter-style>? )" }, "target-text()": { syntax: "target-text( [ <string> | <url> ] , [ content | before | after | first-letter ]? )" }, "time-percentage": { syntax: "<time> | <percentage>" }, "timing-function": { syntax: "linear | <cubic-bezier-timing-function> | <step-timing-function>" }, "track-breadth": { syntax: "<length-percentage> | <flex> | min-content | max-content | auto" }, "track-list": { syntax: "[ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?" }, "track-repeat": { syntax: "repeat( [ <positive-integer> ] , [ <line-names>? <track-size> ]+ <line-names>? )" }, "track-size": { syntax: "<track-breadth> | minmax( <inflexible-breadth> , <track-breadth> ) | fit-content( [ <length> | <percentage> ] )" }, "transform-function": { syntax: "<matrix()> | <translate()> | <translateX()> | <translateY()> | <scale()> | <scaleX()> | <scaleY()> | <rotate()> | <skew()> | <skewX()> | <skewY()> | <matrix3d()> | <translate3d()> | <translateZ()> | <scale3d()> | <scaleZ()> | <rotate3d()> | <rotateX()> | <rotateY()> | <rotateZ()> | <perspective()>" }, "transform-list": { syntax: "<transform-function>+" }, "translate()": { syntax: "translate( <length-percentage> , <length-percentage>? )" }, "translate3d()": { syntax: "translate3d( <length-percentage> , <length-percentage> , <length> )" }, "translateX()": { syntax: "translateX( <length-percentage> )" }, "translateY()": { syntax: "translateY( <length-percentage> )" }, "translateZ()": { syntax: "translateZ( <length> )" }, "type-or-unit": { syntax: "string | color | url | integer | number | length | angle | time | frequency | cap | ch | em | ex | ic | lh | rlh | rem | vb | vi | vw | vh | vmin | vmax | mm | Q | cm | in | pt | pc | px | deg | grad | rad | turn | ms | s | Hz | kHz | %" }, "type-selector": { syntax: "<wq-name> | <ns-prefix>? '*'" }, "var()": { syntax: "var( <custom-property-name> , <declaration-value>? )" }, "viewport-length": { syntax: "auto | <length-percentage>" }, "wq-name": { syntax: "<ns-prefix>? <ident-token>" } }; var syntaxes$1 = /*#__PURE__*/Object.freeze({ __proto__: null, attachment: attachment, box: box, color: color$1, combinator: combinator, compat: compat, gradient: gradient, hue: hue, image: image, nth: nth, position: position$1, quote: quote, shadow: shadow, shape: shape$1, size: size, symbol: symbol, target: target, 'default': syntaxes }); var properties$3 = { "-moz-background-clip": { comment: "deprecated syntax in old Firefox, https://developer.mozilla.org/en/docs/Web/CSS/background-clip", syntax: "padding | border" }, "-moz-border-radius-bottomleft": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-left-radius", syntax: "<'border-bottom-left-radius'>" }, "-moz-border-radius-bottomright": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius", syntax: "<'border-bottom-right-radius'>" }, "-moz-border-radius-topleft": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-left-radius", syntax: "<'border-top-left-radius'>" }, "-moz-border-radius-topright": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius", syntax: "<'border-bottom-right-radius'>" }, "-moz-control-character-visibility": { comment: "firefox specific keywords, https://bugzilla.mozilla.org/show_bug.cgi?id=947588", syntax: "visible | hidden" }, "-moz-osx-font-smoothing": { comment: "misssed old syntax https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth", syntax: "auto | grayscale" }, "-moz-user-select": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/user-select", syntax: "none | text | all | -moz-none" }, "-ms-flex-align": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align", syntax: "start | end | center | baseline | stretch" }, "-ms-flex-item-align": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align", syntax: "auto | start | end | center | baseline | stretch" }, "-ms-flex-line-pack": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack", syntax: "start | end | center | justify | distribute | stretch" }, "-ms-flex-negative": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-shrink'>" }, "-ms-flex-pack": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack", syntax: "start | end | center | justify | distribute" }, "-ms-flex-order": { comment: "misssed old syntax implemented in IE; https://msdn.microsoft.com/en-us/library/jj127303(v=vs.85).aspx", syntax: "<integer>" }, "-ms-flex-positive": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-grow'>" }, "-ms-flex-preferred-size": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-basis'>" }, "-ms-interpolation-mode": { comment: "https://msdn.microsoft.com/en-us/library/ff521095(v=vs.85).aspx", syntax: "nearest-neighbor | bicubic" }, "-ms-grid-column-align": { comment: "add this property first since it uses as fallback for flexbox, https://msdn.microsoft.com/en-us/library/windows/apps/hh466338.aspx", syntax: "start | end | center | stretch" }, "-ms-grid-columns": { comment: "misssed old syntax implemented in IE; https://www.w3.org/TR/2012/WD-css3-grid-layout-20120322/#grid-columns", syntax: "<track-list-v0>" }, "-ms-grid-row-align": { comment: "add this property first since it uses as fallback for flexbox, https://msdn.microsoft.com/en-us/library/windows/apps/hh466348.aspx", syntax: "start | end | center | stretch" }, "-ms-grid-rows": { comment: "misssed old syntax implemented in IE; https://www.w3.org/TR/2012/WD-css3-grid-layout-20120322/#grid-rows", syntax: "<track-list-v0>" }, "-ms-hyphenate-limit-last": { comment: "misssed old syntax implemented in IE; https://www.w3.org/TR/css-text-4/#hyphenate-line-limits", syntax: "none | always | column | page | spread" }, "-webkit-appearance": { comment: "webkit specific keywords", references: [ "http://css-infos.net/property/-webkit-appearance" ], syntax: "none | button | button-bevel | caps-lock-indicator | caret | checkbox | default-button | listbox | listitem | media-fullscreen-button | media-mute-button | media-play-button | media-seek-back-button | media-seek-forward-button | media-slider | media-sliderthumb | menulist | menulist-button | menulist-text | menulist-textfield | push-button | radio | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbargripper-horizontal | scrollbargripper-vertical | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical | searchfield | searchfield-cancel-button | searchfield-decoration | searchfield-results-button | searchfield-results-decoration | slider-horizontal | slider-vertical | sliderthumb-horizontal | sliderthumb-vertical | square-button | textarea | textfield" }, "-webkit-background-clip": { comment: "https://developer.mozilla.org/en/docs/Web/CSS/background-clip", syntax: "[ <box> | border | padding | content | text ]#" }, "-webkit-column-break-after": { comment: "added, http://help.dottoro.com/lcrthhhv.php", syntax: "always | auto | avoid" }, "-webkit-column-break-before": { comment: "added, http://help.dottoro.com/lcxquvkf.php", syntax: "always | auto | avoid" }, "-webkit-column-break-inside": { comment: "added, http://help.dottoro.com/lclhnthl.php", syntax: "always | auto | avoid" }, "-webkit-font-smoothing": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth", syntax: "auto | none | antialiased | subpixel-antialiased" }, "-webkit-mask-box-image": { comment: "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-box-image", syntax: "[ <url> | <gradient> | none ] [ <length-percentage>{4} <-webkit-mask-box-repeat>{2} ]?" }, "-webkit-print-color-adjust": { comment: "missed", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/-webkit-print-color-adjust" ], syntax: "economy | exact" }, "-webkit-text-security": { comment: "missed; http://help.dottoro.com/lcbkewgt.php", syntax: "none | circle | disc | square" }, "-webkit-user-drag": { comment: "missed; http://help.dottoro.com/lcbixvwm.php", syntax: "none | element | auto" }, "-webkit-user-select": { comment: "auto is supported by old webkit, https://developer.mozilla.org/en-US/docs/Web/CSS/user-select", syntax: "auto | none | text | all" }, "alignment-baseline": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#AlignmentBaselineProperty" ], syntax: "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical" }, "baseline-shift": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#BaselineShiftProperty" ], syntax: "baseline | sub | super | <svg-length>" }, behavior: { comment: "added old IE property https://msdn.microsoft.com/en-us/library/ms530723(v=vs.85).aspx", syntax: "<url>+" }, "clip-rule": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/masking.html#ClipRuleProperty" ], syntax: "nonzero | evenodd" }, cue: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'cue-before'> <'cue-after'>?" }, "cue-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<url> <decibel>? | none" }, "cue-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<url> <decibel>? | none" }, cursor: { comment: "added legacy keywords: hand, -webkit-grab. -webkit-grabbing, -webkit-zoom-in, -webkit-zoom-out, -moz-grab, -moz-grabbing, -moz-zoom-in, -moz-zoom-out", references: [ "https://www.sitepoint.com/css3-cursor-styles/" ], syntax: "[ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]" }, display: { comment: "extended with -ms-flexbox", syntax: "block | contents | flex | flow | flow-root | grid | inline | inline-block | inline-flex | inline-grid | inline-list-item | inline-table | list-item | none | ruby | ruby-base | ruby-base-container | ruby-text | ruby-text-container | run-in | table | table-caption | table-cell | table-column | table-column-group | table-footer-group | table-header-group | table-row | table-row-group | -ms-flexbox | -ms-inline-flexbox | -ms-grid | -ms-inline-grid | -webkit-flex | -webkit-inline-flex | -webkit-box | -webkit-inline-box | -moz-inline-stack | -moz-box | -moz-inline-box" }, position: { comment: "extended with -webkit-sticky", syntax: "static | relative | absolute | sticky | fixed | -webkit-sticky" }, "dominant-baseline": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#DominantBaselineProperty" ], syntax: "auto | use-script | no-change | reset-size | ideographic | alphabetic | hanging | mathematical | central | middle | text-after-edge | text-before-edge" }, "image-rendering": { comment: "extended with <-non-standard-image-rendering>, added SVG keywords optimizeSpeed and optimizeQuality", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/image-rendering", "https://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty" ], syntax: "auto | crisp-edges | pixelated | optimizeSpeed | optimizeQuality | <-non-standard-image-rendering>" }, fill: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "<paint>" }, "fill-opacity": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "<number-zero-one>" }, "fill-rule": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "nonzero | evenodd" }, filter: { comment: "extend with IE legacy syntaxes", syntax: "none | <filter-function-list> | <-ms-filter-function-list>" }, "glyph-orientation-horizontal": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#GlyphOrientationHorizontalProperty" ], syntax: "<angle>" }, "glyph-orientation-vertical": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#GlyphOrientationVerticalProperty" ], syntax: "<angle>" }, kerning: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#KerningProperty" ], syntax: "auto | <svg-length>" }, "letter-spacing": { comment: "fix syntax <length> -> <length-percentage>", references: [ "https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing" ], syntax: "normal | <length-percentage>" }, marker: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-end": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-mid": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-start": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "max-width": { comment: "extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/max-width", syntax: "<length> | <percentage> | none | max-content | min-content | fit-content | fill-available | <-non-standard-width>" }, "min-width": { comment: "extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width", syntax: "<length> | <percentage> | auto | max-content | min-content | fit-content | fill-available | <-non-standard-width>" }, opacity: { comment: "strict to 0..1 <number> -> <number-zero-one>", syntax: "<number-zero-one>" }, overflow: { comment: "extend by vendor keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow", syntax: "[ visible | hidden | clip | scroll | auto ]{1,2} | <-non-standard-overflow>" }, pause: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'pause-before'> <'pause-after'>?" }, "pause-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "pause-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, rest: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'rest-before'> <'rest-after'>?" }, "rest-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "rest-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "shape-rendering": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#ShapeRenderingPropert" ], syntax: "auto | optimizeSpeed | crispEdges | geometricPrecision" }, src: { comment: "added @font-face's src property https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src", syntax: "[ <url> [ format( <string># ) ]? | local( <family-name> ) ]#" }, speak: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "auto | none | normal" }, "speak-as": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "normal | spell-out || digits || [ literal-punctuation | no-punctuation ]" }, stroke: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<paint>" }, "stroke-dasharray": { comment: "added SVG property; a list of comma and/or white space separated <length>s and <percentage>s", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "none | [ <svg-length>+ ]#" }, "stroke-dashoffset": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<svg-length>" }, "stroke-linecap": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "butt | round | square" }, "stroke-linejoin": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "miter | round | bevel" }, "stroke-miterlimit": { comment: "added SVG property (<miterlimit> = <number-one-or-greater>) ", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<number-one-or-greater>" }, "stroke-opacity": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<number-zero-one>" }, "stroke-width": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<svg-length>" }, "text-anchor": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#TextAlignmentProperties" ], syntax: "start | middle | end" }, "unicode-bidi": { comment: "added prefixed keywords https://developer.mozilla.org/en-US/docs/Web/CSS/unicode-bidi", syntax: "normal | embed | isolate | bidi-override | isolate-override | plaintext | -moz-isolate | -moz-isolate-override | -moz-plaintext | -webkit-isolate" }, "unicode-range": { comment: "added missed property https://developer.mozilla.org/en-US/docs/Web/CSS/%40font-face/unicode-range", syntax: "<urange>#" }, "voice-balance": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<number> | left | center | right | leftwards | rightwards" }, "voice-duration": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "auto | <time>" }, "voice-family": { comment: "<name> -> <family-name>, https://www.w3.org/TR/css3-speech/#property-index", syntax: "[ [ <family-name> | <generic-voice> ] , ]* [ <family-name> | <generic-voice> ] | preserve" }, "voice-pitch": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<frequency> && absolute | [ [ x-low | low | medium | high | x-high ] || [ <frequency> | <semitones> | <percentage> ] ]" }, "voice-range": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<frequency> && absolute | [ [ x-low | low | medium | high | x-high ] || [ <frequency> | <semitones> | <percentage> ] ]" }, "voice-rate": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "[ normal | x-slow | slow | medium | fast | x-fast ] || <percentage>" }, "voice-stress": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "normal | strong | moderate | none | reduced" }, "voice-volume": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "silent | [ [ x-soft | soft | medium | loud | x-loud ] || <decibel> ]" }, "writing-mode": { comment: "extend with SVG keywords", syntax: "horizontal-tb | vertical-rl | vertical-lr | sideways-rl | sideways-lr | <svg-writing-mode>" } }; var syntaxes$2 = { "-legacy-gradient": { comment: "added collection of legacy gradient syntaxes", syntax: "<-webkit-gradient()> | <-legacy-linear-gradient> | <-legacy-repeating-linear-gradient> | <-legacy-radial-gradient> | <-legacy-repeating-radial-gradient>" }, "-legacy-linear-gradient": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "-moz-linear-gradient( <-legacy-linear-gradient-arguments> ) | -webkit-linear-gradient( <-legacy-linear-gradient-arguments> ) | -o-linear-gradient( <-legacy-linear-gradient-arguments> )" }, "-legacy-repeating-linear-gradient": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "-moz-repeating-linear-gradient( <-legacy-linear-gradient-arguments> ) | -webkit-repeating-linear-gradient( <-legacy-linear-gradient-arguments> ) | -o-repeating-linear-gradient( <-legacy-linear-gradient-arguments> )" }, "-legacy-linear-gradient-arguments": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "[ <angle> | <side-or-corner> ]? , <color-stop-list>" }, "-legacy-radial-gradient": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "-moz-radial-gradient( <-legacy-radial-gradient-arguments> ) | -webkit-radial-gradient( <-legacy-radial-gradient-arguments> ) | -o-radial-gradient( <-legacy-radial-gradient-arguments> )" }, "-legacy-repeating-radial-gradient": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "-moz-repeating-radial-gradient( <-legacy-radial-gradient-arguments> ) | -webkit-repeating-radial-gradient( <-legacy-radial-gradient-arguments> ) | -o-repeating-radial-gradient( <-legacy-radial-gradient-arguments> )" }, "-legacy-radial-gradient-arguments": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "[ <position> , ]? [ [ [ <-legacy-radial-gradient-shape> || <-legacy-radial-gradient-size> ] | [ <length> | <percentage> ]{2} ] , ]? <color-stop-list>" }, "-legacy-radial-gradient-size": { comment: "before a standard it contains 2 extra keywords (`contain` and `cover`) https://www.w3.org/TR/2011/WD-css3-images-20110908/#ltsize", syntax: "closest-side | closest-corner | farthest-side | farthest-corner | contain | cover" }, "-legacy-radial-gradient-shape": { comment: "define to double sure it doesn't extends in future https://www.w3.org/TR/2011/WD-css3-images-20110908/#ltshape", syntax: "circle | ellipse" }, "-non-standard-font": { comment: "non standard fonts", references: [ "https://webkit.org/blog/3709/using-the-system-font-in-web-content/" ], syntax: "-apple-system-body | -apple-system-headline | -apple-system-subheadline | -apple-system-caption1 | -apple-system-caption2 | -apple-system-footnote | -apple-system-short-body | -apple-system-short-headline | -apple-system-short-subheadline | -apple-system-short-caption1 | -apple-system-short-footnote | -apple-system-tall-body" }, "-non-standard-color": { comment: "non standard colors", references: [ "http://cssdot.ru/%D0%A1%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%87%D0%BD%D0%B8%D0%BA_CSS/color-i305.html", "https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Mozilla_Color_Preference_Extensions" ], syntax: "-moz-ButtonDefault | -moz-ButtonHoverFace | -moz-ButtonHoverText | -moz-CellHighlight | -moz-CellHighlightText | -moz-Combobox | -moz-ComboboxText | -moz-Dialog | -moz-DialogText | -moz-dragtargetzone | -moz-EvenTreeRow | -moz-Field | -moz-FieldText | -moz-html-CellHighlight | -moz-html-CellHighlightText | -moz-mac-accentdarkestshadow | -moz-mac-accentdarkshadow | -moz-mac-accentface | -moz-mac-accentlightesthighlight | -moz-mac-accentlightshadow | -moz-mac-accentregularhighlight | -moz-mac-accentregularshadow | -moz-mac-chrome-active | -moz-mac-chrome-inactive | -moz-mac-focusring | -moz-mac-menuselect | -moz-mac-menushadow | -moz-mac-menutextselect | -moz-MenuHover | -moz-MenuHoverText | -moz-MenuBarText | -moz-MenuBarHoverText | -moz-nativehyperlinktext | -moz-OddTreeRow | -moz-win-communicationstext | -moz-win-mediatext | -moz-activehyperlinktext | -moz-default-background-color | -moz-default-color | -moz-hyperlinktext | -moz-visitedhyperlinktext | -webkit-activelink | -webkit-focus-ring-color | -webkit-link | -webkit-text" }, "-non-standard-image-rendering": { comment: "non-standard keywords http://phrogz.net/tmp/canvas_image_zoom.html", syntax: "optimize-contrast | -moz-crisp-edges | -o-crisp-edges | -webkit-optimize-contrast" }, "-non-standard-overflow": { comment: "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow", syntax: "-moz-scrollbars-none | -moz-scrollbars-horizontal | -moz-scrollbars-vertical | -moz-hidden-unscrollable" }, "-non-standard-width": { comment: "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width", syntax: "min-intrinsic | intrinsic | -moz-min-content | -moz-max-content | -webkit-min-content | -webkit-max-content" }, "-webkit-gradient()": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/ - TODO: simplify when after match algorithm improvement ( [, point, radius | , point] -> [, radius]? , point )", syntax: "-webkit-gradient( <-webkit-gradient-type>, <-webkit-gradient-point> [, <-webkit-gradient-point> | , <-webkit-gradient-radius>, <-webkit-gradient-point> ] [, <-webkit-gradient-radius>]? [, <-webkit-gradient-color-stop>]* )" }, "-webkit-gradient-color-stop": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "from( <color> ) | color-stop( [ <number-zero-one> | <percentage> ] , <color> ) | to( <color> )" }, "-webkit-gradient-point": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "[ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]" }, "-webkit-gradient-radius": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "<length> | <percentage>" }, "-webkit-gradient-type": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "linear | radial" }, "-webkit-mask-box-repeat": { comment: "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-box-image", syntax: "repeat | stretch | round" }, "-webkit-mask-clip-style": { comment: "missed; there is no enough information about `-webkit-mask-clip` property, but looks like all those keywords are working", syntax: "border | border-box | padding | padding-box | content | content-box | text" }, "-ms-filter-function-list": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<-ms-filter-function>+" }, "-ms-filter-function": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<-ms-filter-function-progid> | <-ms-filter-function-legacy>" }, "-ms-filter-function-progid": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "'progid:' [ <ident-token> '.' ]* [ <ident-token> | <function-token> <any-value>? ) ]" }, "-ms-filter-function-legacy": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<ident-token> | <function-token> <any-value>? )" }, "-ms-filter": { syntax: "<string>" }, age: { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "child | young | old" }, "attr-name": { syntax: "<wq-name>" }, "attr-fallback": { syntax: "<any-value>" }, "border-radius": { comment: "missed, https://drafts.csswg.org/css-backgrounds-3/#the-border-radius", syntax: "<length-percentage>{1,2}" }, bottom: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "content-list": { comment: "missed -> https://drafts.csswg.org/css-content/#typedef-content-list (document-url, <target> and leader() is omitted util stabilization)", syntax: "[ <string> | contents | <url> | <quote> | <attr()> | counter( <ident>, <'list-style-type'>? ) ]+" }, "generic-voice": { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "[ <age>? <gender> <integer>? ]" }, gender: { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "male | female | neutral" }, "generic-family": { comment: "added -apple-system", references: [ "https://webkit.org/blog/3709/using-the-system-font-in-web-content/" ], syntax: "serif | sans-serif | cursive | fantasy | monospace | -apple-system" }, gradient: { comment: "added legacy syntaxes support", syntax: "<linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()> | <conic-gradient()> | <-legacy-gradient>" }, left: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "mask-image": { comment: "missed; https://drafts.fxtf.org/css-masking-1/#the-mask-image", syntax: "<mask-reference>#" }, "name-repeat": { comment: "missed, and looks like obsolete, keep it as is since other property syntaxes should be changed too; https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-name-repeat", syntax: "repeat( [ <positive-integer> | auto-fill ], <line-names>+)" }, "named-color": { comment: "added non standard color names", syntax: "transparent | aliceblue | antiquewhite | aqua | aquamarine | azure | beige | bisque | black | blanchedalmond | blue | blueviolet | brown | burlywood | cadetblue | chartreuse | chocolate | coral | cornflowerblue | cornsilk | crimson | cyan | darkblue | darkcyan | darkgoldenrod | darkgray | darkgreen | darkgrey | darkkhaki | darkmagenta | darkolivegreen | darkorange | darkorchid | darkred | darksalmon | darkseagreen | darkslateblue | darkslategray | darkslategrey | darkturquoise | darkviolet | deeppink | deepskyblue | dimgray | dimgrey | dodgerblue | firebrick | floralwhite | forestgreen | fuchsia | gainsboro | ghostwhite | gold | goldenrod | gray | green | greenyellow | grey | honeydew | hotpink | indianred | indigo | ivory | khaki | lavender | lavenderblush | lawngreen | lemonchiffon | lightblue | lightcoral | lightcyan | lightgoldenrodyellow | lightgray | lightgreen | lightgrey | lightpink | lightsalmon | lightseagreen | lightskyblue | lightslategray | lightslategrey | lightsteelblue | lightyellow | lime | limegreen | linen | magenta | maroon | mediumaquamarine | mediumblue | mediumorchid | mediumpurple | mediumseagreen | mediumslateblue | mediumspringgreen | mediumturquoise | mediumvioletred | midnightblue | mintcream | mistyrose | moccasin | navajowhite | navy | oldlace | olive | olivedrab | orange | orangered | orchid | palegoldenrod | palegreen | paleturquoise | palevioletred | papayawhip | peachpuff | peru | pink | plum | powderblue | purple | rebeccapurple | red | rosybrown | royalblue | saddlebrown | salmon | sandybrown | seagreen | seashell | sienna | silver | skyblue | slateblue | slategray | slategrey | snow | springgreen | steelblue | tan | teal | thistle | tomato | turquoise | violet | wheat | white | whitesmoke | yellow | yellowgreen | <-non-standard-color>" }, paint: { comment: "used by SVG https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint", syntax: "none | <color> | <url> [ none | <color> ]? | context-fill | context-stroke" }, "path()": { comment: "missed, `motion` property was renamed, but left it as is for now; path() syntax was get from last draft https://drafts.fxtf.org/motion-1/#funcdef-offset-path-path", syntax: "path( <string> )" }, ratio: { comment: "missed, https://drafts.csswg.org/mediaqueries-4/#typedef-ratio", syntax: "<integer> / <integer>" }, right: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, shape: { comment: "missed spaces in function body and add backwards compatible syntax", syntax: "rect( <top>, <right>, <bottom>, <left> ) | rect( <top> <right> <bottom> <left> )" }, "svg-length": { comment: "All coordinates and lengths in SVG can be specified with or without a unit identifier", references: [ "https://www.w3.org/TR/SVG11/coords.html#Units" ], syntax: "<percentage> | <length> | <number>" }, "svg-writing-mode": { comment: "SVG specific keywords (deprecated for CSS)", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/writing-mode", "https://www.w3.org/TR/SVG/text.html#WritingModeProperty" ], syntax: "lr-tb | rl-tb | tb-rl | lr | rl | tb" }, top: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "track-group": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "'(' [ <string>* <track-minmax> <string>* ]+ ')' [ '[' <positive-integer> ']' ]? | <track-minmax>" }, "track-list-v0": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "[ <string>* <track-group> <string>* ]+ | none" }, "track-minmax": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "minmax( <track-breadth> , <track-breadth> ) | auto | <track-breadth> | fit-content" }, x: { comment: "missed; not sure we should add it, but no others except `cursor` is using it so it's ok for now; https://drafts.csswg.org/css-ui-3/#cursor", syntax: "<number>" }, y: { comment: "missed; not sure we should add it, but no others except `cursor` is using so it's ok for now; https://drafts.csswg.org/css-ui-3/#cursor", syntax: "<number>" }, declaration: { comment: "missed, restored by https://drafts.csswg.org/css-syntax", syntax: "<ident-token> : <declaration-value>? [ '!' important ]?" }, "declaration-list": { comment: "missed, restored by https://drafts.csswg.org/css-syntax", syntax: "[ <declaration>? ';' ]* <declaration>?" }, url: { comment: "https://drafts.csswg.org/css-values-4/#urls", syntax: "url( <string> <url-modifier>* ) | <url-token>" }, "url-modifier": { comment: "https://drafts.csswg.org/css-values-4/#typedef-url-modifier", syntax: "<ident> | <function-token> <any-value> )" }, "number-zero-one": { syntax: "<number [0,1]>" }, "number-one-or-greater": { syntax: "<number [1,∞]>" }, "positive-integer": { syntax: "<integer [0,∞]>" } }; var patch = { properties: properties$3, syntaxes: syntaxes$2 }; var patch$1 = /*#__PURE__*/Object.freeze({ __proto__: null, properties: properties$3, syntaxes: syntaxes$2, 'default': patch }); var mdnAtrules = getCjsExportFromNamespace(atRules$1); var mdnProperties = getCjsExportFromNamespace(properties$2); var mdnSyntaxes = getCjsExportFromNamespace(syntaxes$1); var patch$2 = getCjsExportFromNamespace(patch$1); function preprocessAtrules(dict) { var result = Object.create(null); for (var atruleName in dict) { var atrule = dict[atruleName]; var descriptors = null; if (atrule.descriptors) { descriptors = Object.create(null); for (var descriptor in atrule.descriptors) { descriptors[descriptor] = atrule.descriptors[descriptor].syntax; } } result[atruleName.substr(1)] = { prelude: atrule.syntax.trim().match(/^@\S+\s+([^;\{]*)/)[1].trim() || null, descriptors }; } return result; } function buildDictionary(dict, patchDict) { var result = {}; // copy all syntaxes for an original dict for (var key in dict) { result[key] = dict[key].syntax; } // apply a patch for (var key in patchDict) { if (key in dict) { if (patchDict[key].syntax) { result[key] = patchDict[key].syntax; } else { delete result[key]; } } else { if (patchDict[key].syntax) { result[key] = patchDict[key].syntax; } } } return result; } var data = { types: buildDictionary(mdnSyntaxes, patch$2.syntaxes), atrules: preprocessAtrules(mdnAtrules), properties: buildDictionary(mdnProperties, patch$2.properties) }; var cmpChar$3 = tokenizer.cmpChar; var isDigit$4 = tokenizer.isDigit; var TYPE$9 = tokenizer.TYPE; var WHITESPACE$4 = TYPE$9.WhiteSpace; var COMMENT$3 = TYPE$9.Comment; var IDENT$3 = TYPE$9.Ident; var NUMBER$3 = TYPE$9.Number; var DIMENSION$2 = TYPE$9.Dimension; var PLUSSIGN$3 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$3 = 0x002D; // U+002D HYPHEN-MINUS (-) var N$4 = 0x006E; // U+006E LATIN SMALL LETTER N (n) var DISALLOW_SIGN$1 = true; var ALLOW_SIGN$1 = false; function checkInteger$1(offset, disallowSign) { var pos = this.scanner.tokenStart + offset; var code = this.scanner.source.charCodeAt(pos); if (code === PLUSSIGN$3 || code === HYPHENMINUS$3) { if (disallowSign) { this.error('Number sign is not allowed'); } pos++; } for (; pos < this.scanner.tokenEnd; pos++) { if (!isDigit$4(this.scanner.source.charCodeAt(pos))) { this.error('Integer is expected', pos); } } } function checkTokenIsInteger(disallowSign) { return checkInteger$1.call(this, 0, disallowSign); } function expectCharCode(offset, code) { if (!cmpChar$3(this.scanner.source, this.scanner.tokenStart + offset, code)) { var msg = ''; switch (code) { case N$4: msg = 'N is expected'; break; case HYPHENMINUS$3: msg = 'HyphenMinus is expected'; break; } this.error(msg, this.scanner.tokenStart + offset); } } // ... <signed-integer> // ... ['+' | '-'] <signless-integer> function consumeB$1() { var offset = 0; var sign = 0; var type = this.scanner.tokenType; while (type === WHITESPACE$4 || type === COMMENT$3) { type = this.scanner.lookupType(++offset); } if (type !== NUMBER$3) { if (this.scanner.isDelim(PLUSSIGN$3, offset) || this.scanner.isDelim(HYPHENMINUS$3, offset)) { sign = this.scanner.isDelim(PLUSSIGN$3, offset) ? PLUSSIGN$3 : HYPHENMINUS$3; do { type = this.scanner.lookupType(++offset); } while (type === WHITESPACE$4 || type === COMMENT$3); if (type !== NUMBER$3) { this.scanner.skip(offset); checkTokenIsInteger.call(this, DISALLOW_SIGN$1); } } else { return null; } } if (offset > 0) { this.scanner.skip(offset); } if (sign === 0) { type = this.scanner.source.charCodeAt(this.scanner.tokenStart); if (type !== PLUSSIGN$3 && type !== HYPHENMINUS$3) { this.error('Number sign is expected'); } } checkTokenIsInteger.call(this, sign !== 0); return sign === HYPHENMINUS$3 ? '-' + this.consume(NUMBER$3) : this.consume(NUMBER$3); } // An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb var AnPlusB = { name: 'AnPlusB', structure: { a: [String, null], b: [String, null] }, parse: function() { /* eslint-disable brace-style*/ var start = this.scanner.tokenStart; var a = null; var b = null; // <integer> if (this.scanner.tokenType === NUMBER$3) { checkTokenIsInteger.call(this, ALLOW_SIGN$1); b = this.consume(NUMBER$3); } // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> // -n- <signless-integer> // <dashndashdigit-ident> else if (this.scanner.tokenType === IDENT$3 && cmpChar$3(this.scanner.source, this.scanner.tokenStart, HYPHENMINUS$3)) { a = '-1'; expectCharCode.call(this, 1, N$4); switch (this.scanner.getTokenLength()) { // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> case 2: this.scanner.next(); b = consumeB$1.call(this); break; // -n- <signless-integer> case 3: expectCharCode.call(this, 2, HYPHENMINUS$3); this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN$1); b = '-' + this.consume(NUMBER$3); break; // <dashndashdigit-ident> default: expectCharCode.call(this, 2, HYPHENMINUS$3); checkInteger$1.call(this, 3, DISALLOW_SIGN$1); this.scanner.next(); b = this.scanner.substrToCursor(start + 2); } } // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> // '+'? n- <signless-integer> // '+'? <ndashdigit-ident> else if (this.scanner.tokenType === IDENT$3 || (this.scanner.isDelim(PLUSSIGN$3) && this.scanner.lookupType(1) === IDENT$3)) { var sign = 0; a = '1'; // just ignore a plus if (this.scanner.isDelim(PLUSSIGN$3)) { sign = 1; this.scanner.next(); } expectCharCode.call(this, 0, N$4); switch (this.scanner.getTokenLength()) { // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> case 1: this.scanner.next(); b = consumeB$1.call(this); break; // '+'? n- <signless-integer> case 2: expectCharCode.call(this, 1, HYPHENMINUS$3); this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN$1); b = '-' + this.consume(NUMBER$3); break; // '+'? <ndashdigit-ident> default: expectCharCode.call(this, 1, HYPHENMINUS$3); checkInteger$1.call(this, 2, DISALLOW_SIGN$1); this.scanner.next(); b = this.scanner.substrToCursor(start + sign + 1); } } // <ndashdigit-dimension> // <ndash-dimension> <signless-integer> // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> else if (this.scanner.tokenType === DIMENSION$2) { var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); var sign = code === PLUSSIGN$3 || code === HYPHENMINUS$3; for (var i = this.scanner.tokenStart + sign; i < this.scanner.tokenEnd; i++) { if (!isDigit$4(this.scanner.source.charCodeAt(i))) { break; } } if (i === this.scanner.tokenStart + sign) { this.error('Integer is expected', this.scanner.tokenStart + sign); } expectCharCode.call(this, i - this.scanner.tokenStart, N$4); a = this.scanner.source.substring(start, i); // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> if (i + 1 === this.scanner.tokenEnd) { this.scanner.next(); b = consumeB$1.call(this); } else { expectCharCode.call(this, i - this.scanner.tokenStart + 1, HYPHENMINUS$3); // <ndash-dimension> <signless-integer> if (i + 2 === this.scanner.tokenEnd) { this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN$1); b = '-' + this.consume(NUMBER$3); } // <ndashdigit-dimension> else { checkInteger$1.call(this, i - this.scanner.tokenStart + 2, DISALLOW_SIGN$1); this.scanner.next(); b = this.scanner.substrToCursor(i + 1); } } } else { this.error(); } if (a !== null && a.charCodeAt(0) === PLUSSIGN$3) { a = a.substr(1); } if (b !== null && b.charCodeAt(0) === PLUSSIGN$3) { b = b.substr(1); } return { type: 'AnPlusB', loc: this.getLocation(start, this.scanner.tokenStart), a: a, b: b }; }, generate: function(node) { var a = node.a !== null && node.a !== undefined; var b = node.b !== null && node.b !== undefined; if (a) { this.chunk( node.a === '+1' ? '+n' : // eslint-disable-line operator-linebreak, indent node.a === '1' ? 'n' : // eslint-disable-line operator-linebreak, indent node.a === '-1' ? '-n' : // eslint-disable-line operator-linebreak, indent node.a + 'n' // eslint-disable-line operator-linebreak, indent ); if (b) { b = String(node.b); if (b.charAt(0) === '-' || b.charAt(0) === '+') { this.chunk(b.charAt(0)); this.chunk(b.substr(1)); } else { this.chunk('+'); this.chunk(b); } } } else { this.chunk(String(node.b)); } } }; var TYPE$a = tokenizer.TYPE; var WhiteSpace = TYPE$a.WhiteSpace; var Semicolon = TYPE$a.Semicolon; var LeftCurlyBracket = TYPE$a.LeftCurlyBracket; var Delim = TYPE$a.Delim; var EXCLAMATIONMARK$1 = 0x0021; // U+0021 EXCLAMATION MARK (!) function getOffsetExcludeWS() { if (this.scanner.tokenIndex > 0) { if (this.scanner.lookupType(-1) === WhiteSpace) { return this.scanner.tokenIndex > 1 ? this.scanner.getTokenStart(this.scanner.tokenIndex - 1) : this.scanner.firstCharOffset; } } return this.scanner.tokenStart; } // 0, 0, false function balanceEnd() { return 0; } // LEFTCURLYBRACKET, 0, false function leftCurlyBracket(tokenType) { return tokenType === LeftCurlyBracket ? 1 : 0; } // LEFTCURLYBRACKET, SEMICOLON, false function leftCurlyBracketOrSemicolon(tokenType) { return tokenType === LeftCurlyBracket || tokenType === Semicolon ? 1 : 0; } // EXCLAMATIONMARK, SEMICOLON, false function exclamationMarkOrSemicolon(tokenType, source, offset) { if (tokenType === Delim && source.charCodeAt(offset) === EXCLAMATIONMARK$1) { return 1; } return tokenType === Semicolon ? 1 : 0; } // 0, SEMICOLON, true function semicolonIncluded(tokenType) { return tokenType === Semicolon ? 2 : 0; } var Raw = { name: 'Raw', structure: { value: String }, parse: function(startToken, mode, excludeWhiteSpace) { var startOffset = this.scanner.getTokenStart(startToken); var endOffset; this.scanner.skip( this.scanner.getRawLength(startToken, mode || balanceEnd) ); if (excludeWhiteSpace && this.scanner.tokenStart > startOffset) { endOffset = getOffsetExcludeWS.call(this); } else { endOffset = this.scanner.tokenStart; } return { type: 'Raw', loc: this.getLocation(startOffset, endOffset), value: this.scanner.source.substring(startOffset, endOffset) }; }, generate: function(node) { this.chunk(node.value); }, mode: { default: balanceEnd, leftCurlyBracket: leftCurlyBracket, leftCurlyBracketOrSemicolon: leftCurlyBracketOrSemicolon, exclamationMarkOrSemicolon: exclamationMarkOrSemicolon, semicolonIncluded: semicolonIncluded } }; var TYPE$b = tokenizer.TYPE; var rawMode = Raw.mode; var ATKEYWORD = TYPE$b.AtKeyword; var SEMICOLON = TYPE$b.Semicolon; var LEFTCURLYBRACKET$1 = TYPE$b.LeftCurlyBracket; var RIGHTCURLYBRACKET$1 = TYPE$b.RightCurlyBracket; function consumeRaw(startToken) { return this.Raw(startToken, rawMode.leftCurlyBracketOrSemicolon, true); } function isDeclarationBlockAtrule() { for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) { if (type === RIGHTCURLYBRACKET$1) { return true; } if (type === LEFTCURLYBRACKET$1 || type === ATKEYWORD) { return false; } } return false; } var Atrule = { name: 'Atrule', structure: { name: String, prelude: ['AtrulePrelude', 'Raw', null], block: ['Block', null] }, parse: function() { var start = this.scanner.tokenStart; var name; var nameLowerCase; var prelude = null; var block = null; this.eat(ATKEYWORD); name = this.scanner.substrToCursor(start + 1); nameLowerCase = name.toLowerCase(); this.scanner.skipSC(); // parse prelude if (this.scanner.eof === false && this.scanner.tokenType !== LEFTCURLYBRACKET$1 && this.scanner.tokenType !== SEMICOLON) { if (this.parseAtrulePrelude) { prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw); // turn empty AtrulePrelude into null if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) { prelude = null; } } else { prelude = consumeRaw.call(this, this.scanner.tokenIndex); } this.scanner.skipSC(); } switch (this.scanner.tokenType) { case SEMICOLON: this.scanner.next(); break; case LEFTCURLYBRACKET$1: if (this.atrule.hasOwnProperty(nameLowerCase) && typeof this.atrule[nameLowerCase].block === 'function') { block = this.atrule[nameLowerCase].block.call(this); } else { // TODO: should consume block content as Raw? block = this.Block(isDeclarationBlockAtrule.call(this)); } break; } return { type: 'Atrule', loc: this.getLocation(start, this.scanner.tokenStart), name: name, prelude: prelude, block: block }; }, generate: function(node) { this.chunk('@'); this.chunk(node.name); if (node.prelude !== null) { this.chunk(' '); this.node(node.prelude); } if (node.block) { this.node(node.block); } else { this.chunk(';'); } }, walkContext: 'atrule' }; var TYPE$c = tokenizer.TYPE; var SEMICOLON$1 = TYPE$c.Semicolon; var LEFTCURLYBRACKET$2 = TYPE$c.LeftCurlyBracket; var AtrulePrelude = { name: 'AtrulePrelude', structure: { children: [[]] }, parse: function(name) { var children = null; if (name !== null) { name = name.toLowerCase(); } this.scanner.skipSC(); if (this.atrule.hasOwnProperty(name) && typeof this.atrule[name].prelude === 'function') { // custom consumer children = this.atrule[name].prelude.call(this); } else { // default consumer children = this.readSequence(this.scope.AtrulePrelude); } this.scanner.skipSC(); if (this.scanner.eof !== true && this.scanner.tokenType !== LEFTCURLYBRACKET$2 && this.scanner.tokenType !== SEMICOLON$1) { this.error('Semicolon or block is expected'); } if (children === null) { children = this.createList(); } return { type: 'AtrulePrelude', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); }, walkContext: 'atrulePrelude' }; var TYPE$d = tokenizer.TYPE; var IDENT$4 = TYPE$d.Ident; var STRING = TYPE$d.String; var COLON = TYPE$d.Colon; var LEFTSQUAREBRACKET$1 = TYPE$d.LeftSquareBracket; var RIGHTSQUAREBRACKET$1 = TYPE$d.RightSquareBracket; var DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($) var ASTERISK$1 = 0x002A; // U+002A ASTERISK (*) var EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=) var CIRCUMFLEXACCENT = 0x005E; // U+005E (^) var VERTICALLINE$1 = 0x007C; // U+007C VERTICAL LINE (|) var TILDE = 0x007E; // U+007E TILDE (~) function getAttributeName() { if (this.scanner.eof) { this.error('Unexpected end of input'); } var start = this.scanner.tokenStart; var expectIdent = false; var checkColon = true; if (this.scanner.isDelim(ASTERISK$1)) { expectIdent = true; checkColon = false; this.scanner.next(); } else if (!this.scanner.isDelim(VERTICALLINE$1)) { this.eat(IDENT$4); } if (this.scanner.isDelim(VERTICALLINE$1)) { if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 1) !== EQUALSSIGN) { this.scanner.next(); this.eat(IDENT$4); } else if (expectIdent) { this.error('Identifier is expected', this.scanner.tokenEnd); } } else if (expectIdent) { this.error('Vertical line is expected'); } if (checkColon && this.scanner.tokenType === COLON) { this.scanner.next(); this.eat(IDENT$4); } return { type: 'Identifier', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; } function getOperator() { var start = this.scanner.tokenStart; var code = this.scanner.source.charCodeAt(start); if (code !== EQUALSSIGN && // = code !== TILDE && // ~= code !== CIRCUMFLEXACCENT && // ^= code !== DOLLARSIGN && // $= code !== ASTERISK$1 && // *= code !== VERTICALLINE$1 // |= ) { this.error('Attribute selector (=, ~=, ^=, $=, *=, |=) is expected'); } this.scanner.next(); if (code !== EQUALSSIGN) { if (!this.scanner.isDelim(EQUALSSIGN)) { this.error('Equal sign is expected'); } this.scanner.next(); } return this.scanner.substrToCursor(start); } // '[' <wq-name> ']' // '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']' var AttributeSelector = { name: 'AttributeSelector', structure: { name: 'Identifier', matcher: [String, null], value: ['String', 'Identifier', null], flags: [String, null] }, parse: function() { var start = this.scanner.tokenStart; var name; var matcher = null; var value = null; var flags = null; this.eat(LEFTSQUAREBRACKET$1); this.scanner.skipSC(); name = getAttributeName.call(this); this.scanner.skipSC(); if (this.scanner.tokenType !== RIGHTSQUAREBRACKET$1) { // avoid case `[name i]` if (this.scanner.tokenType !== IDENT$4) { matcher = getOperator.call(this); this.scanner.skipSC(); value = this.scanner.tokenType === STRING ? this.String() : this.Identifier(); this.scanner.skipSC(); } // attribute flags if (this.scanner.tokenType === IDENT$4) { flags = this.scanner.getTokenValue(); this.scanner.next(); this.scanner.skipSC(); } } this.eat(RIGHTSQUAREBRACKET$1); return { type: 'AttributeSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, matcher: matcher, value: value, flags: flags }; }, generate: function(node) { var flagsPrefix = ' '; this.chunk('['); this.node(node.name); if (node.matcher !== null) { this.chunk(node.matcher); if (node.value !== null) { this.node(node.value); // space between string and flags is not required if (node.value.type === 'String') { flagsPrefix = ''; } } } if (node.flags !== null) { this.chunk(flagsPrefix); this.chunk(node.flags); } this.chunk(']'); } }; var TYPE$e = tokenizer.TYPE; var rawMode$1 = Raw.mode; var WHITESPACE$5 = TYPE$e.WhiteSpace; var COMMENT$4 = TYPE$e.Comment; var SEMICOLON$2 = TYPE$e.Semicolon; var ATKEYWORD$1 = TYPE$e.AtKeyword; var LEFTCURLYBRACKET$3 = TYPE$e.LeftCurlyBracket; var RIGHTCURLYBRACKET$2 = TYPE$e.RightCurlyBracket; function consumeRaw$1(startToken) { return this.Raw(startToken, null, true); } function consumeRule() { return this.parseWithFallback(this.Rule, consumeRaw$1); } function consumeRawDeclaration(startToken) { return this.Raw(startToken, rawMode$1.semicolonIncluded, true); } function consumeDeclaration() { if (this.scanner.tokenType === SEMICOLON$2) { return consumeRawDeclaration.call(this, this.scanner.tokenIndex); } var node = this.parseWithFallback(this.Declaration, consumeRawDeclaration); if (this.scanner.tokenType === SEMICOLON$2) { this.scanner.next(); } return node; } var Block = { name: 'Block', structure: { children: [[ 'Atrule', 'Rule', 'Declaration' ]] }, parse: function(isDeclaration) { var consumer = isDeclaration ? consumeDeclaration : consumeRule; var start = this.scanner.tokenStart; var children = this.createList(); this.eat(LEFTCURLYBRACKET$3); scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case RIGHTCURLYBRACKET$2: break scan; case WHITESPACE$5: case COMMENT$4: this.scanner.next(); break; case ATKEYWORD$1: children.push(this.parseWithFallback(this.Atrule, consumeRaw$1)); break; default: children.push(consumer.call(this)); } } if (!this.scanner.eof) { this.eat(RIGHTCURLYBRACKET$2); } return { type: 'Block', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('{'); this.children(node, function(prev) { if (prev.type === 'Declaration') { this.chunk(';'); } }); this.chunk('}'); }, walkContext: 'block' }; var TYPE$f = tokenizer.TYPE; var LEFTSQUAREBRACKET$2 = TYPE$f.LeftSquareBracket; var RIGHTSQUAREBRACKET$2 = TYPE$f.RightSquareBracket; var Brackets = { name: 'Brackets', structure: { children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var children = null; this.eat(LEFTSQUAREBRACKET$2); children = readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTSQUAREBRACKET$2); } return { type: 'Brackets', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('['); this.children(node); this.chunk(']'); } }; var CDC = tokenizer.TYPE.CDC; var CDC_1 = { name: 'CDC', structure: [], parse: function() { var start = this.scanner.tokenStart; this.eat(CDC); // --> return { type: 'CDC', loc: this.getLocation(start, this.scanner.tokenStart) }; }, generate: function() { this.chunk('-->'); } }; var CDO = tokenizer.TYPE.CDO; var CDO_1 = { name: 'CDO', structure: [], parse: function() { var start = this.scanner.tokenStart; this.eat(CDO); // <!-- return { type: 'CDO', loc: this.getLocation(start, this.scanner.tokenStart) }; }, generate: function() { this.chunk('<!--'); } }; var TYPE$g = tokenizer.TYPE; var IDENT$5 = TYPE$g.Ident; var FULLSTOP = 0x002E; // U+002E FULL STOP (.) // '.' ident var ClassSelector = { name: 'ClassSelector', structure: { name: String }, parse: function() { if (!this.scanner.isDelim(FULLSTOP)) { this.error('Full stop is expected'); } this.scanner.next(); return { type: 'ClassSelector', loc: this.getLocation(this.scanner.tokenStart - 1, this.scanner.tokenEnd), name: this.consume(IDENT$5) }; }, generate: function(node) { this.chunk('.'); this.chunk(node.name); } }; var TYPE$h = tokenizer.TYPE; var IDENT$6 = TYPE$h.Ident; var PLUSSIGN$4 = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS = 0x002F; // U+002F SOLIDUS (/) var GREATERTHANSIGN$1 = 0x003E; // U+003E GREATER-THAN SIGN (>) var TILDE$1 = 0x007E; // U+007E TILDE (~) // + | > | ~ | /deep/ var Combinator = { name: 'Combinator', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); switch (code) { case GREATERTHANSIGN$1: case PLUSSIGN$4: case TILDE$1: this.scanner.next(); break; case SOLIDUS: this.scanner.next(); if (this.scanner.tokenType !== IDENT$6 || this.scanner.lookupValue(0, 'deep') === false) { this.error('Identifier `deep` is expected'); } this.scanner.next(); if (!this.scanner.isDelim(SOLIDUS)) { this.error('Solidus is expected'); } this.scanner.next(); break; default: this.error('Combinator is expected'); } return { type: 'Combinator', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.name); } }; var TYPE$i = tokenizer.TYPE; var COMMENT$5 = TYPE$i.Comment; var ASTERISK$2 = 0x002A; // U+002A ASTERISK (*) var SOLIDUS$1 = 0x002F; // U+002F SOLIDUS (/) // '/*' .* '*/' var Comment = { name: 'Comment', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; var end = this.scanner.tokenEnd; this.eat(COMMENT$5); if ((end - start + 2) >= 2 && this.scanner.source.charCodeAt(end - 2) === ASTERISK$2 && this.scanner.source.charCodeAt(end - 1) === SOLIDUS$1) { end -= 2; } return { type: 'Comment', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start + 2, end) }; }, generate: function(node) { this.chunk('/*'); this.chunk(node.value); this.chunk('*/'); } }; var isCustomProperty$1 = names.isCustomProperty; var TYPE$j = tokenizer.TYPE; var rawMode$2 = Raw.mode; var IDENT$7 = TYPE$j.Ident; var HASH$1 = TYPE$j.Hash; var COLON$1 = TYPE$j.Colon; var SEMICOLON$3 = TYPE$j.Semicolon; var DELIM$2 = TYPE$j.Delim; var EXCLAMATIONMARK$2 = 0x0021; // U+0021 EXCLAMATION MARK (!) var NUMBERSIGN$2 = 0x0023; // U+0023 NUMBER SIGN (#) var DOLLARSIGN$1 = 0x0024; // U+0024 DOLLAR SIGN ($) var AMPERSAND$1 = 0x0026; // U+0026 ANPERSAND (&) var ASTERISK$3 = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN$5 = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS$2 = 0x002F; // U+002F SOLIDUS (/) function consumeValueRaw(startToken) { return this.Raw(startToken, rawMode$2.exclamationMarkOrSemicolon, true); } function consumeCustomPropertyRaw(startToken) { return this.Raw(startToken, rawMode$2.exclamationMarkOrSemicolon, false); } function consumeValue() { var startValueToken = this.scanner.tokenIndex; var value = this.Value(); if (value.type !== 'Raw' && this.scanner.eof === false && this.scanner.tokenType !== SEMICOLON$3 && this.scanner.isDelim(EXCLAMATIONMARK$2) === false && this.scanner.isBalanceEdge(startValueToken) === false) { this.error(); } return value; } var Declaration = { name: 'Declaration', structure: { important: [Boolean, String], property: String, value: ['Value', 'Raw'] }, parse: function() { var start = this.scanner.tokenStart; var startToken = this.scanner.tokenIndex; var property = readProperty$1.call(this); var customProperty = isCustomProperty$1(property); var parseValue = customProperty ? this.parseCustomProperty : this.parseValue; var consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw; var important = false; var value; this.scanner.skipSC(); this.eat(COLON$1); if (!customProperty) { this.scanner.skipSC(); } if (parseValue) { value = this.parseWithFallback(consumeValue, consumeRaw); } else { value = consumeRaw.call(this, this.scanner.tokenIndex); } if (this.scanner.isDelim(EXCLAMATIONMARK$2)) { important = getImportant.call(this); this.scanner.skipSC(); } // Do not include semicolon to range per spec // https://drafts.csswg.org/css-syntax/#declaration-diagram if (this.scanner.eof === false && this.scanner.tokenType !== SEMICOLON$3 && this.scanner.isBalanceEdge(startToken) === false) { this.error(); } return { type: 'Declaration', loc: this.getLocation(start, this.scanner.tokenStart), important: important, property: property, value: value }; }, generate: function(node) { this.chunk(node.property); this.chunk(':'); this.node(node.value); if (node.important) { this.chunk(node.important === true ? '!important' : '!' + node.important); } }, walkContext: 'declaration' }; function readProperty$1() { var start = this.scanner.tokenStart; // hacks if (this.scanner.tokenType === DELIM$2) { switch (this.scanner.source.charCodeAt(this.scanner.tokenStart)) { case ASTERISK$3: case DOLLARSIGN$1: case PLUSSIGN$5: case NUMBERSIGN$2: case AMPERSAND$1: this.scanner.next(); break; // TODO: not sure we should support this hack case SOLIDUS$2: this.scanner.next(); if (this.scanner.isDelim(SOLIDUS$2)) { this.scanner.next(); } break; } } if (this.scanner.tokenType === HASH$1) { this.eat(HASH$1); } else { this.eat(IDENT$7); } return this.scanner.substrToCursor(start); } // ! ws* important function getImportant() { this.eat(DELIM$2); this.scanner.skipSC(); var important = this.consume(IDENT$7); // store original value in case it differ from `important` // for better original source restoring and hacks like `!ie` support return important === 'important' ? true : important; } var TYPE$k = tokenizer.TYPE; var rawMode$3 = Raw.mode; var WHITESPACE$6 = TYPE$k.WhiteSpace; var COMMENT$6 = TYPE$k.Comment; var SEMICOLON$4 = TYPE$k.Semicolon; function consumeRaw$2(startToken) { return this.Raw(startToken, rawMode$3.semicolonIncluded, true); } var DeclarationList = { name: 'DeclarationList', structure: { children: [[ 'Declaration' ]] }, parse: function() { var children = this.createList(); while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE$6: case COMMENT$6: case SEMICOLON$4: this.scanner.next(); break; default: children.push(this.parseWithFallback(this.Declaration, consumeRaw$2)); } } return { type: 'DeclarationList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function(prev) { if (prev.type === 'Declaration') { this.chunk(';'); } }); } }; var consumeNumber$3 = utils.consumeNumber; var TYPE$l = tokenizer.TYPE; var DIMENSION$3 = TYPE$l.Dimension; var Dimension = { name: 'Dimension', structure: { value: String, unit: String }, parse: function() { var start = this.scanner.tokenStart; var numberEnd = consumeNumber$3(this.scanner.source, start); this.eat(DIMENSION$3); return { type: 'Dimension', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start, numberEnd), unit: this.scanner.source.substring(numberEnd, this.scanner.tokenStart) }; }, generate: function(node) { this.chunk(node.value); this.chunk(node.unit); } }; var TYPE$m = tokenizer.TYPE; var RIGHTPARENTHESIS$2 = TYPE$m.RightParenthesis; // <function-token> <sequence> ) var _Function = { name: 'Function', structure: { name: String, children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var name = this.consumeFunctionName(); var nameLowerCase = name.toLowerCase(); var children; children = recognizer.hasOwnProperty(nameLowerCase) ? recognizer[nameLowerCase].call(this, recognizer) : readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTPARENTHESIS$2); } return { type: 'Function', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk(node.name); this.chunk('('); this.children(node); this.chunk(')'); }, walkContext: 'function' }; var TYPE$n = tokenizer.TYPE; var HASH$2 = TYPE$n.Hash; // '#' ident var HexColor = { name: 'HexColor', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; this.eat(HASH$2); return { type: 'HexColor', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start + 1) }; }, generate: function(node) { this.chunk('#'); this.chunk(node.value); } }; var TYPE$o = tokenizer.TYPE; var IDENT$8 = TYPE$o.Ident; var Identifier = { name: 'Identifier', structure: { name: String }, parse: function() { return { type: 'Identifier', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), name: this.consume(IDENT$8) }; }, generate: function(node) { this.chunk(node.name); } }; var TYPE$p = tokenizer.TYPE; var HASH$3 = TYPE$p.Hash; // <hash-token> var IdSelector = { name: 'IdSelector', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; // TODO: check value is an ident this.eat(HASH$3); return { type: 'IdSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start + 1) }; }, generate: function(node) { this.chunk('#'); this.chunk(node.name); } }; var TYPE$q = tokenizer.TYPE; var IDENT$9 = TYPE$q.Ident; var NUMBER$4 = TYPE$q.Number; var DIMENSION$4 = TYPE$q.Dimension; var LEFTPARENTHESIS$2 = TYPE$q.LeftParenthesis; var RIGHTPARENTHESIS$3 = TYPE$q.RightParenthesis; var COLON$2 = TYPE$q.Colon; var DELIM$3 = TYPE$q.Delim; var MediaFeature = { name: 'MediaFeature', structure: { name: String, value: ['Identifier', 'Number', 'Dimension', 'Ratio', null] }, parse: function() { var start = this.scanner.tokenStart; var name; var value = null; this.eat(LEFTPARENTHESIS$2); this.scanner.skipSC(); name = this.consume(IDENT$9); this.scanner.skipSC(); if (this.scanner.tokenType !== RIGHTPARENTHESIS$3) { this.eat(COLON$2); this.scanner.skipSC(); switch (this.scanner.tokenType) { case NUMBER$4: if (this.lookupNonWSType(1) === DELIM$3) { value = this.Ratio(); } else { value = this.Number(); } break; case DIMENSION$4: value = this.Dimension(); break; case IDENT$9: value = this.Identifier(); break; default: this.error('Number, dimension, ratio or identifier is expected'); } this.scanner.skipSC(); } this.eat(RIGHTPARENTHESIS$3); return { type: 'MediaFeature', loc: this.getLocation(start, this.scanner.tokenStart), name: name, value: value }; }, generate: function(node) { this.chunk('('); this.chunk(node.name); if (node.value !== null) { this.chunk(':'); this.node(node.value); } this.chunk(')'); } }; var TYPE$r = tokenizer.TYPE; var WHITESPACE$7 = TYPE$r.WhiteSpace; var COMMENT$7 = TYPE$r.Comment; var IDENT$a = TYPE$r.Ident; var LEFTPARENTHESIS$3 = TYPE$r.LeftParenthesis; var MediaQuery = { name: 'MediaQuery', structure: { children: [[ 'Identifier', 'MediaFeature', 'WhiteSpace' ]] }, parse: function() { this.scanner.skipSC(); var children = this.createList(); var child = null; var space = null; scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case COMMENT$7: this.scanner.next(); continue; case WHITESPACE$7: space = this.WhiteSpace(); continue; case IDENT$a: child = this.Identifier(); break; case LEFTPARENTHESIS$3: child = this.MediaFeature(); break; default: break scan; } if (space !== null) { children.push(space); space = null; } children.push(child); } if (child === null) { this.error('Identifier or parenthesis is expected'); } return { type: 'MediaQuery', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); } }; var COMMA$1 = tokenizer.TYPE.Comma; var MediaQueryList = { name: 'MediaQueryList', structure: { children: [[ 'MediaQuery' ]] }, parse: function(relative) { var children = this.createList(); this.scanner.skipSC(); while (!this.scanner.eof) { children.push(this.MediaQuery(relative)); if (this.scanner.tokenType !== COMMA$1) { break; } this.scanner.next(); } return { type: 'MediaQueryList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function() { this.chunk(','); }); } }; var Nth = { name: 'Nth', structure: { nth: ['AnPlusB', 'Identifier'], selector: ['SelectorList', null] }, parse: function(allowOfClause) { this.scanner.skipSC(); var start = this.scanner.tokenStart; var end = start; var selector = null; var query; if (this.scanner.lookupValue(0, 'odd') || this.scanner.lookupValue(0, 'even')) { query = this.Identifier(); } else { query = this.AnPlusB(); } this.scanner.skipSC(); if (allowOfClause && this.scanner.lookupValue(0, 'of')) { this.scanner.next(); selector = this.SelectorList(); if (this.needPositions) { end = this.getLastListNode(selector.children).loc.end.offset; } } else { if (this.needPositions) { end = query.loc.end.offset; } } return { type: 'Nth', loc: this.getLocation(start, end), nth: query, selector: selector }; }, generate: function(node) { this.node(node.nth); if (node.selector !== null) { this.chunk(' of '); this.node(node.selector); } } }; var NUMBER$5 = tokenizer.TYPE.Number; var _Number = { name: 'Number', structure: { value: String }, parse: function() { return { type: 'Number', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), value: this.consume(NUMBER$5) }; }, generate: function(node) { this.chunk(node.value); } }; // '/' | '*' | ',' | ':' | '+' | '-' var Operator = { name: 'Operator', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; this.scanner.next(); return { type: 'Operator', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.value); } }; var TYPE$s = tokenizer.TYPE; var LEFTPARENTHESIS$4 = TYPE$s.LeftParenthesis; var RIGHTPARENTHESIS$4 = TYPE$s.RightParenthesis; var Parentheses = { name: 'Parentheses', structure: { children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var children = null; this.eat(LEFTPARENTHESIS$4); children = readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTPARENTHESIS$4); } return { type: 'Parentheses', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('('); this.children(node); this.chunk(')'); } }; var consumeNumber$4 = utils.consumeNumber; var TYPE$t = tokenizer.TYPE; var PERCENTAGE$1 = TYPE$t.Percentage; var Percentage = { name: 'Percentage', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; var numberEnd = consumeNumber$4(this.scanner.source, start); this.eat(PERCENTAGE$1); return { type: 'Percentage', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start, numberEnd) }; }, generate: function(node) { this.chunk(node.value); this.chunk('%'); } }; var TYPE$u = tokenizer.TYPE; var IDENT$b = TYPE$u.Ident; var FUNCTION$1 = TYPE$u.Function; var COLON$3 = TYPE$u.Colon; var RIGHTPARENTHESIS$5 = TYPE$u.RightParenthesis; // : [ <ident> | <function-token> <any-value>? ) ] var PseudoClassSelector = { name: 'PseudoClassSelector', structure: { name: String, children: [['Raw'], null] }, parse: function() { var start = this.scanner.tokenStart; var children = null; var name; var nameLowerCase; this.eat(COLON$3); if (this.scanner.tokenType === FUNCTION$1) { name = this.consumeFunctionName(); nameLowerCase = name.toLowerCase(); if (this.pseudo.hasOwnProperty(nameLowerCase)) { this.scanner.skipSC(); children = this.pseudo[nameLowerCase].call(this); this.scanner.skipSC(); } else { children = this.createList(); children.push( this.Raw(this.scanner.tokenIndex, null, false) ); } this.eat(RIGHTPARENTHESIS$5); } else { name = this.consume(IDENT$b); } return { type: 'PseudoClassSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk(':'); this.chunk(node.name); if (node.children !== null) { this.chunk('('); this.children(node); this.chunk(')'); } }, walkContext: 'function' }; var TYPE$v = tokenizer.TYPE; var IDENT$c = TYPE$v.Ident; var FUNCTION$2 = TYPE$v.Function; var COLON$4 = TYPE$v.Colon; var RIGHTPARENTHESIS$6 = TYPE$v.RightParenthesis; // :: [ <ident> | <function-token> <any-value>? ) ] var PseudoElementSelector = { name: 'PseudoElementSelector', structure: { name: String, children: [['Raw'], null] }, parse: function() { var start = this.scanner.tokenStart; var children = null; var name; var nameLowerCase; this.eat(COLON$4); this.eat(COLON$4); if (this.scanner.tokenType === FUNCTION$2) { name = this.consumeFunctionName(); nameLowerCase = name.toLowerCase(); if (this.pseudo.hasOwnProperty(nameLowerCase)) { this.scanner.skipSC(); children = this.pseudo[nameLowerCase].call(this); this.scanner.skipSC(); } else { children = this.createList(); children.push( this.Raw(this.scanner.tokenIndex, null, false) ); } this.eat(RIGHTPARENTHESIS$6); } else { name = this.consume(IDENT$c); } return { type: 'PseudoElementSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk('::'); this.chunk(node.name); if (node.children !== null) { this.chunk('('); this.children(node); this.chunk(')'); } }, walkContext: 'function' }; var isDigit$5 = tokenizer.isDigit; var TYPE$w = tokenizer.TYPE; var NUMBER$6 = TYPE$w.Number; var DELIM$4 = TYPE$w.Delim; var SOLIDUS$3 = 0x002F; // U+002F SOLIDUS (/) var FULLSTOP$1 = 0x002E; // U+002E FULL STOP (.) // Terms of <ratio> should be a positive numbers (not zero or negative) // (see https://drafts.csswg.org/mediaqueries-3/#values) // However, -o-min-device-pixel-ratio takes fractional values as a ratio's term // and this is using by various sites. Therefore we relax checking on parse // to test a term is unsigned number without an exponent part. // Additional checking may be applied on lexer validation. function consumeNumber$5() { this.scanner.skipWS(); var value = this.consume(NUMBER$6); for (var i = 0; i < value.length; i++) { var code = value.charCodeAt(i); if (!isDigit$5(code) && code !== FULLSTOP$1) { this.error('Unsigned number is expected', this.scanner.tokenStart - value.length + i); } } if (Number(value) === 0) { this.error('Zero number is not allowed', this.scanner.tokenStart - value.length); } return value; } // <positive-integer> S* '/' S* <positive-integer> var Ratio = { name: 'Ratio', structure: { left: String, right: String }, parse: function() { var start = this.scanner.tokenStart; var left = consumeNumber$5.call(this); var right; this.scanner.skipWS(); if (!this.scanner.isDelim(SOLIDUS$3)) { this.error('Solidus is expected'); } this.eat(DELIM$4); right = consumeNumber$5.call(this); return { type: 'Ratio', loc: this.getLocation(start, this.scanner.tokenStart), left: left, right: right }; }, generate: function(node) { this.chunk(node.left); this.chunk('/'); this.chunk(node.right); } }; var TYPE$x = tokenizer.TYPE; var rawMode$4 = Raw.mode; var LEFTCURLYBRACKET$4 = TYPE$x.LeftCurlyBracket; function consumeRaw$3(startToken) { return this.Raw(startToken, rawMode$4.leftCurlyBracket, true); } function consumePrelude() { var prelude = this.SelectorList(); if (prelude.type !== 'Raw' && this.scanner.eof === false && this.scanner.tokenType !== LEFTCURLYBRACKET$4) { this.error(); } return prelude; } var Rule = { name: 'Rule', structure: { prelude: ['SelectorList', 'Raw'], block: ['Block'] }, parse: function() { var startToken = this.scanner.tokenIndex; var startOffset = this.scanner.tokenStart; var prelude; var block; if (this.parseRulePrelude) { prelude = this.parseWithFallback(consumePrelude, consumeRaw$3); } else { prelude = consumeRaw$3.call(this, startToken); } block = this.Block(true); return { type: 'Rule', loc: this.getLocation(startOffset, this.scanner.tokenStart), prelude: prelude, block: block }; }, generate: function(node) { this.node(node.prelude); this.node(node.block); }, walkContext: 'rule' }; var Selector = { name: 'Selector', structure: { children: [[ 'TypeSelector', 'IdSelector', 'ClassSelector', 'AttributeSelector', 'PseudoClassSelector', 'PseudoElementSelector', 'Combinator', 'WhiteSpace' ]] }, parse: function() { var children = this.readSequence(this.scope.Selector); // nothing were consumed if (this.getFirstListNode(children) === null) { this.error('Selector is expected'); } return { type: 'Selector', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); } }; var TYPE$y = tokenizer.TYPE; var COMMA$2 = TYPE$y.Comma; var SelectorList = { name: 'SelectorList', structure: { children: [[ 'Selector', 'Raw' ]] }, parse: function() { var children = this.createList(); while (!this.scanner.eof) { children.push(this.Selector()); if (this.scanner.tokenType === COMMA$2) { this.scanner.next(); continue; } break; } return { type: 'SelectorList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function() { this.chunk(','); }); }, walkContext: 'selector' }; var STRING$1 = tokenizer.TYPE.String; var _String = { name: 'String', structure: { value: String }, parse: function() { return { type: 'String', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), value: this.consume(STRING$1) }; }, generate: function(node) { this.chunk(node.value); } }; var TYPE$z = tokenizer.TYPE; var WHITESPACE$8 = TYPE$z.WhiteSpace; var COMMENT$8 = TYPE$z.Comment; var ATKEYWORD$2 = TYPE$z.AtKeyword; var CDO$1 = TYPE$z.CDO; var CDC$1 = TYPE$z.CDC; var EXCLAMATIONMARK$3 = 0x0021; // U+0021 EXCLAMATION MARK (!) function consumeRaw$4(startToken) { return this.Raw(startToken, null, false); } var StyleSheet = { name: 'StyleSheet', structure: { children: [[ 'Comment', 'CDO', 'CDC', 'Atrule', 'Rule', 'Raw' ]] }, parse: function() { var start = this.scanner.tokenStart; var children = this.createList(); var child; while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE$8: this.scanner.next(); continue; case COMMENT$8: // ignore comments except exclamation comments (i.e. /*! .. */) on top level if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 2) !== EXCLAMATIONMARK$3) { this.scanner.next(); continue; } child = this.Comment(); break; case CDO$1: // <!-- child = this.CDO(); break; case CDC$1: // --> child = this.CDC(); break; // CSS Syntax Module Level 3 // §2.2 Error handling // At the "top level" of a stylesheet, an <at-keyword-token> starts an at-rule. case ATKEYWORD$2: child = this.parseWithFallback(this.Atrule, consumeRaw$4); break; // Anything else starts a qualified rule ... default: child = this.parseWithFallback(this.Rule, consumeRaw$4); } children.push(child); } return { type: 'StyleSheet', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.children(node); }, walkContext: 'stylesheet' }; var TYPE$A = tokenizer.TYPE; var IDENT$d = TYPE$A.Ident; var ASTERISK$4 = 0x002A; // U+002A ASTERISK (*) var VERTICALLINE$2 = 0x007C; // U+007C VERTICAL LINE (|) function eatIdentifierOrAsterisk() { if (this.scanner.tokenType !== IDENT$d && this.scanner.isDelim(ASTERISK$4) === false) { this.error('Identifier or asterisk is expected'); } this.scanner.next(); } // ident // ident|ident // ident|* // * // *|ident // *|* // |ident // |* var TypeSelector = { name: 'TypeSelector', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; if (this.scanner.isDelim(VERTICALLINE$2)) { this.scanner.next(); eatIdentifierOrAsterisk.call(this); } else { eatIdentifierOrAsterisk.call(this); if (this.scanner.isDelim(VERTICALLINE$2)) { this.scanner.next(); eatIdentifierOrAsterisk.call(this); } } return { type: 'TypeSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.name); } }; var isHexDigit$4 = tokenizer.isHexDigit; var cmpChar$4 = tokenizer.cmpChar; var TYPE$B = tokenizer.TYPE; var NAME$3 = tokenizer.NAME; var IDENT$e = TYPE$B.Ident; var NUMBER$7 = TYPE$B.Number; var DIMENSION$5 = TYPE$B.Dimension; var PLUSSIGN$6 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$4 = 0x002D; // U+002D HYPHEN-MINUS (-) var QUESTIONMARK$2 = 0x003F; // U+003F QUESTION MARK (?) var U$1 = 0x0075; // U+0075 LATIN SMALL LETTER U (u) function eatHexSequence(offset, allowDash) { for (var pos = this.scanner.tokenStart + offset, len = 0; pos < this.scanner.tokenEnd; pos++) { var code = this.scanner.source.charCodeAt(pos); if (code === HYPHENMINUS$4 && allowDash && len !== 0) { if (eatHexSequence.call(this, offset + len + 1, false) === 0) { this.error(); } return -1; } if (!isHexDigit$4(code)) { this.error( allowDash && len !== 0 ? 'HyphenMinus' + (len < 6 ? ' or hex digit' : '') + ' is expected' : (len < 6 ? 'Hex digit is expected' : 'Unexpected input'), pos ); } if (++len > 6) { this.error('Too many hex digits', pos); } } this.scanner.next(); return len; } function eatQuestionMarkSequence(max) { var count = 0; while (this.scanner.isDelim(QUESTIONMARK$2)) { if (++count > max) { this.error('Too many question marks'); } this.scanner.next(); } } function startsWith$1(code) { if (this.scanner.source.charCodeAt(this.scanner.tokenStart) !== code) { this.error(NAME$3[code] + ' is expected'); } } // https://drafts.csswg.org/css-syntax/#urange // Informally, the <urange> production has three forms: // U+0001 // Defines a range consisting of a single code point, in this case the code point "1". // U+0001-00ff // Defines a range of codepoints between the first and the second value, in this case // the range between "1" and "ff" (255 in decimal) inclusive. // U+00?? // Defines a range of codepoints where the "?" characters range over all hex digits, // in this case defining the same as the value U+0000-00ff. // In each form, a maximum of 6 digits is allowed for each hexadecimal number (if you treat "?" as a hexadecimal digit). // // <urange> = // u '+' <ident-token> '?'* | // u <dimension-token> '?'* | // u <number-token> '?'* | // u <number-token> <dimension-token> | // u <number-token> <number-token> | // u '+' '?'+ function scanUnicodeRange() { var hexLength = 0; // u '+' <ident-token> '?'* // u '+' '?'+ if (this.scanner.isDelim(PLUSSIGN$6)) { this.scanner.next(); if (this.scanner.tokenType === IDENT$e) { hexLength = eatHexSequence.call(this, 0, true); if (hexLength > 0) { eatQuestionMarkSequence.call(this, 6 - hexLength); } return; } if (this.scanner.isDelim(QUESTIONMARK$2)) { this.scanner.next(); eatQuestionMarkSequence.call(this, 5); return; } this.error('Hex digit or question mark is expected'); return; } // u <number-token> '?'* // u <number-token> <dimension-token> // u <number-token> <number-token> if (this.scanner.tokenType === NUMBER$7) { startsWith$1.call(this, PLUSSIGN$6); hexLength = eatHexSequence.call(this, 1, true); if (this.scanner.isDelim(QUESTIONMARK$2)) { eatQuestionMarkSequence.call(this, 6 - hexLength); return; } if (this.scanner.tokenType === DIMENSION$5 || this.scanner.tokenType === NUMBER$7) { startsWith$1.call(this, HYPHENMINUS$4); eatHexSequence.call(this, 1, false); return; } return; } // u <dimension-token> '?'* if (this.scanner.tokenType === DIMENSION$5) { startsWith$1.call(this, PLUSSIGN$6); hexLength = eatHexSequence.call(this, 1, true); if (hexLength > 0) { eatQuestionMarkSequence.call(this, 6 - hexLength); } return; } this.error(); } var UnicodeRange = { name: 'UnicodeRange', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; // U or u if (!cmpChar$4(this.scanner.source, start, U$1)) { this.error('U is expected'); } if (!cmpChar$4(this.scanner.source, start + 1, PLUSSIGN$6)) { this.error('Plus sign is expected'); } this.scanner.next(); scanUnicodeRange.call(this); return { type: 'UnicodeRange', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.value); } }; var isWhiteSpace$2 = tokenizer.isWhiteSpace; var cmpStr$4 = tokenizer.cmpStr; var TYPE$C = tokenizer.TYPE; var FUNCTION$3 = TYPE$C.Function; var URL$2 = TYPE$C.Url; var RIGHTPARENTHESIS$7 = TYPE$C.RightParenthesis; // <url-token> | <function-token> <string> ) var Url = { name: 'Url', structure: { value: ['String', 'Raw'] }, parse: function() { var start = this.scanner.tokenStart; var value; switch (this.scanner.tokenType) { case URL$2: var rawStart = start + 4; var rawEnd = this.scanner.tokenEnd - 1; while (rawStart < rawEnd && isWhiteSpace$2(this.scanner.source.charCodeAt(rawStart))) { rawStart++; } while (rawStart < rawEnd && isWhiteSpace$2(this.scanner.source.charCodeAt(rawEnd - 1))) { rawEnd--; } value = { type: 'Raw', loc: this.getLocation(rawStart, rawEnd), value: this.scanner.source.substring(rawStart, rawEnd) }; this.eat(URL$2); break; case FUNCTION$3: if (!cmpStr$4(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(')) { this.error('Function name must be `url`'); } this.eat(FUNCTION$3); this.scanner.skipSC(); value = this.String(); this.scanner.skipSC(); this.eat(RIGHTPARENTHESIS$7); break; default: this.error('Url or Function is expected'); } return { type: 'Url', loc: this.getLocation(start, this.scanner.tokenStart), value: value }; }, generate: function(node) { this.chunk('url'); this.chunk('('); this.node(node.value); this.chunk(')'); } }; var Value = { name: 'Value', structure: { children: [[]] }, parse: function() { var start = this.scanner.tokenStart; var children = this.readSequence(this.scope.Value); return { type: 'Value', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.children(node); } }; var WHITESPACE$9 = tokenizer.TYPE.WhiteSpace; var SPACE$2 = Object.freeze({ type: 'WhiteSpace', loc: null, value: ' ' }); var WhiteSpace$1 = { name: 'WhiteSpace', structure: { value: String }, parse: function() { this.eat(WHITESPACE$9); return SPACE$2; // return { // type: 'WhiteSpace', // loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), // value: this.consume(WHITESPACE) // }; }, generate: function(node) { this.chunk(node.value); } }; var node = { AnPlusB: AnPlusB, Atrule: Atrule, AtrulePrelude: AtrulePrelude, AttributeSelector: AttributeSelector, Block: Block, Brackets: Brackets, CDC: CDC_1, CDO: CDO_1, ClassSelector: ClassSelector, Combinator: Combinator, Comment: Comment, Declaration: Declaration, DeclarationList: DeclarationList, Dimension: Dimension, Function: _Function, HexColor: HexColor, Identifier: Identifier, IdSelector: IdSelector, MediaFeature: MediaFeature, MediaQuery: MediaQuery, MediaQueryList: MediaQueryList, Nth: Nth, Number: _Number, Operator: Operator, Parentheses: Parentheses, Percentage: Percentage, PseudoClassSelector: PseudoClassSelector, PseudoElementSelector: PseudoElementSelector, Ratio: Ratio, Raw: Raw, Rule: Rule, Selector: Selector, SelectorList: SelectorList, String: _String, StyleSheet: StyleSheet, TypeSelector: TypeSelector, UnicodeRange: UnicodeRange, Url: Url, Value: Value, WhiteSpace: WhiteSpace$1 }; var lexer = { generic: true, types: data.types, atrules: data.atrules, properties: data.properties, node: node }; var cmpChar$5 = tokenizer.cmpChar; var cmpStr$5 = tokenizer.cmpStr; var TYPE$D = tokenizer.TYPE; var IDENT$f = TYPE$D.Ident; var STRING$2 = TYPE$D.String; var NUMBER$8 = TYPE$D.Number; var FUNCTION$4 = TYPE$D.Function; var URL$3 = TYPE$D.Url; var HASH$4 = TYPE$D.Hash; var DIMENSION$6 = TYPE$D.Dimension; var PERCENTAGE$2 = TYPE$D.Percentage; var LEFTPARENTHESIS$5 = TYPE$D.LeftParenthesis; var LEFTSQUAREBRACKET$3 = TYPE$D.LeftSquareBracket; var COMMA$3 = TYPE$D.Comma; var DELIM$5 = TYPE$D.Delim; var NUMBERSIGN$3 = 0x0023; // U+0023 NUMBER SIGN (#) var ASTERISK$5 = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN$7 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$5 = 0x002D; // U+002D HYPHEN-MINUS (-) var SOLIDUS$4 = 0x002F; // U+002F SOLIDUS (/) var U$2 = 0x0075; // U+0075 LATIN SMALL LETTER U (u) var _default = function defaultRecognizer(context) { switch (this.scanner.tokenType) { case HASH$4: return this.HexColor(); case COMMA$3: context.space = null; context.ignoreWSAfter = true; return this.Operator(); case LEFTPARENTHESIS$5: return this.Parentheses(this.readSequence, context.recognizer); case LEFTSQUAREBRACKET$3: return this.Brackets(this.readSequence, context.recognizer); case STRING$2: return this.String(); case DIMENSION$6: return this.Dimension(); case PERCENTAGE$2: return this.Percentage(); case NUMBER$8: return this.Number(); case FUNCTION$4: return cmpStr$5(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(') ? this.Url() : this.Function(this.readSequence, context.recognizer); case URL$3: return this.Url(); case IDENT$f: // check for unicode range, it should start with u+ or U+ if (cmpChar$5(this.scanner.source, this.scanner.tokenStart, U$2) && cmpChar$5(this.scanner.source, this.scanner.tokenStart + 1, PLUSSIGN$7)) { return this.UnicodeRange(); } else { return this.Identifier(); } case DELIM$5: var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); if (code === SOLIDUS$4 || code === ASTERISK$5 || code === PLUSSIGN$7 || code === HYPHENMINUS$5) { return this.Operator(); // TODO: replace with Delim } // TODO: produce a node with Delim node type if (code === NUMBERSIGN$3) { this.error('Hex or identifier is expected', this.scanner.tokenStart + 1); } break; } }; var atrulePrelude = { getNode: _default }; var TYPE$E = tokenizer.TYPE; var DELIM$6 = TYPE$E.Delim; var IDENT$g = TYPE$E.Ident; var DIMENSION$7 = TYPE$E.Dimension; var PERCENTAGE$3 = TYPE$E.Percentage; var NUMBER$9 = TYPE$E.Number; var HASH$5 = TYPE$E.Hash; var COLON$5 = TYPE$E.Colon; var LEFTSQUAREBRACKET$4 = TYPE$E.LeftSquareBracket; var NUMBERSIGN$4 = 0x0023; // U+0023 NUMBER SIGN (#) var ASTERISK$6 = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN$8 = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS$5 = 0x002F; // U+002F SOLIDUS (/) var FULLSTOP$2 = 0x002E; // U+002E FULL STOP (.) var GREATERTHANSIGN$2 = 0x003E; // U+003E GREATER-THAN SIGN (>) var VERTICALLINE$3 = 0x007C; // U+007C VERTICAL LINE (|) var TILDE$2 = 0x007E; // U+007E TILDE (~) function getNode(context) { switch (this.scanner.tokenType) { case LEFTSQUAREBRACKET$4: return this.AttributeSelector(); case HASH$5: return this.IdSelector(); case COLON$5: if (this.scanner.lookupType(1) === COLON$5) { return this.PseudoElementSelector(); } else { return this.PseudoClassSelector(); } case IDENT$g: return this.TypeSelector(); case NUMBER$9: case PERCENTAGE$3: return this.Percentage(); case DIMENSION$7: // throws when .123ident if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === FULLSTOP$2) { this.error('Identifier is expected', this.scanner.tokenStart + 1); } break; case DELIM$6: var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); switch (code) { case PLUSSIGN$8: case GREATERTHANSIGN$2: case TILDE$2: context.space = null; context.ignoreWSAfter = true; return this.Combinator(); case SOLIDUS$5: // /deep/ return this.Combinator(); case FULLSTOP$2: return this.ClassSelector(); case ASTERISK$6: case VERTICALLINE$3: return this.TypeSelector(); case NUMBERSIGN$4: return this.IdSelector(); } break; } } var selector = { getNode: getNode }; // https://drafts.csswg.org/css-images-4/#element-notation // https://developer.mozilla.org/en-US/docs/Web/CSS/element var element = function() { this.scanner.skipSC(); var children = this.createSingleNodeList( this.IdSelector() ); this.scanner.skipSC(); return children; }; // legacy IE function // expression( <any-value> ) var expression = function() { return this.createSingleNodeList( this.Raw(this.scanner.tokenIndex, null, false) ); }; var TYPE$F = tokenizer.TYPE; var rawMode$5 = Raw.mode; var COMMA$4 = TYPE$F.Comma; // var( <ident> , <value>? ) var _var = function() { var children = this.createList(); this.scanner.skipSC(); // NOTE: Don't check more than a first argument is an ident, rest checks are for lexer children.push(this.Identifier()); this.scanner.skipSC(); if (this.scanner.tokenType === COMMA$4) { children.push(this.Operator()); children.push(this.parseCustomProperty ? this.Value(null) : this.Raw(this.scanner.tokenIndex, rawMode$5.exclamationMarkOrSemicolon, false) ); } return children; }; var value = { getNode: _default, '-moz-element': element, 'element': element, 'expression': expression, 'var': _var }; var scope = { AtrulePrelude: atrulePrelude, Selector: selector, Value: value }; var fontFace = { parse: { prelude: null, block: function() { return this.Block(true); } } }; var TYPE$G = tokenizer.TYPE; var STRING$3 = TYPE$G.String; var IDENT$h = TYPE$G.Ident; var URL$4 = TYPE$G.Url; var FUNCTION$5 = TYPE$G.Function; var LEFTPARENTHESIS$6 = TYPE$G.LeftParenthesis; var _import = { parse: { prelude: function() { var children = this.createList(); this.scanner.skipSC(); switch (this.scanner.tokenType) { case STRING$3: children.push(this.String()); break; case URL$4: case FUNCTION$5: children.push(this.Url()); break; default: this.error('String or url() is expected'); } if (this.lookupNonWSType(0) === IDENT$h || this.lookupNonWSType(0) === LEFTPARENTHESIS$6) { children.push(this.WhiteSpace()); children.push(this.MediaQueryList()); } return children; }, block: null } }; var media = { parse: { prelude: function() { return this.createSingleNodeList( this.MediaQueryList() ); }, block: function() { return this.Block(false); } } }; var page = { parse: { prelude: function() { return this.createSingleNodeList( this.SelectorList() ); }, block: function() { return this.Block(true); } } }; var TYPE$H = tokenizer.TYPE; var WHITESPACE$a = TYPE$H.WhiteSpace; var COMMENT$9 = TYPE$H.Comment; var IDENT$i = TYPE$H.Ident; var FUNCTION$6 = TYPE$H.Function; var COLON$6 = TYPE$H.Colon; var LEFTPARENTHESIS$7 = TYPE$H.LeftParenthesis; function consumeRaw$5() { return this.createSingleNodeList( this.Raw(this.scanner.tokenIndex, null, false) ); } function parentheses() { this.scanner.skipSC(); if (this.scanner.tokenType === IDENT$i && this.lookupNonWSType(1) === COLON$6) { return this.createSingleNodeList( this.Declaration() ); } return readSequence.call(this); } function readSequence() { var children = this.createList(); var space = null; var child; this.scanner.skipSC(); scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE$a: space = this.WhiteSpace(); continue; case COMMENT$9: this.scanner.next(); continue; case FUNCTION$6: child = this.Function(consumeRaw$5, this.scope.AtrulePrelude); break; case IDENT$i: child = this.Identifier(); break; case LEFTPARENTHESIS$7: child = this.Parentheses(parentheses, this.scope.AtrulePrelude); break; default: break scan; } if (space !== null) { children.push(space); space = null; } children.push(child); } return children; } var supports = { parse: { prelude: function() { var children = readSequence.call(this); if (this.getFirstListNode(children) === null) { this.error('Condition is expected'); } return children; }, block: function() { return this.Block(false); } } }; var atrule = { 'font-face': fontFace, 'import': _import, 'media': media, 'page': page, 'supports': supports }; var dir = { parse: function() { return this.createSingleNodeList( this.Identifier() ); } }; var has$1 = { parse: function() { return this.createSingleNodeList( this.SelectorList() ); } }; var lang = { parse: function() { return this.createSingleNodeList( this.Identifier() ); } }; var selectorList = { parse: function selectorList() { return this.createSingleNodeList( this.SelectorList() ); } }; var matches = selectorList; var not = selectorList; var ALLOW_OF_CLAUSE = true; var nthWithOfClause = { parse: function nthWithOfClause() { return this.createSingleNodeList( this.Nth(ALLOW_OF_CLAUSE) ); } }; var nthChild = nthWithOfClause; var nthLastChild = nthWithOfClause; var DISALLOW_OF_CLAUSE = false; var nth$1 = { parse: function nth() { return this.createSingleNodeList( this.Nth(DISALLOW_OF_CLAUSE) ); } }; var nthLastOfType = nth$1; var nthOfType = nth$1; var slotted = { parse: function compoundSelector() { return this.createSingleNodeList( this.Selector() ); } }; var pseudo = { 'dir': dir, 'has': has$1, 'lang': lang, 'matches': matches, 'not': not, 'nth-child': nthChild, 'nth-last-child': nthLastChild, 'nth-last-of-type': nthLastOfType, 'nth-of-type': nthOfType, 'slotted': slotted }; var parser = { parseContext: { default: 'StyleSheet', stylesheet: 'StyleSheet', atrule: 'Atrule', atrulePrelude: function(options) { return this.AtrulePrelude(options.atrule ? String(options.atrule) : null); }, mediaQueryList: 'MediaQueryList', mediaQuery: 'MediaQuery', rule: 'Rule', selectorList: 'SelectorList', selector: 'Selector', block: function() { return this.Block(true); }, declarationList: 'DeclarationList', declaration: 'Declaration', value: 'Value' }, scope: scope, atrule: atrule, pseudo: pseudo, node: node }; var walker = { node: node }; function merge() { var dest = {}; for (var i = 0; i < arguments.length; i++) { var src = arguments[i]; for (var key in src) { dest[key] = src[key]; } } return dest; } var syntax = create$5.create( merge( lexer, parser, walker ) ); var lib = syntax; class Sheet { constructor(url, hooks) { if (hooks) { this.hooks = hooks; } else { this.hooks = {}; this.hooks.onUrl = new Hook(this); this.hooks.onAtPage = new Hook(this); this.hooks.onAtMedia = new Hook(this); this.hooks.onRule = new Hook(this); this.hooks.onDeclaration = new Hook(this); this.hooks.onSelector = new Hook(this); this.hooks.onPseudoSelector = new Hook(this); this.hooks.onContent = new Hook(this); this.hooks.onImport = new Hook(this); this.hooks.beforeTreeParse = new Hook(this); this.hooks.beforeTreeWalk = new Hook(this); this.hooks.afterTreeWalk = new Hook(this); } try { this.url = new URL(url, window.location.href); } catch (e) { this.url = new URL(window.location.href); } } // parse async parse(text) { this.text = text; await this.hooks.beforeTreeParse.trigger(this.text, this); // send to csstree this.ast = lib.parse(this._text); await this.hooks.beforeTreeWalk.trigger(this.ast); // Replace urls this.replaceUrls(this.ast); // Scope this.id = UUID(); // this.addScope(this.ast, this.uuid); // Replace IDs with data-id this.replaceIds(this.ast); this.imported = []; // Trigger Hooks this.urls(this.ast); this.rules(this.ast); this.atrules(this.ast); await this.hooks.afterTreeWalk.trigger(this.ast, this); // return ast return this.ast; } insertRule(rule) { let inserted = this.ast.children.appendData(rule); inserted.forEach((item) => { this.declarations(item); }); } urls(ast) { lib.walk(ast, { visit: "Url", enter: (node, item, list) => { this.hooks.onUrl.trigger(node, item, list); } }); } atrules(ast) { lib.walk(ast, { visit: "Atrule", enter: (node, item, list) => { const basename = lib.keyword(node.name).basename; if (basename === "page") { this.hooks.onAtPage.trigger(node, item, list); this.declarations(node, item, list); } if (basename === "media") { this.hooks.onAtMedia.trigger(node, item, list); this.declarations(node, item, list); } if (basename === "import") { this.hooks.onImport.trigger(node, item, list); this.imports(node, item, list); } } }); } rules(ast) { lib.walk(ast, { visit: "Rule", enter: (ruleNode, ruleItem, rulelist) => { // console.log("rule", ruleNode); this.hooks.onRule.trigger(ruleNode, ruleItem, rulelist); this.declarations(ruleNode, ruleItem, rulelist); this.onSelector(ruleNode, ruleItem, rulelist); } }); } declarations(ruleNode, ruleItem, rulelist) { lib.walk(ruleNode, { visit: "Declaration", enter: (declarationNode, dItem, dList) => { // console.log(declarationNode); this.hooks.onDeclaration.trigger(declarationNode, dItem, dList, {ruleNode, ruleItem, rulelist}); if (declarationNode.property === "content") { lib.walk(declarationNode, { visit: "Function", enter: (funcNode, fItem, fList) => { this.hooks.onContent.trigger(funcNode, fItem, fList, {declarationNode, dItem, dList}, {ruleNode, ruleItem, rulelist}); } }); } } }); } // add pseudo elements to parser onSelector(ruleNode, ruleItem, rulelist) { lib.walk(ruleNode, { visit: "Selector", enter: (selectNode, selectItem, selectList) => { // console.log(selectNode); this.hooks.onSelector.trigger(selectNode, selectItem, selectList, {ruleNode, ruleItem, rulelist}); if (selectNode.children.forEach(node => {if (node.type === "PseudoElementSelector") { lib.walk(node, { visit: "PseudoElementSelector", enter: (pseudoNode, pItem, pList) => { this.hooks.onPseudoSelector.trigger(pseudoNode, pItem, pList, {selectNode, selectItem, selectList}, {ruleNode, ruleItem, rulelist}); } }); }})); // else { // console.log("dommage"); // } } }); } replaceUrls(ast) { lib.walk(ast, { visit: "Url", enter: (node, item, list) => { let content = node.value.value; if ((node.value.type === "Raw" && content.startsWith("data:")) || (node.value.type === "String" && (content.startsWith("\"data:") || content.startsWith("'data:")))) ; else { let href = content.replace(/["']/g, ""); let url = new URL(href, this.url); node.value.value = url.toString(); } } }); } addScope(ast, id) { // Get all selector lists // add an id lib.walk(ast, { visit: "Selector", enter: (node, item, list) => { let children = node.children; children.prepend(children.createItem({ type: "WhiteSpace", value: " " })); children.prepend(children.createItem({ type: "IdSelector", name: id, loc: null, children: null })); } }); } getNamedPageSelectors(ast) { let namedPageSelectors = {}; lib.walk(ast, { visit: "Rule", enter: (node, item, list) => { lib.walk(node, { visit: "Declaration", enter: (declaration, dItem, dList) => { if (declaration.property === "page") { let value = declaration.value.children.first(); let name = value.name; let selector = lib.generate(node.prelude); namedPageSelectors[name] = { name: name, selector: selector }; // dList.remove(dItem); // Add in page break declaration.property = "break-before"; value.type = "Identifier"; value.name = "always"; } } }); } }); return namedPageSelectors; } replaceIds(ast) { lib.walk(ast, { visit: "Rule", enter: (node, item, list) => { lib.walk(node, { visit: "IdSelector", enter: (idNode, idItem, idList) => { let name = idNode.name; idNode.flags = null; idNode.matcher = "="; idNode.name = {type: "Identifier", loc: null, name: "data-id"}; idNode.type = "AttributeSelector"; idNode.value = {type: "String", loc: null, value: `"${name}"`}; } }); } }); } imports(node, item, list) { // console.log("import", node, item, list); let queries = []; lib.walk(node, { visit: "MediaQuery", enter: (mqNode, mqItem, mqList) => { lib.walk(mqNode, { visit: "Identifier", enter: (identNode, identItem, identList) => { queries.push(identNode.name); } }); } }); // Just basic media query support for now let shouldNotApply = queries.some((query, index) => { let q = query; if (q === "not") { q = queries[index + 1]; return !(q === "screen" || q === "speech"); } else { return (q === "screen" || q === "speech"); } }); if (shouldNotApply) { return; } lib.walk(node, { visit: "String", enter: (urlNode, urlItem, urlList) => { let href = urlNode.value.replace(/["']/g, ""); let url = new URL(href, this.url); let value = url.toString(); this.imported.push(value); // Remove the original list.remove(item); } }); } set text(t) { this._text = t; } get text() { return this._text; } // generate string toString(ast) { return lib.generate(ast || this.ast); } } var baseStyles = ` :root { --pagedjs-width: 8.5in; --pagedjs-height: 11in; --pagedjs-width-right: 8.5in; --pagedjs-height-right: 11in; --pagedjs-width-left: 8.5in; --pagedjs-height-left: 11in; --pagedjs-pagebox-width: 8.5in; --pagedjs-pagebox-height: 11in; --pagedjs-margin-top: 1in; --pagedjs-margin-right: 1in; --pagedjs-margin-bottom: 1in; --pagedjs-margin-left: 1in; --pagedjs-padding-top: 0mm; --pagedjs-padding-right: 0mm; --pagedjs-padding-bottom: 0mm; --pagedjs-padding-left: 0mm; --pagedjs-border-top: 0mm; --pagedjs-border-right: 0mm; --pagedjs-border-bottom: 0mm; --pagedjs-border-left: 0mm; --pagedjs-bleed-top: 0mm; --pagedjs-bleed-right: 0mm; --pagedjs-bleed-bottom: 0mm; --pagedjs-bleed-left: 0mm; --pagedjs-bleed-right-top: 0mm; --pagedjs-bleed-right-right: 0mm; --pagedjs-bleed-right-bottom: 0mm; --pagedjs-bleed-right-left: 0mm; --pagedjs-bleed-left-top: 0mm; --pagedjs-bleed-left-right: 0mm; --pagedjs-bleed-left-bottom: 0mm; --pagedjs-bleed-left-left: 0mm; --pagedjs-crop-color: black; --pagedjs-crop-offset: 2mm; --pagedjs-crop-stroke: 1px; --pagedjs-cross-size: 5mm; --pagedjs-mark-cross-display: none; --pagedjs-mark-crop-display: none; --pagedjs-page-count: 0; --pagedjs-page-counter-increment: 1; } @page { size: letter; margin: 0; } .pagedjs_sheet { box-sizing: border-box; width: var(--pagedjs-width); height: var(--pagedjs-height); overflow: hidden; position: relative; display: grid; grid-template-columns: [bleed-left] var(--pagedjs-bleed-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-left) - var(--pagedjs-bleed-right)) [bleed-right] var(--pagedjs-bleed-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-top) - var(--pagedjs-bleed-bottom)) [bleed-bottom] var(--pagedjs-bleed-bottom); } .pagedjs_right_page .pagedjs_sheet { width: var(--pagedjs-width-right); height: var(--pagedjs-height-right); grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-right-left) - var(--pagedjs-bleed-right-right)) [bleed-right] var(--pagedjs-bleed-right-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-right-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-right-top) - var(--pagedjs-bleed-right-bottom)) [bleed-bottom] var(--pagedjs-bleed-right-bottom); } .pagedjs_left_page .pagedjs_sheet { width: var(--pagedjs-width-left); height: var(--pagedjs-height-left); grid-template-columns: [bleed-left] var(--pagedjs-bleed-left-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-left-left) - var(--pagedjs-bleed-left-right)) [bleed-right] var(--pagedjs-bleed-left-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-left-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-left-top) - var(--pagedjs-bleed-left-bottom)) [bleed-bottom] var(--pagedjs-bleed-left-bottom); } .pagedjs_bleed { display: flex; align-items: center; justify-content: center; flex-wrap: nowrap; overflow: hidden; } .pagedjs_bleed-top { grid-column: bleed-left / -1; grid-row: bleed-top; flex-direction: row; } .pagedjs_bleed-bottom { grid-column: bleed-left / -1; grid-row: bleed-bottom; flex-direction: row; } .pagedjs_bleed-left { grid-column: bleed-left; grid-row: bleed-top / -1; flex-direction: column; } .pagedjs_bleed-right { grid-column: bleed-right; grid-row: bleed-top / -1; flex-direction: column; } .pagedjs_marks-crop { display: var(--pagedjs-mark-crop-display); flex-grow: 0; flex-shrink: 0; z-index: 9999999999; } .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-left) - var(--pagedjs-crop-stroke)); border-right: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-right-left) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-right) - var(--pagedjs-crop-stroke)); border-left: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-right-right) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-left-right) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-top .pagedjs_marks-crop { align-self: flex-start; height: calc(var(--pagedjs-bleed-top) - var(--pagedjs-crop-offset)); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-right-top) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-left-top) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-bottom .pagedjs_marks-crop { align-self: flex-end; height: calc(var(--pagedjs-bleed-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-right-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-left-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-top) - var(--pagedjs-crop-stroke)); border-bottom: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-right-top) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-left-top) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-bottom) - var(--pagedjs-crop-stroke)); border-top: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-right-bottom) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-left-bottom) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left) - var(--pagedjs-crop-offset)); align-self: flex-start; } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right-left) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right) - var(--pagedjs-crop-offset)); align-self: flex-end; } .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right-right) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left-right) - var(--pagedjs-crop-offset)); } .pagedjs_marks-middle { display: flex; flex-grow: 1; flex-shrink: 0; align-items: center; justify-content: center; } .pagedjs_marks-cross { display: var(--pagedjs-mark-cross-display); background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIzMi41MzdweCIgaGVpZ2h0PSIzMi41MzdweCIgdmlld0JveD0iMC4xMDQgMC4xMDQgMzIuNTM3IDMyLjUzNyIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwLjEwNCAwLjEwNCAzMi41MzcgMzIuNTM3IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMy4zODkzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIGQ9Ik0yOS45MzEsMTYuMzczYzAsNy40ODktNi4wNjgsMTMuNTYtMTMuNTU4LDEzLjU2Yy03LjQ4MywwLTEzLjU1Ny02LjA3Mi0xMy41NTctMTMuNTZjMC03LjQ4Niw2LjA3NC0xMy41NTQsMTMuNTU3LTEzLjU1NEMyMy44NjIsMi44MTksMjkuOTMxLDguODg3LDI5LjkzMSwxNi4zNzN6Ii8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjMuMzg5MyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMC4xMDQiIHkxPSIxNi4zNzMiIHgyPSIzMi42NDIiIHkyPSIxNi4zNzMiLz48bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMy4zODkzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHgxPSIxNi4zNzMiIHkxPSIwLjEwNCIgeDI9IjE2LjM3MyIgeTI9IjMyLjY0MiIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIzLjM4OTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgZD0iTTI0LjUwOCwxNi4zNzNjMCw0LjQ5Ni0zLjYzOCw4LjEzNS04LjEzNSw4LjEzNWMtNC40OTEsMC04LjEzNS0zLjYzOC04LjEzNS04LjEzNWMwLTQuNDg5LDMuNjQ0LTguMTM1LDguMTM1LTguMTM1QzIwLjg2OSw4LjIzOSwyNC41MDgsMTEuODg0LDI0LjUwOCwxNi4zNzN6Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBkPSJNMjkuOTMxLDE2LjM3M2MwLDcuNDg5LTYuMDY4LDEzLjU2LTEzLjU1OCwxMy41NmMtNy40ODMsMC0xMy41NTctNi4wNzItMTMuNTU3LTEzLjU2YzAtNy40ODYsNi4wNzQtMTMuNTU0LDEzLjU1Ny0xMy41NTRDMjMuODYyLDIuODE5LDI5LjkzMSw4Ljg4NywyOS45MzEsMTYuMzczeiIvPjxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIwLjY3NzgiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjAuMTA0IiB5MT0iMTYuMzczIiB4Mj0iMzIuNjQyIiB5Mj0iMTYuMzczIi8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMTYuMzczIiB5MT0iMC4xMDQiIHgyPSIxNi4zNzMiIHkyPSIzMi42NDIiLz48cGF0aCBkPSJNMjQuNTA4LDE2LjM3M2MwLDQuNDk2LTMuNjM4LDguMTM1LTguMTM1LDguMTM1Yy00LjQ5MSwwLTguMTM1LTMuNjM4LTguMTM1LTguMTM1YzAtNC40ODksMy42NDQtOC4xMzUsOC4xMzUtOC4xMzVDMjAuODY5LDguMjM5LDI0LjUwOCwxMS44ODQsMjQuNTA4LDE2LjM3MyIvPjxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIwLjY3NzgiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjguMjM5IiB5MT0iMTYuMzczIiB4Mj0iMjQuNTA4IiB5Mj0iMTYuMzczIi8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMTYuMzczIiB5MT0iOC4yMzkiIHgyPSIxNi4zNzMiIHkyPSIyNC41MDgiLz48L3N2Zz4=); background-repeat: no-repeat; background-position: 50% 50%; background-size: var(--pagedjs-cross-size); z-index: 2147483647; width: var(--pagedjs-cross-size); height: var(--pagedjs-cross-size); } .pagedjs_pagebox { box-sizing: border-box; width: var(--pagedjs-pagebox-width); height: var(--pagedjs-pagebox-height); position: relative; display: grid; grid-template-columns: [left] var(--pagedjs-margin-left) [center] calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)) [right] var(--pagedjs-margin-right); grid-template-rows: [header] var(--pagedjs-margin-top) [page] calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)) [footer] var(--pagedjs-margin-bottom); grid-column: sheet-center; grid-row: sheet-middle; } .pagedjs_pagebox * { box-sizing: border-box; } .pagedjs_margin-top { width: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)); height: var(--pagedjs-margin-top); grid-column: center; grid-row: header; flex-wrap: nowrap; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 100%; } .pagedjs_margin-top-left-corner-holder { width: var(--pagedjs-margin-left); height: var(--pagedjs-margin-top); display: flex; grid-column: left; grid-row: header; } .pagedjs_margin-top-right-corner-holder { width: var(--pagedjs-margin-right); height: var(--pagedjs-margin-top); display: flex; grid-column: right; grid-row: header; } .pagedjs_margin-top-left-corner { width: var(--pagedjs-margin-left); } .pagedjs_margin-top-right-corner { width: var(--pagedjs-margin-right); } .pagedjs_margin-right { height: calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)); width: var(--pagedjs-margin-right); right: 0; grid-column: right; grid-row: page; display: grid; grid-template-rows: repeat(3, 33.3333%); grid-template-columns: 100%; } .pagedjs_margin-bottom { width: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)); height: var(--pagedjs-margin-bottom); grid-column: center; grid-row: footer; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 100%; } .pagedjs_margin-bottom-left-corner-holder { width: var(--pagedjs-margin-left); height: var(--pagedjs-margin-bottom); display: flex; grid-column: left; grid-row: footer; } .pagedjs_margin-bottom-right-corner-holder { width: var(--pagedjs-margin-right); height: var(--pagedjs-margin-bottom); display: flex; grid-column: right; grid-row: footer; } .pagedjs_margin-bottom-left-corner { width: var(--pagedjs-margin-left); } .pagedjs_margin-bottom-right-corner { width: var(--pagedjs-margin-right); } .pagedjs_margin-left { height: calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)); width: var(--pagedjs-margin-left); grid-column: left; grid-row: page; display: grid; grid-template-rows: repeat(3, 33.33333%); grid-template-columns: 100%; } .pagedjs_pages .pagedjs_pagebox .pagedjs_margin:not(.hasContent) { visibility: hidden; } .pagedjs_pagebox > .pagedjs_area { grid-column: center; grid-row: page; width: 100%; height: 100%; padding: var(--pagedjs-padding-top) var(--pagedjs-padding-right) var(--pagedjs-padding-bottom) var(--pagedjs-padding-left); border-top: var(--pagedjs-border-top); border-right: var(--pagedjs-border-right); border-bottom: var(--pagedjs-border-bottom); border-left: var(--pagedjs-border-left); } .pagedjs_pagebox > .pagedjs_area > .pagedjs_page_content { width: 100%; height: 100%; position: relative; column-fill: auto; } .pagedjs_page { counter-increment: page var(--pagedjs-page-counter-increment); width: var(--pagedjs-width); height: var(--pagedjs-height); } .pagedjs_page.pagedjs_right_page { width: var(--pagedjs-width-right); height: var(--pagedjs-height-right); } .pagedjs_page.pagedjs_left_page { width: var(--pagedjs-width-left); height: var(--pagedjs-height-left); } .pagedjs_pages { counter-reset: pages var(--pagedjs-page-count); } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner, .pagedjs_pagebox .pagedjs_margin-top-left, .pagedjs_pagebox .pagedjs_margin-top-right, .pagedjs_pagebox .pagedjs_margin-bottom-left, .pagedjs_pagebox .pagedjs_margin-bottom-right, .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_margin-right-middle, .pagedjs_margin-left-middle { display: flex; align-items: center; } .pagedjs_margin-right-top, .pagedjs_margin-left-top { display: flex; align-items: flex-top; } .pagedjs_margin-right-bottom, .pagedjs_margin-left-bottom { display: flex; align-items: flex-end; } /* .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center { height: 100%; display: none; align-items: center; flex: 1 0 33%; margin: 0 auto; } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner { display: none; align-items: center; } .pagedjs_pagebox .pagedjs_margin-left-top, .pagedjs_pagebox .pagedjs_margin-right-top { display: none; align-items: flex-start; } .pagedjs_pagebox .pagedjs_margin-right-middle, .pagedjs_pagebox .pagedjs_margin-left-middle { display: none; align-items: center; } .pagedjs_pagebox .pagedjs_margin-left-bottom, .pagedjs_pagebox .pagedjs_margin-right-bottom { display: none; align-items: flex-end; } */ .pagedjs_pagebox .pagedjs_margin-top-left, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner { text-align: left; } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right { text-align: right; } .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_pagebox .pagedjs_margin-left-top, .pagedjs_pagebox .pagedjs_margin-left-middle, .pagedjs_pagebox .pagedjs_margin-left-bottom, .pagedjs_pagebox .pagedjs_margin-right-top, .pagedjs_pagebox .pagedjs_margin-right-middle, .pagedjs_pagebox .pagedjs_margin-right-bottom { text-align: center; } .pagedjs_pages .pagedjs_margin .pagedjs_margin-content { width: 100%; } .pagedjs_pages .pagedjs_margin-left .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-top .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-right .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-bottom .pagedjs_margin-content::after { display: block; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to] { margin-bottom: unset; padding-bottom: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from] { text-indent: unset; margin-top: unset; padding-top: unset; initial-letter: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from] > *::first-letter, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]::first-letter { color: unset; font-size: unset; font-weight: unset; font-family: unset; color: unset; line-height: unset; float: unset; padding: unset; margin: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:after, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]::after { content: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:before, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]::before { content: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div li[data-split-from]:first-of-type { list-style: none; } /* [data-page]:not([data-split-from]), [data-break-before="page"]:not([data-split-from]), [data-break-before="always"]:not([data-split-from]), [data-break-before="left"]:not([data-split-from]), [data-break-before="right"]:not([data-split-from]), [data-break-before="recto"]:not([data-split-from]), [data-break-before="verso"]:not([data-split-from]) { break-before: column; } [data-page]:not([data-split-to]), [data-break-after="page"]:not([data-split-to]), [data-break-after="always"]:not([data-split-to]), [data-break-after="left"]:not([data-split-to]), [data-break-after="right"]:not([data-split-to]), [data-break-after="recto"]:not([data-split-to]), [data-break-after="verso"]:not([data-split-to]) { break-after: column; } */ .pagedjs_clear-after::after { content: none !important; } [data-align-last-split-element='justify'] { text-align-last: justify; } @media print { html { width: 100%; height: 100%; } body { margin: 0; padding: 0; width: 100% !important; height: 100% !important; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; } .pagedjs_pages { width: auto; display: block !important; transform: none !important; height: 100% !important; min-height: 100%; max-height: 100%; overflow: visible; } .pagedjs_page { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; page-break-after: always; break-after: page; } .pagedjs_sheet { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; } } `; async function request(url, options={}) { return new Promise(function(resolve, reject) { let request = new XMLHttpRequest(); request.open(options.method || "get", url, true); for (let i in options.headers) { request.setRequestHeader(i, options.headers[i]); } request.withCredentials = options.credentials === "include"; request.onload = () => { // Chrome returns a status code of 0 for local files const status = request.status === 0 && url.startsWith("file://") ? 200 : request.status; resolve(new Response(request.responseText, {status})); }; request.onerror = reject; request.send(options.body || null); }); } class Polisher { constructor(setup) { this.sheets = []; this.inserted = []; this.hooks = {}; this.hooks.onUrl = new Hook(this); this.hooks.onAtPage = new Hook(this); this.hooks.onAtMedia = new Hook(this); this.hooks.onRule = new Hook(this); this.hooks.onDeclaration = new Hook(this); this.hooks.onContent = new Hook(this); this.hooks.onSelector = new Hook(this); this.hooks.onPseudoSelector = new Hook(this); this.hooks.onImport = new Hook(this); this.hooks.beforeTreeParse = new Hook(this); this.hooks.beforeTreeWalk = new Hook(this); this.hooks.afterTreeWalk = new Hook(this); if (setup !== false) { this.setup(); } } setup() { this.base = this.insert(baseStyles); this.styleEl = document.createElement("style"); document.head.appendChild(this.styleEl); this.styleSheet = this.styleEl.sheet; return this.styleSheet; } async add() { let fetched = []; let urls = []; for (var i = 0; i < arguments.length; i++) { let f; if (typeof arguments[i] === "object") { for (let url in arguments[i]) { let obj = arguments[i]; f = new Promise(function(resolve, reject) { urls.push(url); resolve(obj[url]); }); } } else { urls.push(arguments[i]); f = request(arguments[i]).then((response) => { return response.text(); }); } fetched.push(f); } return await Promise.all(fetched) .then(async (originals) => { let text = ""; for (let index = 0; index < originals.length; index++) { text = await this.convertViaSheet(originals[index], urls[index]); this.insert(text); } return text; }); } async convertViaSheet(cssStr, href) { let sheet = new Sheet(href, this.hooks); await sheet.parse(cssStr); // Insert the imported sheets first for (let url of sheet.imported) { let str = await request(url).then((response) => { return response.text(); }); let text = await this.convertViaSheet(str, url); this.insert(text); } this.sheets.push(sheet); if (typeof sheet.width !== "undefined") { this.width = sheet.width; } if (typeof sheet.height !== "undefined") { this.height = sheet.height; } if (typeof sheet.orientation !== "undefined") { this.orientation = sheet.orientation; } return sheet.toString(); } insert(text){ let head = document.querySelector("head"); let style = document.createElement("style"); style.type = "text/css"; style.setAttribute("data-pagedjs-inserted-styles", "true"); style.appendChild(document.createTextNode(text)); head.appendChild(style); this.inserted.push(style); return style; } destroy() { this.styleEl.remove(); this.inserted.forEach((s) => { s.remove(); }); this.sheets = []; } } class Handler { constructor(chunker, polisher, caller) { let hooks = Object.assign({}, chunker && chunker.hooks, polisher && polisher.hooks, caller && caller.hooks); this.chunker = chunker; this.polisher = polisher; this.caller = caller; for (let name in hooks) { if (name in this) { let hook = hooks[name]; hook.register(this[name].bind(this)); } } } } eventEmitter(Handler.prototype); // https://www.w3.org/TR/css3-page/#page-size-prop var pageSizes = { "A0": { width: { value: 841, unit: "mm" }, height: { value: 1189, unit: "mm" } }, "A1": { width: { value: 594, unit: "mm" }, height: { value: 841, unit: "mm" } }, "A2": { width: { value: 420, unit: "mm" }, height: { value: 594, unit: "mm" } }, "A3": { width: { value: 297, unit: "mm" }, height: { value: 420, unit: "mm" } }, "A4": { width: { value: 210, unit: "mm" }, height: { value: 297, unit: "mm" } }, "A5": { width: { value: 148, unit: "mm" }, height: { value: 210, unit: "mm" } }, "A6": { width: { value: 105, unit: "mm" }, height: { value: 148, unit: "mm" } }, "A7": { width: { value: 74, unit: "mm" }, height: { value: 105, unit: "mm" } }, "A8": { width: { value: 52, unit: "mm" }, height: { value: 74, unit: "mm" } }, "A9": { width: { value: 37, unit: "mm" }, height: { value: 52, unit: "mm" } }, "A10": { width: { value: 26, unit: "mm" }, height: { value: 37, unit: "mm" } }, "B4": { width: { value: 250, unit: "mm" }, height: { value: 353, unit: "mm" } }, "B5": { width: { value: 176, unit: "mm" }, height: { value: 250, unit: "mm" } }, "letter": { width: { value: 8.5, unit: "in" }, height: { value: 11, unit: "in" } }, "legal": { width: { value: 8.5, unit: "in" }, height: { value: 14, unit: "in" } }, "ledger": { width: { value: 11, unit: "in" }, height: { value: 17, unit: "in" } } }; class AtPage extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.pages = {}; this.width = undefined; this.height = undefined; this.orientation = undefined; this.marginalia = {}; } pageModel(selector) { return { selector: selector, name: undefined, psuedo: undefined, nth: undefined, marginalia: {}, width: undefined, height: undefined, orientation: undefined, margin: { top: {}, right: {}, left: {}, bottom: {} }, padding: { top: {}, right: {}, left: {}, bottom: {} }, border: { top: {}, right: {}, left: {}, bottom: {} }, backgroundOrigin: undefined, block: {}, marks: undefined }; } // Find and Remove @page rules onAtPage(node, item, list) { let page, marginalia; let selector = ""; let named, psuedo, nth; let needsMerge = false; if (node.prelude) { named = this.getTypeSelector(node); psuedo = this.getPsuedoSelector(node); nth = this.getNthSelector(node); selector = lib.generate(node.prelude); } else { selector = "*"; } if (selector in this.pages) { // this.pages[selector] = Object.assign(this.pages[selector], page); // console.log("after", selector, this.pages[selector]); // this.pages[selector].added = false; page = this.pages[selector]; marginalia = this.replaceMarginalia(node); needsMerge = true; } else { page = this.pageModel(selector); marginalia = this.replaceMarginalia(node); this.pages[selector] = page; } page.name = named; page.psuedo = psuedo; page.nth = nth; if (needsMerge) { page.marginalia = Object.assign(page.marginalia, marginalia); } else { page.marginalia = marginalia; } let declarations = this.replaceDeclarations(node); if (declarations.size) { page.size = declarations.size; page.width = declarations.size.width; page.height = declarations.size.height; page.orientation = declarations.size.orientation; page.format = declarations.size.format; } if (declarations.bleed && declarations.bleed[0] != "auto") { switch (declarations.bleed.length) { case 4: // top right bottom left page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[2], left: declarations.bleed[3] }; break; case 3: // top right bottom right page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[2], left: declarations.bleed[1] }; break; case 2: // top right top right page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[0], left: declarations.bleed[1] }; break; default: page.bleed = { top: declarations.bleed[0], right: declarations.bleed[0], bottom: declarations.bleed[0], left: declarations.bleed[0] }; } } if (declarations.marks) { if (!declarations.bleed || declarations.bleed && declarations.bleed[0] === "auto") { // Spec say 6pt, but needs more space for marks page.bleed = { top: { value: 6, unit: "mm" }, right: { value: 6, unit: "mm" }, bottom: { value: 6, unit: "mm" }, left: { value: 6, unit: "mm" } }; } page.marks = declarations.marks; } if (declarations.margin) { page.margin = declarations.margin; } if (declarations.padding) { page.padding = declarations.padding; } if (declarations.border) { page.border = declarations.border; } if (declarations.marks) { page.marks = declarations.marks; } if (needsMerge) { page.block.children.appendList(node.block.children); } else { page.block = node.block; } // Remove the rule list.remove(item); } /* Handled in breaks */ /* afterParsed(parsed) { for (let b in this.named) { // Find elements let elements = parsed.querySelectorAll(b); // Add break data for (var i = 0; i < elements.length; i++) { elements[i].setAttribute("data-page", this.named[b]); } } } */ afterTreeWalk(ast, sheet) { this.addPageClasses(this.pages, ast, sheet); if ("*" in this.pages) { let width = this.pages["*"].width; let height = this.pages["*"].height; let format = this.pages["*"].format; let orientation = this.pages["*"].orientation; let bleed = this.pages["*"].bleed; let marks = this.pages["*"].marks; let bleedverso = undefined; let bleedrecto = undefined; if (":left" in this.pages) { bleedverso = this.pages[":left"].bleed; } if (":right" in this.pages) { bleedrecto = this.pages[":right"].bleed; } if ((width && height) && (this.width !== width || this.height !== height)) { this.width = width; this.height = height; this.format = format; this.orientation = orientation; this.addRootVars(ast, width, height, orientation, bleed, bleedrecto, bleedverso, marks); this.addRootPage(ast, this.pages["*"].size, bleed, bleedrecto, bleedverso); this.emit("size", { width, height, orientation, format, bleed }); this.emit("atpages", this.pages); } } } getTypeSelector(ast) { // Find page name let name; lib.walk(ast, { visit: "TypeSelector", enter: (node, item, list) => { name = node.name; } }); return name; } getPsuedoSelector(ast) { // Find if it has :left & :right & :black & :first let name; lib.walk(ast, { visit: "PseudoClassSelector", enter: (node, item, list) => { if (node.name !== "nth") { name = node.name; } } }); return name; } getNthSelector(ast) { // Find if it has :nth let nth; lib.walk(ast, { visit: "PseudoClassSelector", enter: (node, item, list) => { if (node.name === "nth" && node.children) { let raw = node.children.first(); nth = raw.value; } } }); return nth; } replaceMarginalia(ast) { let parsed = {}; lib.walk(ast.block, { visit: "Atrule", enter: (node, item, list) => { let name = node.name; if (name === "top") { name = "top-center"; } if (name === "right") { name = "right-middle"; } if (name === "left") { name = "left-middle"; } if (name === "bottom") { name = "bottom-center"; } parsed[name] = node.block; list.remove(item); } }); return parsed; } replaceDeclarations(ast) { let parsed = {}; lib.walk(ast.block, { visit: "Declaration", enter: (declaration, dItem, dList) => { let prop = lib.property(declaration.property).name; // let value = declaration.value; if (prop === "marks") { parsed.marks = []; lib.walk(declaration, { visit: "Identifier", enter: (ident) => { parsed.marks.push(ident.name); } }); dList.remove(dItem); } else if (prop === "margin") { parsed.margin = this.getMargins(declaration); dList.remove(dItem); } else if (prop.indexOf("margin-") === 0) { let m = prop.substring("margin-".length); if (!parsed.margin) { parsed.margin = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.margin[m] = declaration.value.children.first(); dList.remove(dItem); } else if (prop === "padding") { parsed.padding = this.getPaddings(declaration.value); dList.remove(dItem); } else if (prop.indexOf("padding-") === 0) { let p = prop.substring("padding-".length); if (!parsed.padding) { parsed.padding = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.padding[p] = declaration.value.children.first(); dList.remove(dItem); } else if (prop === "border") { if (!parsed.border) { parsed.border = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.border.top = lib.generate(declaration.value); parsed.border.right = lib.generate(declaration.value); parsed.border.left = lib.generate(declaration.value); parsed.border.bottom = lib.generate(declaration.value); dList.remove(dItem); } else if (prop.indexOf("border-") === 0) { if (!parsed.border) { parsed.border = { top: {}, right: {}, left: {}, bottom: {} }; } let p = prop.substring("border-".length); parsed.border[p] = lib.generate(declaration.value); dList.remove(dItem); } else if (prop === "size") { parsed.size = this.getSize(declaration); dList.remove(dItem); } else if (prop === "bleed") { parsed.bleed = []; lib.walk(declaration, { enter: (subNode) => { switch (subNode.type) { case "String": // bleed: "auto" if (subNode.value.indexOf("auto") > -1) { parsed.bleed.push("auto"); } break; case "Dimension": // bleed: 1in 2in, bleed: 20px ect. parsed.bleed.push({ value: subNode.value, unit: subNode.unit }); break; case "Number": parsed.bleed.push({ value: subNode.value, unit: "px" }); break; // ignore } } }); dList.remove(dItem); } } }); return parsed; } getSize(declaration) { let width, height, orientation, format; // Get size: Xmm Ymm lib.walk(declaration, { visit: "Dimension", enter: (node, item, list) => { let { value, unit } = node; if (typeof width === "undefined") { width = { value, unit }; } else if (typeof height === "undefined") { height = { value, unit }; } } }); // Get size: "A4" lib.walk(declaration, { visit: "String", enter: (node, item, list) => { let name = node.value.replace(/["|']/g, ""); let s = pageSizes[name]; if (s) { width = s.width; height = s.height; } } }); // Get Format or Landscape or Portrait lib.walk(declaration, { visit: "Identifier", enter: (node, item, list) => { let name = node.name; if (name === "landscape" || name === "portrait") { orientation = node.name; } else if (name !== "auto") { let s = pageSizes[name]; if (s) { width = s.width; height = s.height; } format = name; } } }); return { width, height, orientation, format }; } getMargins(declaration) { let margins = []; let margin = { top: {}, right: {}, left: {}, bottom: {} }; lib.walk(declaration, { enter: (node) => { switch (node.type) { case "Dimension": // margin: 1in 2in, margin: 20px, etc... margins.push(node); break; case "Number": // margin: 0 margins.push({value: node.value, unit: "px"}); break; // ignore } } }); if (margins.length === 1) { for (let m in margin) { margin[m] = margins[0]; } } else if (margins.length === 2) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[0]; margin.left = margins[1]; } else if (margins.length === 3) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[2]; margin.left = margins[1]; } else if (margins.length === 4) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[2]; margin.left = margins[3]; } return margin; } getPaddings(declaration) { let paddings = []; let padding = { top: {}, right: {}, left: {}, bottom: {} }; lib.walk(declaration, { enter: (node) => { switch (node.type) { case "Dimension": // padding: 1in 2in, padding: 20px, etc... paddings.push(node); break; case "Number": // padding: 0 paddings.push({value: node.value, unit: "px"}); break; // ignore } } }); if (paddings.length === 1) { for (let p in padding) { padding[p] = paddings[0]; } } else if (paddings.length === 2) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[0]; padding.left = paddings[1]; } else if (paddings.length === 3) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[2]; padding.left = paddings[1]; } else if (paddings.length === 4) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[2]; padding.left = paddings[3]; } return padding; } // get values for the border on the @page to pass them to the element with the .pagedjs_area class getBorders(declaration) { let border = { top: {}, right: {}, left: {}, bottom: {} }; if (declaration.prop == "border") { border.top = lib.generate(declaration.value); border.right = lib.generate(declaration.value); border.bottom = lib.generate(declaration.value); border.left = lib.generate(declaration.value); } else if (declaration.prop == "border-top") { border.top = lib.generate(declaration.value); } else if (declaration.prop == "border-right") { border.right = lib.generate(declaration.value); } else if (declaration.prop == "border-bottom") { border.bottom = lib.generate(declaration.value); } else if (declaration.prop == "border-left") { border.left = lib.generate(declaration.value); } return border; } addPageClasses(pages, ast, sheet) { // First add * page if ("*" in pages) { let p = this.createPage(pages["*"], ast.children, sheet); sheet.insertRule(p); } // Add :left & :right if (":left" in pages) { let left = this.createPage(pages[":left"], ast.children, sheet); sheet.insertRule(left); } if (":right" in pages) { let right = this.createPage(pages[":right"], ast.children, sheet); sheet.insertRule(right); } // Add :first & :blank if (":first" in pages) { let first = this.createPage(pages[":first"], ast.children, sheet); sheet.insertRule(first); } if (":blank" in pages) { let blank = this.createPage(pages[":blank"], ast.children, sheet); sheet.insertRule(blank); } // Add nth pages for (let pg in pages) { if (pages[pg].nth) { let nth = this.createPage(pages[pg], ast.children, sheet); sheet.insertRule(nth); } } // Add named pages for (let pg in pages) { if (pages[pg].name) { let named = this.createPage(pages[pg], ast.children, sheet); sheet.insertRule(named); } } } createPage(page, ruleList, sheet) { let selectors = this.selectorsForPage(page); let children = page.block.children.copy(); let block = { type: "Block", loc: 0, children: children }; let rule = this.createRule(selectors, block); this.addMarginVars(page.margin, children, children.first()); this.addPaddingVars(page.padding, children, children.first()); this.addBorderVars(page.border, children, children.first()); if (page.width) { this.addDimensions(page.width, page.height, page.orientation, children, children.first()); } if (page.marginalia) { this.addMarginaliaStyles(page, ruleList, rule, sheet); this.addMarginaliaContent(page, ruleList, rule, sheet); } return rule; } addMarginVars(margin, list, item) { // variables for margins for (let m in margin) { if (typeof margin[m].value !== "undefined") { let value = margin[m].value + (margin[m].unit || ""); let mVar = list.createItem({ type: "Declaration", property: "--pagedjs-margin-" + m, value: { type: "Raw", value: value } }); list.append(mVar, item); } } } addPaddingVars(padding, list, item) { // variables for padding for (let p in padding) { if (typeof padding[p].value !== "undefined") { let value = padding[p].value + (padding[p].unit || ""); let pVar = list.createItem({ type: "Declaration", property: "--pagedjs-padding-" + p, value: { type: "Raw", value: value } }); list.append(pVar, item); } } } addBorderVars(border, list, item) { // variables for borders for (let b in border) { if (typeof border[b] !== "undefined") { let value = border[b]; let bVar = list.createItem({ type: "Declaration", property: "--pagedjs-border-" + b, value: { type: "Raw", value: value } }); list.append(bVar, item); } } } addDimensions(width, height, orientation, list, item) { let widthString, heightString; widthString = CSSValueToString(width); heightString = CSSValueToString(height); if (orientation && orientation !== "portrait") { // reverse for orientation [widthString, heightString] = [heightString, widthString]; } // width variable let wVar = this.createVariable("--pagedjs-pagebox-width", widthString); list.appendData(wVar); // height variable let hVar = this.createVariable("--pagedjs-pagebox-height", heightString); list.appendData(hVar); // let w = this.createDimension("width", width); // let h = this.createDimension("height", height); // list.appendData(w); // list.appendData(h); } addMarginaliaStyles(page, list, item, sheet) { for (let loc in page.marginalia) { let block = lib.clone(page.marginalia[loc]); let hasContent = false; if (block.children.isEmpty()) { continue; } lib.walk(block, { visit: "Declaration", enter: (node, item, list) => { if (node.property === "content") { if (node.value.children && node.value.children.first().name === "none") { hasContent = false; } else { hasContent = true; } list.remove(item); } if (node.property === "vertical-align") { lib.walk(node, { visit: "Identifier", enter: (identNode, identItem, identlist) => { let name = identNode.name; if (name === "top") { identNode.name = "flex-start"; } else if (name === "middle") { identNode.name = "center"; } else if (name === "bottom") { identNode.name = "flex-end"; } } }); node.property = "align-items"; } if (node.property === "width" && (loc === "top-left" || loc === "top-center" || loc === "top-right" || loc === "bottom-left" || loc === "bottom-center" || loc === "bottom-right")) { let c = lib.clone(node); c.property = "max-width"; list.appendData(c); } if (node.property === "height" && (loc === "left-top" || loc === "left-middle" || loc === "left-bottom" || loc === "right-top" || loc === "right-middle" || loc === "right-bottom")) { let c = lib.clone(node); c.property = "max-height"; list.appendData(c); } } }); let marginSelectors = this.selectorsForPageMargin(page, loc); let marginRule = this.createRule(marginSelectors, block); list.appendData(marginRule); let sel = lib.generate({ type: "Selector", children: marginSelectors }); this.marginalia[sel] = { page: page, selector: sel, block: page.marginalia[loc], hasContent: hasContent }; } } addMarginaliaContent(page, list, item, sheet) { let displayNone; // Just content for (let loc in page.marginalia) { let content = lib.clone(page.marginalia[loc]); lib.walk(content, { visit: "Declaration", enter: (node, item, list) => { if (node.property !== "content") { list.remove(item); } if (node.value.children && node.value.children.first().name === "none") { displayNone = true; } } }); if (content.children.isEmpty()) { continue; } let displaySelectors = this.selectorsForPageMargin(page, loc); let displayDeclaration; displaySelectors.insertData({ type: "Combinator", name: ">" }); displaySelectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-content" }); displaySelectors.insertData({ type: "Combinator", name: ">" }); displaySelectors.insertData({ type: "TypeSelector", name: "*" }); if (displayNone) { displayDeclaration = this.createDeclaration("display", "none"); } else { displayDeclaration = this.createDeclaration("display", "block"); } let displayRule = this.createRule(displaySelectors, [displayDeclaration]); sheet.insertRule(displayRule); // insert content rule let contentSelectors = this.selectorsForPageMargin(page, loc); contentSelectors.insertData({ type: "Combinator", name: ">" }); contentSelectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-content" }); contentSelectors.insertData({ type: "PseudoElementSelector", name: "after", children: null }); let contentRule = this.createRule(contentSelectors, content); sheet.insertRule(contentRule); } } addRootVars(ast, width, height, orientation, bleed, bleedrecto, bleedverso, marks) { let rules = []; let selectors = new lib.List(); selectors.insertData({ type: "PseudoClassSelector", name: "root", children: null }); let widthString, heightString; let widthStringRight, heightStringRight; let widthStringLeft, heightStringLeft; if (!bleed) { widthString = CSSValueToString(width); heightString = CSSValueToString(height); widthStringRight = CSSValueToString(width); heightStringRight = CSSValueToString(height); widthStringLeft = CSSValueToString(width); heightStringLeft = CSSValueToString(height); } else { widthString = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightString = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; widthStringRight = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightStringRight = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; widthStringLeft = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; let bleedTop = this.createVariable("--pagedjs-bleed-top", CSSValueToString(bleed.top)); let bleedRight = this.createVariable("--pagedjs-bleed-right", CSSValueToString(bleed.right)); let bleedBottom = this.createVariable("--pagedjs-bleed-bottom", CSSValueToString(bleed.bottom)); let bleedLeft = this.createVariable("--pagedjs-bleed-left", CSSValueToString(bleed.left)); let bleedTopRecto = this.createVariable("--pagedjs-bleed-right-top", CSSValueToString(bleed.top)); let bleedRightRecto = this.createVariable("--pagedjs-bleed-right-right", CSSValueToString(bleed.right)); let bleedBottomRecto = this.createVariable("--pagedjs-bleed-right-bottom", CSSValueToString(bleed.bottom)); let bleedLeftRecto = this.createVariable("--pagedjs-bleed-right-left", CSSValueToString(bleed.left)); let bleedTopVerso = this.createVariable("--pagedjs-bleed-left-top", CSSValueToString(bleed.top)); let bleedRightVerso = this.createVariable("--pagedjs-bleed-left-right", CSSValueToString(bleed.right)); let bleedBottomVerso = this.createVariable("--pagedjs-bleed-left-bottom", CSSValueToString(bleed.bottom)); let bleedLeftVerso = this.createVariable("--pagedjs-bleed-left-left", CSSValueToString(bleed.left)); if (bleedrecto) { bleedTopRecto = this.createVariable("--pagedjs-bleed-right-top", CSSValueToString(bleedrecto.top)); bleedRightRecto = this.createVariable("--pagedjs-bleed-right-right", CSSValueToString(bleedrecto.right)); bleedBottomRecto = this.createVariable("--pagedjs-bleed-right-bottom", CSSValueToString(bleedrecto.bottom)); bleedLeftRecto = this.createVariable("--pagedjs-bleed-right-left", CSSValueToString(bleedrecto.left)); widthStringRight = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleedrecto.left)} + ${CSSValueToString(bleedrecto.right)} )`; heightStringRight = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedrecto.top)} + ${CSSValueToString(bleedrecto.bottom)} )`; } if (bleedverso) { bleedTopVerso = this.createVariable("--pagedjs-bleed-left-top", CSSValueToString(bleedverso.top)); bleedRightVerso = this.createVariable("--pagedjs-bleed-left-right", CSSValueToString(bleedverso.right)); bleedBottomVerso = this.createVariable("--pagedjs-bleed-left-bottom", CSSValueToString(bleedverso.bottom)); bleedLeftVerso = this.createVariable("--pagedjs-bleed-left-left", CSSValueToString(bleedverso.left)); widthStringLeft = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleedverso.left)} + ${CSSValueToString(bleedverso.right)} )`; heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedverso.top)} + ${CSSValueToString(bleedverso.bottom)} )`; } let pageWidthVar = this.createVariable("--pagedjs-width", CSSValueToString(width)); let pageHeightVar = this.createVariable("--pagedjs-height", CSSValueToString(height)); rules.push( bleedTop, bleedRight, bleedBottom, bleedLeft, bleedTopRecto, bleedRightRecto, bleedBottomRecto, bleedLeftRecto, bleedTopVerso, bleedRightVerso, bleedBottomVerso, bleedLeftVerso, pageWidthVar, pageHeightVar ); } if (marks) { marks.forEach((mark) => { let markDisplay = this.createVariable("--pagedjs-mark-" + mark + "-display", "block"); rules.push(markDisplay); }); } // orientation variable if (orientation) { let oVar = this.createVariable("--pagedjs-orientation", orientation); rules.push(oVar); if (orientation !== "portrait") { // reverse for orientation [widthString, heightString] = [heightString, widthString]; [widthStringRight, heightStringRight] = [heightStringRight, widthStringRight]; [widthStringLeft, heightStringLeft] = [heightStringLeft, widthStringLeft]; } } let wVar = this.createVariable("--pagedjs-width", widthString); let hVar = this.createVariable("--pagedjs-height", heightString); let wVarR = this.createVariable("--pagedjs-width-right", widthStringRight); let hVarR = this.createVariable("--pagedjs-height-right", heightStringRight); let wVarL = this.createVariable("--pagedjs-width-left", widthStringLeft); let hVarL = this.createVariable("--pagedjs-height-left", heightStringLeft); rules.push(wVar, hVar, wVarR, hVarR, wVarL, hVarL); let rule = this.createRule(selectors, rules); ast.children.appendData(rule); } /* @page { size: var(--pagedjs-width) var(--pagedjs-height); margin: 0; padding: 0; } */ addRootPage(ast, size, bleed, bleedrecto, bleedverso) { let { width, height, orientation, format } = size; let children = new lib.List(); let childrenLeft = new lib.List(); let childrenRight = new lib.List(); let dimensions = new lib.List(); let dimensionsLeft = new lib.List(); let dimensionsRight = new lib.List(); if (bleed) { let widthCalculations = new lib.List(); let heightCalculations = new lib.List(); // width widthCalculations.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Operator", value: "+" }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Dimension", unit: bleed.left.unit, value: bleed.left.value }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Operator", value: "+" }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Dimension", unit: bleed.right.unit, value: bleed.right.value }); // height heightCalculations.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Operator", value: "+" }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Dimension", unit: bleed.top.unit, value: bleed.top.value }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Operator", value: "+" }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Dimension", unit: bleed.bottom.unit, value: bleed.bottom.value }); dimensions.appendData({ type: "Function", name: "calc", children: widthCalculations }); dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Function", name: "calc", children: heightCalculations }); } else if (format) { dimensions.appendData({ type: "Identifier", name: format }); if (orientation) { dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Identifier", name: orientation }); } } else { dimensions.appendData({ type: "Dimension", unit: width.unit, value: width.value }); dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Dimension", unit: height.unit, value: height.value }); } children.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensions } }); children.appendData({ type: "Declaration", property: "margin", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); children.appendData({ type: "Declaration", property: "padding", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); children.appendData({ type: "Declaration", property: "padding", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); let rule = ast.children.createItem({ type: "Atrule", prelude: null, name: "page", block: { type: "Block", loc: null, children: children } }); ast.children.append(rule); if (bleedverso) { let widthCalculationsLeft = new lib.List(); let heightCalculationsLeft = new lib.List(); // width widthCalculationsLeft.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Operator", value: "+" }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.left.unit, value: bleedverso.left.value }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Operator", value: "+" }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.right.unit, value: bleedverso.right.value }); // height heightCalculationsLeft.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Operator", value: "+" }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.top.unit, value: bleedverso.top.value }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Operator", value: "+" }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.bottom.unit, value: bleedverso.bottom.value }); dimensionsLeft.appendData({ type: "Function", name: "calc", children: widthCalculationsLeft }); dimensionsLeft.appendData({ type: "WhiteSpace", value: " " }); dimensionsLeft.appendData({ type: "Function", name: "calc", children: heightCalculationsLeft }); childrenLeft.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensionsLeft } }); let ruleLeft = ast.children.createItem({ type: "Atrule", prelude: null, name: "page :left", block: { type: "Block", loc: null, children: childrenLeft } }); ast.children.append(ruleLeft); } if (bleedrecto) { let widthCalculationsRight = new lib.List(); let heightCalculationsRight = new lib.List(); // width widthCalculationsRight.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Operator", value: "+" }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.left.unit, value: bleedrecto.left.value }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Operator", value: "+" }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.right.unit, value: bleedrecto.right.value }); // height heightCalculationsRight.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Operator", value: "+" }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.top.unit, value: bleedrecto.top.value }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Operator", value: "+" }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.bottom.unit, value: bleedrecto.bottom.value }); dimensionsRight.appendData({ type: "Function", name: "calc", children: widthCalculationsRight }); dimensionsRight.appendData({ type: "WhiteSpace", value: " " }); dimensionsRight.appendData({ type: "Function", name: "calc", children: heightCalculationsRight }); childrenRight.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensionsRight } }); let ruleRight = ast.children.createItem({ type: "Atrule", prelude: null, name: "page :right", block: { type: "Block", loc: null, children: childrenRight } }); ast.children.append(ruleRight); } } getNth(nth) { let n = nth.indexOf("n"); let plus = nth.indexOf("+"); let splitN = nth.split("n"); let splitP = nth.split("+"); let a = null; let b = null; if (n > -1) { a = splitN[0]; if (plus > -1) { b = splitP[1]; } } else { b = nth; } return { type: "Nth", loc: null, selector: null, nth: { type: "AnPlusB", loc: null, a: a, b: b } }; } addPageAttributes(page, start, pages) { let named = start.dataset.page; if (named) { page.name = named; page.element.classList.add("pagedjs_named_page"); page.element.classList.add("pagedjs_" + named + "_page"); if (!start.dataset.splitFrom) { page.element.classList.add("pagedjs_" + named + "_first_page"); } } } getStartElement(content, breakToken) { let node = breakToken && breakToken.node; if (!content && !breakToken) { return; } // No break if (!node) { return content.children[0]; } // Top level element if (node.nodeType === 1 && node.parentNode.nodeType === 11) { return node; } // Named page if (node.nodeType === 1 && node.dataset.page) { return node; } // Get top level Named parent let fragment = rebuildAncestors(node); let pages = fragment.querySelectorAll("[data-page]"); if (pages.length) { return pages[pages.length - 1]; } else { return fragment.children[0]; } } beforePageLayout(page, contents, breakToken, chunker) { let start = this.getStartElement(contents, breakToken); if (start) { this.addPageAttributes(page, start, chunker.pages); } // page.element.querySelector('.paged_area').style.color = red; } afterPageLayout(fragment, page, breakToken, chunker) { for (let m in this.marginalia) { let margin = this.marginalia[m]; let sels = m.split(" "); let content; if (page.element.matches(sels[0]) && margin.hasContent) { content = page.element.querySelector(sels[1]); content.classList.add("hasContent"); } } // check center ["top", "bottom"].forEach((loc) => { let marginGroup = page.element.querySelector(".pagedjs_margin-" + loc); let center = page.element.querySelector(".pagedjs_margin-" + loc + "-center"); let left = page.element.querySelector(".pagedjs_margin-" + loc + "-left"); let right = page.element.querySelector(".pagedjs_margin-" + loc + "-right"); let centerContent = center.classList.contains("hasContent"); let leftContent = left.classList.contains("hasContent"); let rightContent = right.classList.contains("hasContent"); let centerWidth, leftWidth, rightWidth; if (leftContent) { leftWidth = window.getComputedStyle(left)["max-width"]; } if (rightContent) { rightWidth = window.getComputedStyle(right)["max-width"]; } if (centerContent) { centerWidth = window.getComputedStyle(center)["max-width"]; if (centerWidth === "none" || centerWidth === "auto") { if (!leftContent && !rightContent) { marginGroup.style["grid-template-columns"] = "0 1fr 0"; } else if (leftContent) { if (!rightContent) { if (leftWidth !== "none" && leftWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + leftWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; left.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let centerOuterWidth = center.offsetWidth; let outerwidths = leftOuterWidth + centerOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; left.style["white-space"] = "normal"; center.style["white-space"] = "normal"; } } else { if (leftWidth !== "none" && leftWidth !== "auto") { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + leftWidth; } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = rightWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; left.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; right.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let centerOuterWidth = center.offsetWidth; let rightOuterWidth = right.offsetWidth; let outerwidths = leftOuterWidth + centerOuterWidth + rightOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; if (newcenterWidth > 40) { marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; } else { marginGroup.style["grid-template-columns"] = "repeat(3, 1fr)"; } left.style["white-space"] = "normal"; center.style["white-space"] = "normal"; right.style["white-space"] = "normal"; } } } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = rightWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; right.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; let rightOuterWidth = right.offsetWidth; let centerOuterWidth = center.offsetWidth; let outerwidths = rightOuterWidth + centerOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; right.style["white-space"] = "normal"; center.style["white-space"] = "normal"; } } } else if (centerWidth !== "none" && centerWidth !== "auto") { if (leftContent && leftWidth !== "none" && leftWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " " + centerWidth + " 1fr"; } else if (rightContent && rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr " + centerWidth + " " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "1fr " + centerWidth + " 1fr"; } } } else { if (leftContent) { if (!rightContent) { marginGroup.style["grid-template-columns"] = "1fr 0 0"; } else { if (leftWidth !== "none" && leftWidth !== "auto") { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = leftWidth + " 0 1fr"; } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr 0 " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto 1fr auto"; left.style["white-space"] = "nowrap"; right.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let rightOuterWidth = right.offsetWidth; let outerwidths = leftOuterWidth + rightOuterWidth; let newLeftWidth = leftOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, " + newLeftWidth + "%) 0 1fr"; left.style["white-space"] = "normal"; right.style["white-space"] = "normal"; } } } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr 0 " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "0 0 1fr"; } } } }); // check middle ["left", "right"].forEach((loc) => { let middle = page.element.querySelector(".pagedjs_margin-" + loc + "-middle.hasContent"); let marginGroup = page.element.querySelector(".pagedjs_margin-" + loc); let top = page.element.querySelector(".pagedjs_margin-" + loc + "-top"); let bottom = page.element.querySelector(".pagedjs_margin-" + loc + "-bottom"); let topContent = top.classList.contains("hasContent"); let bottomContent = bottom.classList.contains("hasContent"); let middleHeight, topHeight, bottomHeight; if (topContent) { topHeight = window.getComputedStyle(top)["max-height"]; } if (bottomContent) { bottomHeight = window.getComputedStyle(bottom)["max-height"]; } if (middle) { middleHeight = window.getComputedStyle(middle)["max-height"]; if (middleHeight === "none" || middleHeight === "auto") { if (!topContent && !bottomContent) { marginGroup.style["grid-template-rows"] = "0 1fr 0"; } else if (topContent) { if (!bottomContent) { if (topHeight !== "none" && topHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + "*2) " + topHeight; } } else { if (topHeight !== "none" && topHeight !== "auto") { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + " - " + bottomHeight + ") " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + "*2) " + topHeight; } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = bottomHeight + " calc(100% - " + bottomHeight + "*2) " + bottomHeight; } } } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = bottomHeight + " calc(100% - " + bottomHeight + "*2) " + bottomHeight; } } } else { if (topContent && topHeight !== "none" && topHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " " + middleHeight + " calc(100% - (" + topHeight + " + " + middleHeight + "))"; } else if (bottomContent && bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr " + middleHeight + " " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "calc((100% - " + middleHeight + ")/2) " + middleHeight + " calc((100% - " + middleHeight + ")/2)"; } } } else { if (topContent) { if (!bottomContent) { marginGroup.style["grid-template-rows"] = "1fr 0 0"; } else { if (topHeight !== "none" && topHeight !== "auto") { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " 1fr " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = topHeight + " 0 1fr"; } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr 0 " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "1fr 0 1fr"; } } } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr 0 " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "0 0 1fr"; } } } }); } // CSS Tree Helpers selectorsForPage(page) { let nthlist; let nth; let selectors = new lib.List(); selectors.insertData({ type: "ClassSelector", name: "pagedjs_page" }); // Named page if (page.name) { selectors.insertData({ type: "ClassSelector", name: "pagedjs_named_page" }); selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.name + "_page" }); } // PsuedoSelector if (page.psuedo && !(page.name && page.psuedo === "first")) { selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.psuedo + "_page" }); } if (page.name && page.psuedo === "first") { selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.name + "_" + page.psuedo + "_page" }); } // Nth if (page.nth) { nthlist = new lib.List(); nth = this.getNth(page.nth); nthlist.insertData(nth); selectors.insertData({ type: "PseudoClassSelector", name: "nth-of-type", children: nthlist }); } return selectors; } selectorsForPageMargin(page, margin) { let selectors = this.selectorsForPage(page); selectors.insertData({ type: "Combinator", name: " " }); selectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-" + margin }); return selectors; } createDeclaration(property, value, important) { let children = new lib.List(); children.insertData({ type: "Identifier", loc: null, name: value }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createVariable(property, value) { return { type: "Declaration", loc: null, property: property, value: { type: "Raw", value: value } }; } createCalculatedDimension(property, items, important, operator = "+") { let children = new lib.List(); let calculations = new lib.List(); items.forEach((item, index) => { calculations.appendData({ type: "Dimension", unit: item.unit, value: item.value }); calculations.appendData({ type: "WhiteSpace", value: " " }); if (index + 1 < items.length) { calculations.appendData({ type: "Operator", value: operator }); calculations.appendData({ type: "WhiteSpace", value: " " }); } }); children.insertData({ type: "Function", loc: null, name: "calc", children: calculations }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createDimension(property, cssValue, important) { let children = new lib.List(); children.insertData({ type: "Dimension", loc: null, value: cssValue.value, unit: cssValue.unit }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createBlock(declarations) { let block = new lib.List(); declarations.forEach((declaration) => { block.insertData(declaration); }); return { type: "Block", loc: null, children: block }; } createRule(selectors, block) { let selectorList = new lib.List(); selectorList.insertData({ type: "Selector", children: selectors }); if (Array.isArray(block)) { block = this.createBlock(block); } return { type: "Rule", prelude: { type: "SelectorList", children: selectorList }, block: block }; } } class Breaks extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.breaks = {}; } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "page") { let children = declaration.value.children.first(); let value = children.name; let selector = lib.generate(rule.ruleNode.prelude); let name = value; let breaker = { property: property, value: value, selector: selector, name: name }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); dList.remove(dItem); } if (property === "break-before" || property === "break-after" || property === "page-break-before" || property === "page-break-after" ) { let child = declaration.value.children.first(); let value = child.name; let selector = lib.generate(rule.ruleNode.prelude); if (property === "page-break-before") { property = "break-before"; } else if (property === "page-break-after") { property = "break-after"; } let breaker = { property: property, value: value, selector: selector }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); // Remove from CSS -- handle right / left in module dList.remove(dItem); } } afterParsed(parsed) { this.processBreaks(parsed, this.breaks); } processBreaks(parsed, breaks) { for (let b in breaks) { // Find elements let elements = parsed.querySelectorAll(b); // Add break data for (var i = 0; i < elements.length; i++) { for (let prop of breaks[b]) { if (prop.property === "break-after") { let nodeAfter = displayedElementAfter(elements[i], parsed); elements[i].setAttribute("data-break-after", prop.value); if (nodeAfter) { nodeAfter.setAttribute("data-previous-break-after", prop.value); } } else if (prop.property === "break-before") { let nodeBefore = displayedElementBefore(elements[i], parsed); // Breaks are only allowed between siblings, not between a box and its container. // If we cannot find a node before we should not break! // https://drafts.csswg.org/css-break-3/#break-propagation if (nodeBefore) { if (prop.value === "page" && needsPageBreak(elements[i], nodeBefore)) { // we ignore this explicit page break because an implicit page break is already needed continue; } elements[i].setAttribute("data-break-before", prop.value); nodeBefore.setAttribute("data-next-break-before", prop.value); } } else if (prop.property === "page") { elements[i].setAttribute("data-page", prop.value); let nodeAfter = displayedElementAfter(elements[i], parsed); if (nodeAfter) { nodeAfter.setAttribute("data-after-page", prop.value); } } else { elements[i].setAttribute("data-" + prop.property, prop.value); } } } } } mergeBreaks(pageBreaks, newBreaks) { for (let b in newBreaks) { if (b in pageBreaks) { pageBreaks[b] = pageBreaks[b].concat(newBreaks[b]); } else { pageBreaks[b] = newBreaks[b]; } } return pageBreaks; } addBreakAttributes(pageElement, page) { let before = pageElement.querySelector("[data-break-before]"); let after = pageElement.querySelector("[data-break-after]"); let previousBreakAfter = pageElement.querySelector("[data-previous-break-after]"); if (before) { if (before.dataset.splitFrom) { page.splitFrom = before.dataset.splitFrom; pageElement.setAttribute("data-split-from", before.dataset.splitFrom); } else if (before.dataset.breakBefore && before.dataset.breakBefore !== "avoid") { page.breakBefore = before.dataset.breakBefore; pageElement.setAttribute("data-break-before", before.dataset.breakBefore); } } if (after && after.dataset) { if (after.dataset.splitTo) { page.splitTo = after.dataset.splitTo; pageElement.setAttribute("data-split-to", after.dataset.splitTo); } else if (after.dataset.breakAfter && after.dataset.breakAfter !== "avoid") { page.breakAfter = after.dataset.breakAfter; pageElement.setAttribute("data-break-after", after.dataset.breakAfter); } } if (previousBreakAfter && previousBreakAfter.dataset) { if (previousBreakAfter.dataset.previousBreakAfter && previousBreakAfter.dataset.previousBreakAfter !== "avoid") { page.previousBreakAfter = previousBreakAfter.dataset.previousBreakAfter; } } } afterPageLayout(pageElement, page) { this.addBreakAttributes(pageElement, page); } } class PrintMedia extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } onAtMedia(node, item, list) { let media = this.getMediaName(node); let rules; if (media === "print") { rules = node.block.children; // Remove rules from the @media block node.block.children = new lib.List(); // Append rules to the end of main rules list list.appendList(rules); } } getMediaName(node) { let media = ""; if (typeof node.prelude === "undefined" || node.prelude.type !== "AtrulePrelude" ) { return; } lib.walk(node.prelude, { visit: "Identifier", enter: (identNode, iItem, iList) => { media = identNode.name; } }); return media; } } class Splits extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } afterPageLayout(pageElement, page, breakToken, chunker) { let splits = Array.from(pageElement.querySelectorAll("[data-split-from]")); let pages = pageElement.parentNode; let index = Array.prototype.indexOf.call(pages.children, pageElement); let prevPage; if (index === 0) { return; } prevPage = pages.children[index - 1]; let from; // Capture the last from element splits.forEach((split) => { let ref = split.dataset.ref; from = prevPage.querySelector("[data-ref='"+ ref +"']:not([data-split-to])"); if (from) { from.dataset.splitTo = ref; if (!from.dataset.splitFrom) { from.dataset.splitOriginal = true; } } }); // Fix alignment on the deepest split element if (from) { this.handleAlignment(from); } } handleAlignment(node) { let styles = window.getComputedStyle(node); let align = styles["text-align"]; let alignLast = styles["text-align-last"]; node.dataset.lastSplitElement = "true"; if (align === "justify" && alignLast === "auto") { node.dataset.alignLastSplitElement = "justify"; } else { node.dataset.alignLastSplitElement = alignLast; } } } class Counters extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.counters = {}; this.resetCountersMap = new Map(); } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "counter-increment") { let inc = this.handleIncrement(declaration, rule); if (inc) { dList.remove(dItem); } } else if (property === "counter-reset") { let reset = this.handleReset(declaration, rule); if (reset) { dList.remove(dItem); } } } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "counter") ; } afterParsed(parsed) { this.processCounters(parsed, this.counters); this.scopeCounters(this.counters); } addCounter(name) { if (name in this.counters) { return this.counters[name]; } this.counters[name] = { name: name, increments: {}, resets: {} }; return this.counters[name]; } handleIncrement(declaration, rule) { const identifier = declaration.value.children.first(); const number = declaration.value.children.getSize() > 1 ? declaration.value.children.last().value : 1; const name = identifier && identifier.name; if (name === "page" || name.indexOf("target-counter-") === 0) { return; } let selector = lib.generate(rule.ruleNode.prelude); let counter; if (!(name in this.counters)) { counter = this.addCounter(name); } else { counter = this.counters[name]; } return counter.increments[selector] = { selector: selector, number }; } handleReset(declaration, rule) { let identifier = declaration.value.children.first(); let number = declaration.value.children.getSize() > 1 && declaration.value.children.last().value; let name = identifier && identifier.name; let selector = lib.generate(rule.ruleNode.prelude); let counter; if (!(name in this.counters)) { counter = this.addCounter(name); } else { counter = this.counters[name]; } return counter.resets[selector] = { selector: selector, number: number || 0 }; } processCounters(parsed, counters) { let counter; for (let c in counters) { counter = this.counters[c]; this.processCounterIncrements(parsed, counter); this.processCounterResets(parsed, counter); if (c !== "page") { this.addCounterValues(parsed, counter); } } } scopeCounters(counters) { let countersArray = []; for (let c in counters) { if(c !== "page") { countersArray.push(`${counters[c].name} 0`); } } // Add to pages to allow cross page scope this.insertRule(`.pagedjs_pages { counter-reset: ${countersArray.join(" ")} page 0 pages var(--pagedjs-page-count)}`); } insertRule(rule) { this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } processCounterIncrements(parsed, counter) { let increment; for (let inc in counter.increments) { increment = counter.increments[inc]; // Find elements for increments let incrementElements = parsed.querySelectorAll(increment.selector); // Add counter data for (let i = 0; i < incrementElements.length; i++) { incrementElements[i].setAttribute("data-counter-"+ counter.name +"-increment", increment.number); incrementElements[i].setAttribute("data-counter-increment", counter.name); } } } processCounterResets(parsed, counter) { let reset; for (let r in counter.resets) { reset = counter.resets[r]; // Find elements for resets let resetElements = parsed.querySelectorAll(reset.selector); // Add counter data for (var i = 0; i < resetElements.length; i++) { resetElements[i].setAttribute("data-counter-"+ counter.name +"-reset", reset.number); resetElements[i].setAttribute("data-counter-reset", counter.name); } } } addCounterValues(parsed, counter) { const counterName = counter.name; const elements = parsed.querySelectorAll("[data-counter-"+ counterName +"-reset], [data-counter-"+ counterName +"-increment]"); let count = 0; let element; let increment, reset; let resetValue, incrementValue, resetDelta; let incrementArray; for (let i = 0; i < elements.length; i++) { element = elements[i]; resetDelta = 0; incrementArray = []; if (element.hasAttribute("data-counter-"+ counterName +"-reset")) { reset = element.getAttribute("data-counter-"+ counterName +"-reset"); resetValue = parseInt(reset); // Use negative increment value inplace of reset resetDelta = resetValue - count; incrementArray.push(`${counterName} ${resetDelta}`); count = resetValue; } if (element.hasAttribute("data-counter-"+ counterName +"-increment")) { increment = element.getAttribute("data-counter-"+ counterName +"-increment"); incrementValue = parseInt(increment); count += incrementValue; element.setAttribute("data-counter-"+counterName+"-value", count); incrementArray.push(`${counterName} ${incrementValue}`); } if (incrementArray.length > 0) { this.incrementCounterForElement(element, incrementArray); } } } incrementCounterForElement(element, incrementArray) { if (!element || !incrementArray || incrementArray.length === 0) return; const ref = element.dataset.ref; const prevIncrements = Array.from(this.styleSheet.cssRules).filter((rule) => { return rule.selectorText === `[data-ref="${element.dataset.ref}"]:not([data-split-from])` && rule.style[0] === "counter-increment"; }); const increments = []; for (let styleRule of prevIncrements) { let values = styleRule.style.counterIncrement.split(" "); for (let i = 0; i < values.length; i+=2) { increments.push(values[i] + " " + values[i+1]); } } Array.prototype.push.apply(increments, incrementArray); this.insertRule(`[data-ref="${ref}"]:not([data-split-from]) { counter-increment: ${increments.join(" ")} }`); } afterPageLayout(pageElement, page) { let pgreset = pageElement.querySelectorAll("[data-counter-page-reset]"); pgreset.forEach((reset) => { const ref = reset.dataset && reset.dataset.ref; if (ref && this.resetCountersMap.has(ref)) ; else { if (ref) { this.resetCountersMap.set(ref, ""); } let value = reset.dataset.counterPageReset; this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] { counter-increment: none; counter-reset: page ${value}; }`, this.styleSheet.cssRules.length); } }); } } class Lists extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } afterParsed(content) { const orderedLists = content.querySelectorAll("ol"); for (var list of orderedLists) { this.addDataNumbers(list); } } afterPageLayout(pageElement, page, breakToken, chunker) { var orderedLists = pageElement.getElementsByTagName("ol"); for (var list of orderedLists) { if (list.hasChildNodes()) { list.start = list.firstElementChild.dataset.itemNum; } else { list.parentNode.removeChild(list); } } } addDataNumbers(list) { let start = 1; if (list.hasAttribute("start")) { start = parseInt(list.getAttribute("start"), 10); if (isNaN(start)) { start = 1; } } let items = list.children; for (var i = 0; i < items.length; i++) { items[i].setAttribute("data-item-num", i + start); } } } class PositionFixed extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.fixedElementsSelector = []; this.fixedElements = []; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "position" && declaration.value.children.first().name === "fixed") { let selector = lib.generate(rule.ruleNode.prelude); this.fixedElementsSelector.push(selector); dList.remove(dItem); } } afterParsed(fragment) { this.fixedElementsSelector.forEach(fixedEl => { fragment.querySelectorAll(`${fixedEl}`).forEach(el => { el.style.setProperty("position", "absolute"); this.fixedElements.push(el); el.remove(); }); }); } afterPageLayout(pageElement, page, breakToken) { this.fixedElements.forEach(el => { const clone = el.cloneNode(true); pageElement.querySelector(".pagedjs_pagebox").insertAdjacentElement("afterbegin", clone); }); } } class PageCounterIncrement extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.pageCounter = { name: "page", increments: {}, resets: {} }; } onDeclaration(declaration, dItem, dList, rule) { const property = declaration.property; if (property === "counter-increment") { let inc = this.handleIncrement(declaration, rule); if (inc) { dList.remove(dItem); } } } afterParsed(_) { for (const inc in this.pageCounter.increments) { const increment = this.pageCounter.increments[inc]; this.insertRule(`${increment.selector} { --pagedjs-page-counter-increment: ${increment.number} }`); } } handleIncrement(declaration, rule) { const identifier = declaration.value.children.first(); const number = declaration.value.children.getSize() > 1 ? declaration.value.children.last().value : 1; const name = identifier && identifier.name; if (name.indexOf("target-counter-") === 0) { return; } // A counter named page is automatically created and incremented by 1 on every page of the document, // unless the counter-increment property in the page context explicitly specifies a different increment for the page counter. // https://www.w3.org/TR/css-page-3/#page-based-counters if (name !== "page") { return; } // the counter-increment property is not defined on the page context (i.e. @page rule), ignoring... if (rule.ruleNode.name === "page" && rule.ruleNode.type === "Atrule") { return; } const selector = lib.generate(rule.ruleNode.prelude); return this.pageCounter.increments[selector] = { selector: selector, number }; } insertRule(rule) { this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } class NthOfType extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.selectors = {}; } onRule(ruleNode, ruleItem, rulelist) { let selector = lib.generate(ruleNode.prelude); if (selector.match(/:(first|last|nth)-of-type/)) { let declarations = lib.generate(ruleNode.block); declarations = declarations.replace(/[{}]/g,""); let uuid = "nth-of-type-" + UUID(); selector.split(",").forEach((s) => { if (!this.selectors[s]) { this.selectors[s] = [uuid, declarations]; } else { this.selectors[s][1] = `${this.selectors[s][1]};${declarations}` ; } }); rulelist.remove(ruleItem); } } afterParsed(parsed) { this.processSelectors(parsed, this.selectors); } processSelectors(parsed, selectors) { // add the new attributes to matching elements for (let s in selectors) { let elements = parsed.querySelectorAll(s); for (var i = 0; i < elements.length; i++) { let dataNthOfType = elements[i].getAttribute("data-nth-of-type"); if (dataNthOfType && dataNthOfType != "") { dataNthOfType = `${dataNthOfType},${selectors[s][0]}`; elements[i].setAttribute("data-nth-of-type", dataNthOfType); } else { elements[i].setAttribute("data-nth-of-type", selectors[s][0]); } } let rule = `*[data-nth-of-type*='${selectors[s][0]}'] { ${selectors[s][1]}; }`; this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } } class Following extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.selectors = {}; } onRule(ruleNode, ruleItem, rulelist) { let selector = lib.generate(ruleNode.prelude); if (selector.match(/\+/)) { let declarations = lib.generate(ruleNode.block); declarations = declarations.replace(/[{}]/g,""); let uuid = "following-" + UUID(); selector.split(",").forEach((s) => { if (!this.selectors[s]) { this.selectors[s] = [uuid, declarations]; } else { this.selectors[s][1] = `${this.selectors[s][1]};${declarations}` ; } }); rulelist.remove(ruleItem); } } afterParsed(parsed) { this.processSelectors(parsed, this.selectors); } processSelectors(parsed, selectors) { // add the new attributes to matching elements for (let s in selectors) { let elements = parsed.querySelectorAll(s); for (var i = 0; i < elements.length; i++) { let dataFollowing = elements[i].getAttribute("data-following"); if (dataFollowing && dataFollowing != "") { dataFollowing = `${dataFollowing},${selectors[s][0]}`; elements[i].setAttribute("data-following", dataFollowing); } else { elements[i].setAttribute("data-following", selectors[s][0]); } } let rule = `*[data-following*='${selectors[s][0]}'] { ${selectors[s][1]}; }`; this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } } var pagedMediaHandlers = [ AtPage, Breaks, PrintMedia, Splits, Counters, Lists, PositionFixed, PageCounterIncrement, NthOfType, Following ]; class RunningHeaders extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.runningSelectors = {}; this.elements = {}; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "position") { let selector = lib.generate(rule.ruleNode.prelude); let identifier = declaration.value.children.first().name; if (identifier === "running") { let value; lib.walk(declaration, { visit: "Function", enter: (node, item, list) => { value = node.children.first().name; } }); this.runningSelectors[value] = { identifier: identifier, value: value, selector: selector }; } } if (declaration.property === "content") { lib.walk(declaration, { visit: "Function", enter: (funcNode, fItem, fList) => { if (funcNode.name.indexOf("element") > -1) { let selector = lib.generate(rule.ruleNode.prelude); let func = funcNode.name; let value = funcNode.children.first().name; let args = [value]; // we only handle first for now let style = "first"; selector.split(",").forEach((s) => { // remove before / after s = s.replace(/::after|::before/, ""); this.elements[s] = { func: func, args: args, value: value, style: style , selector: s, fullSelector: selector }; }); } } }); } } afterParsed(fragment) { for (let name of Object.keys(this.runningSelectors)) { let set = this.runningSelectors[name]; let selected = Array.from(fragment.querySelectorAll(set.selector)); if (set.identifier === "running") { for (let header of selected) { header.style.display = "none"; } } } } afterPageLayout(fragment) { for (let name of Object.keys(this.runningSelectors)) { let set = this.runningSelectors[name]; let selected = fragment.querySelector(set.selector); if (selected) { // let cssVar; if (set.identifier === "running") { // cssVar = selected.textContent.replace(/\\([\s\S])|(["|'])/g,"\\$1$2"); // this.styleSheet.insertRule(`:root { --string-${name}: "${cssVar}"; }`, this.styleSheet.cssRules.length); // fragment.style.setProperty(`--string-${name}`, `"${cssVar}"`); set.first = selected; } else { console.warn(set.value + "needs css replacement"); } } } // move elements if (!this.orderedSelectors) { this.orderedSelectors = this.orderSelectors(this.elements); } for (let selector of this.orderedSelectors) { if (selector) { let el = this.elements[selector]; let selected = fragment.querySelector(selector); if (selected) { let running = this.runningSelectors[el.args[0]]; if (running && running.first) { selected.innerHTML = ""; // Clear node // selected.classList.add("pagedjs_clear-after"); // Clear ::after let clone = running.first.cloneNode(true); clone.style.display = null; selected.appendChild(clone); } } } } } /** * Assign a weight to @page selector classes * 1) page * 2) left & right * 3) blank * 4) first & nth * 5) named page * 6) named left & right * 7) named first & nth * @param {string} [s] selector string * @return {int} weight */ pageWeight(s) { let weight = 1; let selector = s.split(" "); let parts = selector.length && selector[0].split("."); parts.shift(); // remove empty first part switch (parts.length) { case 4: if (parts[3] === "pagedjs_first_page") { weight = 7; } else if (parts[3] === "pagedjs_left_page" || parts[3] === "pagedjs_right_page") { weight = 6; } break; case 3: if (parts[1] === "pagedjs_named_page") { if (parts[2].indexOf(":nth-of-type") > -1) { weight = 7; } else { weight = 5; } } break; case 2: if (parts[1] === "pagedjs_first_page") { weight = 4; } else if (parts[1] === "pagedjs_blank_page") { weight = 3; } else if (parts[1] === "pagedjs_left_page" || parts[1] === "pagedjs_right_page") { weight = 2; } break; default: if (parts[0].indexOf(":nth-of-type") > -1) { weight = 4; } else { weight = 1; } } return weight; } /** * Orders the selectors based on weight * * Does not try to deduplicate base on specifity of the selector * Previous matched selector will just be overwritten * @param {obj} [obj] selectors object * @return {Array} orderedSelectors */ orderSelectors(obj) { let selectors = Object.keys(obj); let weighted = { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [] }; let orderedSelectors = []; for (let s of selectors) { let w = this.pageWeight(s); weighted[w].unshift(s); } for (var i = 1; i <= 7; i++) { orderedSelectors = orderedSelectors.concat(weighted[i]); } return orderedSelectors; } beforeTreeParse(text, sheet) { // element(x) is parsed as image element selector, so update element to element-ident sheet.text = text.replace(/element[\s]*\(([^|^#)]*)\)/g, "element-ident($1)"); } } function cleanPseudoContent(el, trim = "\"' ") { if(el == null) return; return el .replace(new RegExp(`^[${trim}]+`), "") .replace(new RegExp(`[${trim}]+$`), "") .replace(/["']/g, match => { return "\\" + match; }) .replace(/[\n]/g, match => { return "\\00000A"; }); } function cleanSelector(el) { if(el == null) return; return el .replace(new RegExp("::footnote-call", "g"), "") .replace(new RegExp("::footnote-marker", "g"), ""); } class StringSets extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.stringSetSelectors = {}; this.type; // pageLastString = last string variable defined on the page this.pageLastString; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "string-set") { let selector = lib.generate(rule.ruleNode.prelude); let identifier = declaration.value.children.first().name; let value; lib.walk(declaration, { visit: "Function", enter: (node, item, list) => { value = lib.generate(node); } }); this.stringSetSelectors[identifier] = { identifier, value, selector }; } } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "string") { let identifier = funcNode.children && funcNode.children.first().name; this.type = funcNode.children.last().name; funcNode.name = "var"; funcNode.children = new lib.List(); if(this.type === "first" || this.type === "last" || this.type === "start" || this.type === "first-except"){ funcNode.children.append( funcNode.children.createItem({ type: "Identifier", loc: null, name: "--pagedjs-string-" + this.type + "-" + identifier }) ); }else { funcNode.children.append( funcNode.children.createItem({ type: "Identifier", loc: null, name: "--pagedjs-string-first-" + identifier }) ); } } } afterPageLayout(fragment) { if ( this.pageLastString === undefined ) { this.pageLastString = {}; } for (let name of Object.keys(this.stringSetSelectors)) { let set = this.stringSetSelectors[name]; let selected = fragment.querySelectorAll(set.selector); // Get the last found string for the current identifier let stringPrevPage = ( name in this.pageLastString ) ? this.pageLastString[name] : ""; let varFirst, varLast, varStart, varFirstExcept; if(selected.length == 0){ // if there is no sel. on the page varFirst = stringPrevPage; varLast = stringPrevPage; varStart = stringPrevPage; varFirstExcept = stringPrevPage; }else { selected.forEach((sel) => { // push each content into the array to define in the variable the first and the last element of the page. this.pageLastString[name] = selected[selected.length - 1].textContent; }); /* FIRST */ varFirst = selected[0].textContent; /* LAST */ varLast = selected[selected.length - 1].textContent; /* START */ // Hack to find if the sel. is the first elem of the page / find a better way let selTop = selected[0].getBoundingClientRect().top; let pageContent = selected[0].closest(".pagedjs_page_content"); let pageContentTop = pageContent.getBoundingClientRect().top; if(selTop == pageContentTop){ varStart = varFirst; }else { varStart = stringPrevPage; } /* FIRST EXCEPT */ varFirstExcept = ""; } fragment.style.setProperty(`--pagedjs-string-first-${name}`, `"${cleanPseudoContent(varFirst)}`); fragment.style.setProperty(`--pagedjs-string-last-${name}`, `"${cleanPseudoContent(varLast)}`); fragment.style.setProperty(`--pagedjs-string-start-${name}`, `"${cleanPseudoContent(varStart)}`); fragment.style.setProperty(`--pagedjs-string-first-except-${name}`, `"${cleanPseudoContent(varFirstExcept)}`); } } } class TargetCounters extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.counterTargets = {}; } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "target-counter") { let selector = lib.generate(rule.ruleNode.prelude); let first = funcNode.children.first(); let func = first.name; let value = lib.generate(funcNode); let args = []; first.children.forEach((child) => { if (child.type === "Identifier") { args.push(child.name); } }); let counter; let style; let styleIdentifier; funcNode.children.forEach((child) => { if (child.type === "Identifier") { if (!counter) { counter = child.name; } else if (!style) { styleIdentifier = lib.clone(child); style = child.name; } } }); let variable = "target-counter-" + UUID(); selector.split(",").forEach((s) => { this.counterTargets[s] = { func: func, args: args, value: value, counter: counter, style: style, selector: s, fullSelector: selector, variable: variable }; }); // Replace with counter funcNode.name = "counter"; funcNode.children = new lib.List(); funcNode.children.appendData({ type: "Identifier", loc: 0, name: variable }); if (styleIdentifier) { funcNode.children.appendData({type: "Operator", loc: null, value: ","}); funcNode.children.appendData(styleIdentifier); } } } afterPageLayout(fragment, page, breakToken, chunker) { Object.keys(this.counterTargets).forEach((name) => { let target = this.counterTargets[name]; let split = target.selector.split("::"); let query = split[0]; let queried = chunker.pagesArea.querySelectorAll(query + ":not([data-" + target.variable + "])"); queried.forEach((selected, index) => { // TODO: handle func other than attr if (target.func !== "attr") { return; } let val = attr(selected, target.args); let element = chunker.pagesArea.querySelector(querySelectorEscape(val)); if (element) { let selector = UUID(); selected.setAttribute("data-" + target.variable, selector); // TODO: handle other counter types (by query) let pseudo = ""; if (split.length > 1) { pseudo += "::" + split[1]; } if (target.counter === "page") { let pages = chunker.pagesArea.querySelectorAll(".pagedjs_page"); let pg = 0; for (let i = 0; i < pages.length; i++) { let styles = window.getComputedStyle(pages[i]); let reset = styles["counter-reset"].replace("page", "").trim(); let increment = styles["counter-increment"].replace("page", "").trim(); if (reset !== "none") { pg = parseInt(reset); } if (increment !== "none") { pg += parseInt(increment); } if (pages[i].contains(element)) { break; } } this.styleSheet.insertRule(`[data-${target.variable}="${selector}"]${pseudo} { counter-reset: ${target.variable} ${pg}; }`, this.styleSheet.cssRules.length); } else { let value = element.getAttribute(`data-counter-${target.counter}-value`); if (value) { this.styleSheet.insertRule(`[data-${target.variable}="${selector}"]${pseudo} { counter-reset: ${target.variable} ${target.variable} ${parseInt(value)}; }`, this.styleSheet.cssRules.length); } } } }); }); } } // import { nodeAfter } from "../../utils/dom"; class TargetText extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.textTargets = {}; this.beforeContent = ""; this.afterContent = ""; this.selector = {}; } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "target-text") { this.selector = lib.generate(rule.ruleNode.prelude); let first = funcNode.children.first(); let last = funcNode.children.last(); let func = first.name; let value = lib.generate(funcNode); let args = []; first.children.forEach(child => { if (child.type === "Identifier") { args.push(child.name); } }); let style; if (last !== first) { style = last.name; } let variable = "--pagedjs-" + UUID(); this.selector.split(",").forEach(s => { this.textTargets[s] = { func: func, args: args, value: value, style: style || "content", selector: s, fullSelector: this.selector, variable: variable }; }); // Replace with variable funcNode.name = "var"; funcNode.children = new lib.List(); funcNode.children.appendData({ type: "Identifier", loc: 0, name: variable }); } } // parse this on the ONCONTENT : get all before and after and replace the value with a variable onPseudoSelector(pseudoNode, pItem, pList, selector, rule) { // console.log(pseudoNode); // console.log(rule); rule.ruleNode.block.children.forEach(properties => { if (pseudoNode.name === "before" && properties.property === "content") { // let beforeVariable = "--pagedjs-" + UUID(); let contenu = properties.value.children; contenu.forEach(prop => { if (prop.type === "String") { this.beforeContent = prop.value; } }); } else if (pseudoNode.name === "after" && properties.property === "content") { properties.value.children.forEach(prop => { if (prop.type === "String") { this.afterContent = prop.value; } }); } }); } afterParsed(fragment) { Object.keys(this.textTargets).forEach(name => { let target = this.textTargets[name]; let split = target.selector.split("::"); let query = split[0]; let queried = fragment.querySelectorAll(query); let textContent; queried.forEach((selected, index) => { let val = attr(selected, target.args); let element = fragment.querySelector(querySelectorEscape(val)); if (element) { // content & first-letter & before & after refactorized if (target.style) { this.selector = UUID(); selected.setAttribute("data-target-text", this.selector); let psuedo = ""; if (split.length > 1) { psuedo += "::" + split[1]; } if (target.style === "before" || target.style === "after") { const pseudoType = `${target.style}Content`; textContent = cleanPseudoContent(this[pseudoType]); } else { textContent = cleanPseudoContent(element.textContent, " "); } textContent = target.style === "first-letter" ? textContent.charAt(0) : textContent; this.styleSheet.insertRule(`[data-target-text="${this.selector}"]${psuedo} { ${target.variable}: "${textContent}" }`); } else { console.warn("missed target", val); } } }); }); } } var generatedContentHandlers = [ RunningHeaders, StringSets, TargetCounters, TargetText ]; class WhiteSpaceFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { filterTree(content, (node) => { return this.filterEmpty(node); }, NodeFilter.SHOW_TEXT); } filterEmpty(node) { if (node.textContent.length > 1 && isIgnorable(node)) { // Do not touch the content if text is pre-formatted let parent = node.parentNode; let pre = isElement(parent) && parent.closest("pre"); if (pre) { return NodeFilter.FILTER_REJECT; } const previousSibling = previousSignificantNode(node); const nextSibling = nextSignificantNode(node); if (nextSibling === null && previousSibling === null) { // we should not remove a Node that does not have any siblings. node.textContent = " "; return NodeFilter.FILTER_REJECT; } if (nextSibling === null) { // we can safely remove this node return NodeFilter.FILTER_ACCEPT; } if (previousSibling === null) { // we can safely remove this node return NodeFilter.FILTER_ACCEPT; } // replace the content with a single space node.textContent = " "; // TODO: we also need to preserve sequences of white spaces when the parent has "white-space" rule: // pre // Sequences of white space are preserved. Lines are only broken at newline characters in the source and at <br> elements. // // pre-wrap // Sequences of white space are preserved. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes. // // pre-line // Sequences of white space are collapsed. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes. // // break-spaces // The behavior is identical to that of pre-wrap, except that: // - Any sequence of preserved white space always takes up space, including at the end of the line. // - A line breaking opportunity exists after every preserved white space character, including between white space characters. // - Such preserved spaces take up space and do not hang, and thus affect the box’s intrinsic sizes (min-content size and max-content size). // // See: https://developer.mozilla.org/en-US/docs/Web/CSS/white-space#Values return NodeFilter.FILTER_REJECT; } else { return NodeFilter.FILTER_REJECT; } } } class CommentsFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { filterTree(content, null, NodeFilter.SHOW_COMMENT); } } class ScriptsFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { content.querySelectorAll("script").forEach( script => { script.remove(); }); } } var clearCut = createCommonjsModule(function (module, exports) { /** * Originally ported from https://github.com/keeganstreet/specificity/blob/866bf7ab4e7f62a7179c15b13a95af4e1c7b1afa/specificity.js * * Calculates the specificity of CSS selectors * http://www.w3.org/TR/css3-selectors/#specificity * * Returns a selector integer value */ // The following regular expressions assume that selectors matching the preceding regular expressions have been removed var attributeRegex = /(\[[^\]]+\])/g; var idRegex = /(#[^\s\+>~\.\[:]+)/g; var classRegex = /(\.[^\s\+>~\.\[:]+)/g; var pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/g; var pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g; var elementRegex = /([^\s\+>~\.\[:]+)/g; var notRegex = /:not\(([^\)]*)\)/g; var ruleRegex = /\{[^]*/gm; var separatorRegex = /[\*\s\+>~]/g; var straysRegex = /[#\.]/g; // Find matches for a regular expression in a string and push their details to parts // Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements var findMatch = function(regex, type, types, selector) { var matches = selector.match(regex); if (matches) { for (var i = 0; i < matches.length; i++) { types[type]++; // Replace this simple selector with whitespace so it won't be counted in further simple selectors selector = selector.replace(matches[i], ' '); } } return selector; }; // Calculate the specificity for a selector by dividing it into simple selectors and counting them var calculate = function(selector) { var commaIndex = selector.indexOf(','); if (commaIndex !== -1) { selector = selector.substring(0, commaIndex); } var types = { a: 0, b: 0, c: 0 }; // Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument selector = selector.replace(notRegex, ' $1 '); // Remove anything after a left brace in case a user has pasted in a rule, not just a selector selector = selector.replace(ruleRegex, ' '); // Add attribute selectors to parts collection (type b) selector = findMatch(attributeRegex, 'b', types, selector); // Add ID selectors to parts collection (type a) selector = findMatch(idRegex, 'a', types, selector); // Add class selectors to parts collection (type b) selector = findMatch(classRegex, 'b', types, selector); // Add pseudo-element selectors to parts collection (type c) selector = findMatch(pseudoElementRegex, 'c', types, selector); // Add pseudo-class selectors to parts collection (type b) selector = findMatch(pseudoClassRegex, 'b', types, selector); // Remove universal selector and separator characters selector = selector.replace(separatorRegex, ' '); // Remove any stray dots or hashes which aren't attached to words // These may be present if the user is live-editing this selector selector = selector.replace(straysRegex, ' '); // The only things left should be element selectors (type c) findMatch(elementRegex, 'c', types, selector); return (types.a * 100) + (types.b * 10) + (types.c * 1); }; var specificityCache = {}; exports.calculateSpecificity = function(selector) { var specificity = specificityCache[selector]; if (specificity === undefined) { specificity = calculate(selector); specificityCache[selector] = specificity; } return specificity; }; var validSelectorCache = {}; var testSelectorElement = null; exports.isSelectorValid = function(selector) { var valid = validSelectorCache[selector]; if (valid === undefined) { if (testSelectorElement == null) { testSelectorElement = document.createElement('div'); } try { testSelectorElement.querySelector(selector); valid = true; } catch (error) { valid = false; } validSelectorCache[selector] = valid; } return valid; }; exports.validateSelector = function(selector) { if (!exports.isSelectorValid(selector)) { var error = new SyntaxError(selector + ' is not a valid selector'); error.code = 'EBADSELECTOR'; throw error; } }; }); var clearCut_1 = clearCut.calculateSpecificity; var clearCut_2 = clearCut.isSelectorValid; var clearCut_3 = clearCut.validateSelector; class UndisplayedFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.displayRules = {}; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "display") { let selector = lib.generate(rule.ruleNode.prelude); let value = declaration.value.children.first().name; selector.split(",").forEach((s) => { this.displayRules[s] = { value: value, selector: s, specificity: clearCut_1(s), important: declaration.important }; }); } } filter(content) { let { matches, selectors } = this.sortDisplayedSelectors(content, this.displayRules); // Find matching elements that have display styles for (let i = 0; i < matches.length; i++) { let element = matches[i]; let selector = selectors[i]; let displayValue = selector[selector.length-1].value; if(this.removable(element) && displayValue === "none") { element.dataset.undisplayed = "undisplayed"; } } // Find elements that have inline styles let styledElements = content.querySelectorAll("[style]"); for (let i = 0; i < styledElements.length; i++) { let element = styledElements[i]; if (this.removable(element)) { element.dataset.undisplayed = "undisplayed"; } } } sorter(a, b) { if (a.important && !b.important) { return 1; } if (b.important && !a.important) { return -1; } return a.specificity - b.specificity; } sortDisplayedSelectors(content, displayRules=[]) { let matches = []; let selectors = []; for (let d in displayRules) { let displayItem = displayRules[d]; let selector = displayItem.selector; let query = []; try { try { query = content.querySelectorAll(selector); } catch (e) { query = content.querySelectorAll(cleanSelector(selector)); } } catch (e) { query = []; } let elements = Array.from(query); for (let e of elements) { if (matches.includes(e)) { let index = matches.indexOf(e); selectors[index].push(displayItem); selectors[index] = selectors[index].sort(this.sorter); } else { matches.push(e); selectors.push([displayItem]); } } } return { matches, selectors }; } removable(element) { if (element.style && element.style.display !== "" && element.style.display !== "none") { return false; } return true; } } var filters = [ WhiteSpaceFilter, CommentsFilter, ScriptsFilter, UndisplayedFilter ]; var isImplemented$3 = function () { var from = Array.from, arr, result; if (typeof from !== "function") return false; arr = ["raz", "dwa"]; result = from(arr); return Boolean(result && (result !== arr) && (result[1] === "dwa")); }; var validTypes = { object: true, symbol: true }; var isImplemented$4 = function () { var symbol; if (typeof Symbol !== 'function') return false; symbol = Symbol('test symbol'); try { String(symbol); } catch (e) { return false; } // Return 'true' also for polyfills if (!validTypes[typeof Symbol.iterator]) return false; if (!validTypes[typeof Symbol.toPrimitive]) return false; if (!validTypes[typeof Symbol.toStringTag]) return false; return true; }; var isSymbol = function (x) { if (!x) return false; if (typeof x === 'symbol') return true; if (!x.constructor) return false; if (x.constructor.name !== 'Symbol') return false; return (x[x.constructor.toStringTag] === 'Symbol'); }; var validateSymbol = function (value) { if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); return value; }; var create$6 = Object.create, defineProperties = Object.defineProperties , defineProperty = Object.defineProperty, objPrototype = Object.prototype , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create$6(null) , isNativeSafe; if (typeof Symbol === 'function') { NativeSymbol = Symbol; try { String(NativeSymbol()); isNativeSafe = true; } catch (ignore) {} } var generateName = (function () { var created = create$6(null); return function (desc) { var postfix = 0, name, ie11BugWorkaround; while (created[desc + (postfix || '')]) ++postfix; desc += (postfix || ''); created[desc] = true; name = '@@' + desc; defineProperty(objPrototype, name, d_1.gs(null, function (value) { // For IE11 issue see: // https://connect.microsoft.com/IE/feedbackdetail/view/1928508/ // ie11-broken-getters-on-dom-objects // https://github.com/medikoo/es6-symbol/issues/12 if (ie11BugWorkaround) return; ie11BugWorkaround = true; defineProperty(this, name, d_1(value)); ie11BugWorkaround = false; })); return name; }; }()); // Internal constructor (not one exposed) for creating Symbol instances. // This one is used to ensure that `someSymbol instanceof Symbol` always return false HiddenSymbol = function Symbol(description) { if (this instanceof HiddenSymbol) throw new TypeError('Symbol is not a constructor'); return SymbolPolyfill(description); }; // Exposed `Symbol` constructor // (returns instances of HiddenSymbol) var polyfill = SymbolPolyfill = function Symbol(description) { var symbol; if (this instanceof Symbol) throw new TypeError('Symbol is not a constructor'); if (isNativeSafe) return NativeSymbol(description); symbol = create$6(HiddenSymbol.prototype); description = (description === undefined ? '' : String(description)); return defineProperties(symbol, { __description__: d_1('', description), __name__: d_1('', generateName(description)) }); }; defineProperties(SymbolPolyfill, { for: d_1(function (key) { if (globalSymbols[key]) return globalSymbols[key]; return (globalSymbols[key] = SymbolPolyfill(String(key))); }), keyFor: d_1(function (s) { var key; validateSymbol(s); for (key in globalSymbols) if (globalSymbols[key] === s) return key; }), // To ensure proper interoperability with other native functions (e.g. Array.from) // fallback to eventual native implementation of given symbol hasInstance: d_1('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), isConcatSpreadable: d_1('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || SymbolPolyfill('isConcatSpreadable')), iterator: d_1('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), match: d_1('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), replace: d_1('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), search: d_1('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), species: d_1('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), split: d_1('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), toPrimitive: d_1('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), toStringTag: d_1('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), unscopables: d_1('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) }); // Internal tweaks for real symbol producer defineProperties(HiddenSymbol.prototype, { constructor: d_1(SymbolPolyfill), toString: d_1('', function () { return this.__name__; }) }); // Proper implementation of methods exposed on Symbol.prototype // They won't be accessible on produced symbol instances as they derive from HiddenSymbol.prototype defineProperties(SymbolPolyfill.prototype, { toString: d_1(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), valueOf: d_1(function () { return validateSymbol(this); }) }); defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d_1('', function () { var symbol = validateSymbol(this); if (typeof symbol === 'symbol') return symbol; return symbol.toString(); })); defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d_1('c', 'Symbol')); // Proper implementaton of toPrimitive and toStringTag for returned symbol instances defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, d_1('c', SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])); // Note: It's important to define `toPrimitive` as last one, as some implementations // implement `toPrimitive` natively without implementing `toStringTag` (or other specified symbols) // And that may invoke error in definition flow: // See: https://github.com/medikoo/es6-symbol/issues/13#issuecomment-164146149 defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toPrimitive, d_1('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])); var es6Symbol = isImplemented$4() ? Symbol : polyfill; var objToString = Object.prototype.toString , id = objToString.call( (function () { return arguments; })() ); var isArguments = function (value) { return objToString.call(value) === id; }; var objToString$1 = Object.prototype.toString, id$1 = objToString$1.call(noop); var isFunction = function (value) { return typeof value === "function" && objToString$1.call(value) === id$1; }; var isImplemented$5 = function () { var sign = Math.sign; if (typeof sign !== "function") return false; return (sign(10) === 1) && (sign(-20) === -1); }; var shim$3 = function (value) { value = Number(value); if (isNaN(value) || (value === 0)) return value; return value > 0 ? 1 : -1; }; var sign = isImplemented$5() ? Math.sign : shim$3; var abs = Math.abs, floor = Math.floor; var toInteger = function (value) { if (isNaN(value)) return 0; value = Number(value); if ((value === 0) || !isFinite(value)) return value; return sign(value) * floor(abs(value)); }; var max$1 = Math.max; var toPosInteger = function (value) { return max$1(0, toInteger(value)); }; var objToString$2 = Object.prototype.toString, id$2 = objToString$2.call(""); var isString = function (value) { return ( typeof value === "string" || (value && typeof value === "object" && (value instanceof String || objToString$2.call(value) === id$2)) || false ); }; var iteratorSymbol = es6Symbol.iterator , isArray = Array.isArray , call = Function.prototype.call , desc = { configurable: true, enumerable: true, writable: true, value: null } , defineProperty$1 = Object.defineProperty; // eslint-disable-next-line complexity var shim$4 = function (arrayLike /*, mapFn, thisArg*/) { var mapFn = arguments[1] , thisArg = arguments[2] , Context , i , j , arr , length , code , iterator , result , getIterator , value; arrayLike = Object(validValue(arrayLike)); if (isValue(mapFn)) validCallable(mapFn); if (!this || this === Array || !isFunction(this)) { // Result: Plain array if (!mapFn) { if (isArguments(arrayLike)) { // Source: Arguments length = arrayLike.length; if (length !== 1) return Array.apply(null, arrayLike); arr = new Array(1); arr[0] = arrayLike[0]; return arr; } if (isArray(arrayLike)) { // Source: Array arr = new Array(length = arrayLike.length); for (i = 0; i < length; ++i) arr[i] = arrayLike[i]; return arr; } } arr = []; } else { // Result: Non plain array Context = this; } if (!isArray(arrayLike)) { if ((getIterator = arrayLike[iteratorSymbol]) !== undefined) { // Source: Iterator iterator = validCallable(getIterator).call(arrayLike); if (Context) arr = new Context(); result = iterator.next(); i = 0; while (!result.done) { value = mapFn ? call.call(mapFn, thisArg, result.value, i) : result.value; if (Context) { desc.value = value; defineProperty$1(arr, i, desc); } else { arr[i] = value; } result = iterator.next(); ++i; } length = i; } else if (isString(arrayLike)) { // Source: String length = arrayLike.length; if (Context) arr = new Context(); for (i = 0, j = 0; i < length; ++i) { value = arrayLike[i]; if (i + 1 < length) { code = value.charCodeAt(0); // eslint-disable-next-line max-depth if (code >= 0xd800 && code <= 0xdbff) value += arrayLike[++i]; } value = mapFn ? call.call(mapFn, thisArg, value, j) : value; if (Context) { desc.value = value; defineProperty$1(arr, j, desc); } else { arr[j] = value; } ++j; } length = j; } } if (length === undefined) { // Source: array or array-like length = toPosInteger(arrayLike.length); if (Context) arr = new Context(length); for (i = 0; i < length; ++i) { value = mapFn ? call.call(mapFn, thisArg, arrayLike[i], i) : arrayLike[i]; if (Context) { desc.value = value; defineProperty$1(arr, i, desc); } else { arr[i] = value; } } } if (Context) { desc.value = null; arr.length = length; } return arr; }; var from_1 = isImplemented$3() ? Array.from : shim$4; var isImplemented$6 = function () { var numberIsNaN = Number.isNaN; if (typeof numberIsNaN !== "function") return false; return !numberIsNaN({}) && numberIsNaN(NaN) && !numberIsNaN(34); }; var shim$5 = function (value) { // eslint-disable-next-line no-self-compare return value !== value; }; var isNan = isImplemented$6() ? Number.isNaN : shim$5; var indexOf$2 = Array.prototype.indexOf , objHasOwnProperty = Object.prototype.hasOwnProperty , abs$1 = Math.abs , floor$1 = Math.floor; var eIndexOf = function (searchElement /*, fromIndex*/) { var i, length, fromIndex, val; if (!isNan(searchElement)) return indexOf$2.apply(this, arguments); length = toPosInteger(validValue(this).length); fromIndex = arguments[1]; if (isNaN(fromIndex)) fromIndex = 0; else if (fromIndex >= 0) fromIndex = floor$1(fromIndex); else fromIndex = toPosInteger(this.length) - floor$1(abs$1(fromIndex)); for (i = fromIndex; i < length; ++i) { if (objHasOwnProperty.call(this, i)) { val = this[i]; if (isNan(val)) return i; // Jslint: ignore } } return -1; }; var forEach$1 = Array.prototype.forEach , splice = Array.prototype.splice; // eslint-disable-next-line no-unused-vars var remove = function (itemToRemove /*, …item*/) { forEach$1.call( arguments, function (item) { var index = eIndexOf.call(this, item); if (index !== -1) splice.call(this, index, 1); }, this ); }; var map = { function: true, object: true }; var isObject$1 = function (value) { return (isValue(value) && map[typeof value]) || false; }; var validObject = function (value) { if (!isObject$1(value)) throw new TypeError(value + " is not an Object"); return value; }; var emit = eventEmitter.methods.emit , defineProperty$2 = Object.defineProperty , hasOwnProperty$6 = Object.prototype.hasOwnProperty , getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; var pipe = function (e1, e2/*, name*/) { var pipes, pipe, desc, name; (validObject(e1) && validObject(e2)); name = arguments[2]; if (name === undefined) name = 'emit'; pipe = { close: function () { remove.call(pipes, e2); } }; if (hasOwnProperty$6.call(e1, '__eePipes__')) { (pipes = e1.__eePipes__).push(e2); return pipe; } defineProperty$2(e1, '__eePipes__', d_1('c', pipes = [e2])); desc = getOwnPropertyDescriptor(e1, name); if (!desc) { desc = d_1('c', undefined); } else { delete desc.get; delete desc.set; } desc.value = function () { var i, emitter, data = from_1(pipes); emit.apply(this, arguments); for (i = 0; (emitter = data[i]); ++i) emit.apply(emitter, arguments); }; defineProperty$2(e1, name, desc); return pipe; }; let registeredHandlers = [...pagedMediaHandlers, ...generatedContentHandlers, ...filters]; class Handlers { constructor(chunker, polisher, caller) { registeredHandlers.forEach((Handler) => { let handler = new Handler(chunker, polisher, caller); pipe(handler, this); }); } } eventEmitter(Handlers.prototype); function registerHandlers() { for (var i = 0; i < arguments.length; i++) { registeredHandlers.push(arguments[i]); } } function initializeHandlers(chunker, polisher, caller) { let handlers = new Handlers(chunker, polisher, caller); return handlers; } class Previewer { constructor(options) { // this.preview = this.getParams("preview") !== "false"; this.settings = options || {}; // Process styles this.polisher = new Polisher(false); // Chunk contents this.chunker = new Chunker(undefined, undefined, this.settings); // Hooks this.hooks = {}; this.hooks.beforePreview = new Hook(this); this.hooks.afterPreview = new Hook(this); // default size this.size = { width: { value: 8.5, unit: "in" }, height: { value: 11, unit: "in" }, format: undefined, orientation: undefined }; this.chunker.on("page", (page) => { this.emit("page", page); }); this.chunker.on("rendering", () => { this.emit("rendering", this.chunker); }); } initializeHandlers() { let handlers = initializeHandlers(this.chunker, this.polisher, this); handlers.on("size", (size) => { this.size = size; this.emit("size", size); }); handlers.on("atpages", (pages) => { this.atpages = pages; this.emit("atpages", pages); }); return handlers; } registerHandlers() { return registerHandlers.apply(registerHandlers, arguments); } getParams(name) { let param; let url = new URL(window.location); let params = new URLSearchParams(url.search); for(var pair of params.entries()) { if(pair[0] === name) { param = pair[1]; } } return param; } wrapContent() { // Wrap body in template tag let body = document.querySelector("body"); // Check if a template exists let template; template = body.querySelector(":scope > template[data-ref='pagedjs-content']"); if (!template) { // Otherwise create one template = document.createElement("template"); template.dataset.ref = "pagedjs-content"; template.innerHTML = body.innerHTML; body.innerHTML = ""; body.appendChild(template); } return template.content; } removeStyles(doc=document) { // Get all stylesheets let stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']")); let hrefs = stylesheets.map((sheet) => { sheet.remove(); return sheet.href; }); // Get inline styles let inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles])")); inlineStyles.forEach((inlineStyle) => { let obj = {}; obj[window.location.href] = inlineStyle.textContent; hrefs.push(obj); inlineStyle.remove(); }); return hrefs; } async preview(content, stylesheets, renderTo) { await this.hooks.beforePreview.trigger(content, renderTo); if (!content) { content = this.wrapContent(); } if (!stylesheets) { stylesheets = this.removeStyles(); } this.polisher.setup(); this.handlers = this.initializeHandlers(); await this.polisher.add(...stylesheets); let startTime = performance.now(); // Render flow let flow = await this.chunker.flow(content, renderTo); let endTime = performance.now(); flow.performance = (endTime - startTime); flow.size = this.size; this.emit("rendered", flow); await this.hooks.afterPreview.trigger(flow.pages); return flow; } } eventEmitter(Previewer.prototype); var Paged = /*#__PURE__*/Object.freeze({ __proto__: null, Chunker: Chunker, Polisher: Polisher, Previewer: Previewer, Handler: Handler, registerHandlers: registerHandlers, initializeHandlers: initializeHandlers }); window.Paged = Paged; let ready = new Promise(function(resolve, reject){ if (document.readyState === "interactive" || document.readyState === "complete") { resolve(document.readyState); return; } document.onreadystatechange = function ($) { if (document.readyState === "interactive") { resolve(document.readyState); } }; }); let config = window.PagedConfig || { auto: true, before: undefined, after: undefined, content: undefined, stylesheets: undefined, renderTo: undefined, settings: undefined }; let previewer = new Previewer(config.settings); ready.then(async function () { let done; if (config.before) { await config.before(); } if(config.auto !== false) { done = await previewer.preview(config.content, config.stylesheets, config.renderTo); } if (config.after) { await config.after(done); } }); return previewer; })));