diff --git a/assets/paged.polyfill.js b/assets/paged.polyfill.js index 5008dbe..3100799 100644 --- a/assets/paged.polyfill.js +++ b/assets/paged.polyfill.js @@ -23185,4 +23185,10067 @@ function unpackSyntaxes(dict) { const result = {}; - \ No newline at end of file + for (const key in dict) { + result[key] = dict[key].syntax; + } + + return result; + } + + function patchAtrules(dict, patchDict) { + const result = {}; + + // copy all syntaxes for an original dict + for (const key in dict) { + const patchDescriptors = (patchDict[key] && patchDict[key].descriptors) || null; + + result[key] = { + prelude: key in patchDict && 'prelude' in patchDict[key] + ? patchDict[key].prelude + : dict[key].prelude || null, + descriptors: dict[key].descriptors + ? patchDictionary(dict[key].descriptors, patchDescriptors || {}) + : patchDescriptors && unpackSyntaxes(patchDescriptors) + }; + } + + // apply a patch + for (const key in patchDict) { + if (!hasOwnProperty.call(dict, key)) { + result[key] = { + prelude: patchDict[key].prelude || null, + descriptors: patchDict[key].descriptors && unpackSyntaxes(patchDict[key].descriptors) + }; + } + } + + return result; + } + + var data$1 = { + types: patchDictionary(mdnSyntaxes, patch.syntaxes), + atrules: patchAtrules(preprocessAtrules(mdnAtrules), patch.atrules), + properties: patchDictionary(mdnProperties, patch.properties) + }; + + var cmpChar$2 = tokenizer$3.cmpChar; + var isDigit$1 = tokenizer$3.isDigit; + var TYPE$y = tokenizer$3.TYPE; + + var WHITESPACE$8 = TYPE$y.WhiteSpace; + var COMMENT$6 = TYPE$y.Comment; + var IDENT$f = TYPE$y.Ident; + var NUMBER$6 = TYPE$y.Number; + var DIMENSION$5 = TYPE$y.Dimension; + var PLUSSIGN$5 = 0x002B; // U+002B PLUS SIGN (+) + var HYPHENMINUS$2 = 0x002D; // U+002D HYPHEN-MINUS (-) + var N = 0x006E; // U+006E LATIN SMALL LETTER N (n) + var DISALLOW_SIGN = true; + var ALLOW_SIGN = false; + + function checkInteger(offset, disallowSign) { + var pos = this.scanner.tokenStart + offset; + var code = this.scanner.source.charCodeAt(pos); + + if (code === PLUSSIGN$5 || code === HYPHENMINUS$2) { + if (disallowSign) { + this.error('Number sign is not allowed'); + } + pos++; + } + + for (; pos < this.scanner.tokenEnd; pos++) { + if (!isDigit$1(this.scanner.source.charCodeAt(pos))) { + this.error('Integer is expected', pos); + } + } + } + + function checkTokenIsInteger(disallowSign) { + return checkInteger.call(this, 0, disallowSign); + } + + function expectCharCode(offset, code) { + if (!cmpChar$2(this.scanner.source, this.scanner.tokenStart + offset, code)) { + var msg = ''; + + switch (code) { + case N: + msg = 'N is expected'; + break; + case HYPHENMINUS$2: + msg = 'HyphenMinus is expected'; + break; + } + + this.error(msg, this.scanner.tokenStart + offset); + } + } + + // ... + // ... ['+' | '-'] + function consumeB() { + var offset = 0; + var sign = 0; + var type = this.scanner.tokenType; + + while (type === WHITESPACE$8 || type === COMMENT$6) { + type = this.scanner.lookupType(++offset); + } + + if (type !== NUMBER$6) { + if (this.scanner.isDelim(PLUSSIGN$5, offset) || + this.scanner.isDelim(HYPHENMINUS$2, offset)) { + sign = this.scanner.isDelim(PLUSSIGN$5, offset) ? PLUSSIGN$5 : HYPHENMINUS$2; + + do { + type = this.scanner.lookupType(++offset); + } while (type === WHITESPACE$8 || type === COMMENT$6); + + if (type !== NUMBER$6) { + this.scanner.skip(offset); + checkTokenIsInteger.call(this, DISALLOW_SIGN); + } + } else { + return null; + } + } + + if (offset > 0) { + this.scanner.skip(offset); + } + + if (sign === 0) { + type = this.scanner.source.charCodeAt(this.scanner.tokenStart); + if (type !== PLUSSIGN$5 && type !== HYPHENMINUS$2) { + this.error('Number sign is expected'); + } + } + + checkTokenIsInteger.call(this, sign !== 0); + return sign === HYPHENMINUS$2 ? '-' + this.consume(NUMBER$6) : this.consume(NUMBER$6); + } + + // 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; + + // + if (this.scanner.tokenType === NUMBER$6) { + checkTokenIsInteger.call(this, ALLOW_SIGN); + b = this.consume(NUMBER$6); + } + + // -n + // -n + // -n ['+' | '-'] + // -n- + // + else if (this.scanner.tokenType === IDENT$f && cmpChar$2(this.scanner.source, this.scanner.tokenStart, HYPHENMINUS$2)) { + a = '-1'; + + expectCharCode.call(this, 1, N); + + switch (this.scanner.getTokenLength()) { + // -n + // -n + // -n ['+' | '-'] + case 2: + this.scanner.next(); + b = consumeB.call(this); + break; + + // -n- + case 3: + expectCharCode.call(this, 2, HYPHENMINUS$2); + + this.scanner.next(); + this.scanner.skipSC(); + + checkTokenIsInteger.call(this, DISALLOW_SIGN); + + b = '-' + this.consume(NUMBER$6); + break; + + // + default: + expectCharCode.call(this, 2, HYPHENMINUS$2); + checkInteger.call(this, 3, DISALLOW_SIGN); + this.scanner.next(); + + b = this.scanner.substrToCursor(start + 2); + } + } + + // '+'? n + // '+'? n + // '+'? n ['+' | '-'] + // '+'? n- + // '+'? + else if (this.scanner.tokenType === IDENT$f || (this.scanner.isDelim(PLUSSIGN$5) && this.scanner.lookupType(1) === IDENT$f)) { + var sign = 0; + a = '1'; + + // just ignore a plus + if (this.scanner.isDelim(PLUSSIGN$5)) { + sign = 1; + this.scanner.next(); + } + + expectCharCode.call(this, 0, N); + + switch (this.scanner.getTokenLength()) { + // '+'? n + // '+'? n + // '+'? n ['+' | '-'] + case 1: + this.scanner.next(); + b = consumeB.call(this); + break; + + // '+'? n- + case 2: + expectCharCode.call(this, 1, HYPHENMINUS$2); + + this.scanner.next(); + this.scanner.skipSC(); + + checkTokenIsInteger.call(this, DISALLOW_SIGN); + + b = '-' + this.consume(NUMBER$6); + break; + + // '+'? + default: + expectCharCode.call(this, 1, HYPHENMINUS$2); + checkInteger.call(this, 2, DISALLOW_SIGN); + this.scanner.next(); + + b = this.scanner.substrToCursor(start + sign + 1); + } + } + + // + // + // + // + // ['+' | '-'] + else if (this.scanner.tokenType === DIMENSION$5) { + var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); + var sign = code === PLUSSIGN$5 || code === HYPHENMINUS$2; + + for (var i = this.scanner.tokenStart + sign; i < this.scanner.tokenEnd; i++) { + if (!isDigit$1(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); + a = this.scanner.source.substring(start, i); + + // + // + // ['+' | '-'] + if (i + 1 === this.scanner.tokenEnd) { + this.scanner.next(); + b = consumeB.call(this); + } else { + expectCharCode.call(this, i - this.scanner.tokenStart + 1, HYPHENMINUS$2); + + // + if (i + 2 === this.scanner.tokenEnd) { + this.scanner.next(); + this.scanner.skipSC(); + checkTokenIsInteger.call(this, DISALLOW_SIGN); + b = '-' + this.consume(NUMBER$6); + } + // + else { + checkInteger.call(this, i - this.scanner.tokenStart + 2, DISALLOW_SIGN); + this.scanner.next(); + b = this.scanner.substrToCursor(i + 1); + } + } + } else { + this.error(); + } + + if (a !== null && a.charCodeAt(0) === PLUSSIGN$5) { + a = a.substr(1); + } + + if (b !== null && b.charCodeAt(0) === PLUSSIGN$5) { + 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 tokenizer = tokenizer$3; + var TYPE$x = tokenizer.TYPE; + + var WhiteSpace$1 = TYPE$x.WhiteSpace; + var Semicolon = TYPE$x.Semicolon; + var LeftCurlyBracket = TYPE$x.LeftCurlyBracket; + var Delim = TYPE$x.Delim; + var EXCLAMATIONMARK$2 = 0x0021; // U+0021 EXCLAMATION MARK (!) + + function getOffsetExcludeWS() { + if (this.scanner.tokenIndex > 0) { + if (this.scanner.lookupType(-1) === WhiteSpace$1) { + 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$2) { + 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$w = tokenizer$3.TYPE; + var rawMode$5 = Raw.mode; + + var ATKEYWORD$2 = TYPE$w.AtKeyword; + var SEMICOLON$4 = TYPE$w.Semicolon; + var LEFTCURLYBRACKET$3 = TYPE$w.LeftCurlyBracket; + var RIGHTCURLYBRACKET$1 = TYPE$w.RightCurlyBracket; + + function consumeRaw$5(startToken) { + return this.Raw(startToken, rawMode$5.leftCurlyBracketOrSemicolon, true); + } + + function isDeclarationBlockAtrule() { + for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) { + if (type === RIGHTCURLYBRACKET$1) { + return true; + } + + if (type === LEFTCURLYBRACKET$3 || + type === ATKEYWORD$2) { + 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$2); + + name = this.scanner.substrToCursor(start + 1); + nameLowerCase = name.toLowerCase(); + this.scanner.skipSC(); + + // parse prelude + if (this.scanner.eof === false && + this.scanner.tokenType !== LEFTCURLYBRACKET$3 && + this.scanner.tokenType !== SEMICOLON$4) { + if (this.parseAtrulePrelude) { + prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw$5); + + // turn empty AtrulePrelude into null + if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) { + prelude = null; + } + } else { + prelude = consumeRaw$5.call(this, this.scanner.tokenIndex); + } + + this.scanner.skipSC(); + } + + switch (this.scanner.tokenType) { + case SEMICOLON$4: + this.scanner.next(); + break; + + case LEFTCURLYBRACKET$3: + 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$v = tokenizer$3.TYPE; + + var SEMICOLON$3 = TYPE$v.Semicolon; + var LEFTCURLYBRACKET$2 = TYPE$v.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$3) { + 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$u = tokenizer$3.TYPE; + + var IDENT$e = TYPE$u.Ident; + var STRING$3 = TYPE$u.String; + var COLON$6 = TYPE$u.Colon; + var LEFTSQUAREBRACKET$3 = TYPE$u.LeftSquareBracket; + var RIGHTSQUAREBRACKET$1 = TYPE$u.RightSquareBracket; + var DOLLARSIGN$1 = 0x0024; // U+0024 DOLLAR SIGN ($) + var ASTERISK$5 = 0x002A; // U+002A ASTERISK (*) + var EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=) + var CIRCUMFLEXACCENT = 0x005E; // U+005E (^) + var VERTICALLINE$2 = 0x007C; // U+007C VERTICAL LINE (|) + var TILDE$2 = 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$5)) { + expectIdent = true; + checkColon = false; + this.scanner.next(); + } else if (!this.scanner.isDelim(VERTICALLINE$2)) { + this.eat(IDENT$e); + } + + if (this.scanner.isDelim(VERTICALLINE$2)) { + if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 1) !== EQUALSSIGN) { + this.scanner.next(); + this.eat(IDENT$e); + } 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$6) { + this.scanner.next(); + this.eat(IDENT$e); + } + + 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$2 && // ~= + code !== CIRCUMFLEXACCENT && // ^= + code !== DOLLARSIGN$1 && // $= + code !== ASTERISK$5 && // *= + code !== VERTICALLINE$2 // |= + ) { + 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); + } + + // '[' ']' + // '[' [ | ] ? ']' + 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$3); + 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$e) { + matcher = getOperator.call(this); + + this.scanner.skipSC(); + + value = this.scanner.tokenType === STRING$3 + ? this.String() + : this.Identifier(); + + this.scanner.skipSC(); + } + + // attribute flags + if (this.scanner.tokenType === IDENT$e) { + 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$t = tokenizer$3.TYPE; + var rawMode$4 = Raw.mode; + + var WHITESPACE$7 = TYPE$t.WhiteSpace; + var COMMENT$5 = TYPE$t.Comment; + var SEMICOLON$2 = TYPE$t.Semicolon; + var ATKEYWORD$1 = TYPE$t.AtKeyword; + var LEFTCURLYBRACKET$1 = TYPE$t.LeftCurlyBracket; + var RIGHTCURLYBRACKET = TYPE$t.RightCurlyBracket; + + function consumeRaw$4(startToken) { + return this.Raw(startToken, null, true); + } + function consumeRule() { + return this.parseWithFallback(this.Rule, consumeRaw$4); + } + function consumeRawDeclaration(startToken) { + return this.Raw(startToken, rawMode$4.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$1); + + scan: + while (!this.scanner.eof) { + switch (this.scanner.tokenType) { + case RIGHTCURLYBRACKET: + break scan; + + case WHITESPACE$7: + case COMMENT$5: + this.scanner.next(); + break; + + case ATKEYWORD$1: + children.push(this.parseWithFallback(this.Atrule, consumeRaw$4)); + break; + + default: + children.push(consumer.call(this)); + } + } + + if (!this.scanner.eof) { + this.eat(RIGHTCURLYBRACKET); + } + + 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$s = tokenizer$3.TYPE; + + var LEFTSQUAREBRACKET$2 = TYPE$s.LeftSquareBracket; + var RIGHTSQUAREBRACKET = TYPE$s.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); + } + + return { + type: 'Brackets', + loc: this.getLocation(start, this.scanner.tokenStart), + children: children + }; + }, + generate: function(node) { + this.chunk('['); + this.children(node); + this.chunk(']'); + } + }; + + var CDC$1 = tokenizer$3.TYPE.CDC; + + var CDC_1 = { + name: 'CDC', + structure: [], + parse: function() { + var start = this.scanner.tokenStart; + + this.eat(CDC$1); // --> + + return { + type: 'CDC', + loc: this.getLocation(start, this.scanner.tokenStart) + }; + }, + generate: function() { + this.chunk('-->'); + } + }; + + var CDO$1 = tokenizer$3.TYPE.CDO; + + var CDO_1 = { + name: 'CDO', + structure: [], + parse: function() { + var start = this.scanner.tokenStart; + + this.eat(CDO$1); // + child = this.CDC(); + break; + + // CSS Syntax Module Level 3 + // §2.2 Error handling + // At the "top level" of a stylesheet, an starts an at-rule. + case ATKEYWORD: + child = this.parseWithFallback(this.Atrule, consumeRaw$1); + break; + + // Anything else starts a qualified rule ... + default: + child = this.parseWithFallback(this.Rule, consumeRaw$1); + } + + 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$7 = tokenizer$3.TYPE; + + var IDENT$5 = TYPE$7.Ident; + var ASTERISK$2 = 0x002A; // U+002A ASTERISK (*) + var VERTICALLINE$1 = 0x007C; // U+007C VERTICAL LINE (|) + + function eatIdentifierOrAsterisk() { + if (this.scanner.tokenType !== IDENT$5 && + this.scanner.isDelim(ASTERISK$2) === 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$1)) { + this.scanner.next(); + eatIdentifierOrAsterisk.call(this); + } else { + eatIdentifierOrAsterisk.call(this); + + if (this.scanner.isDelim(VERTICALLINE$1)) { + 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 = tokenizer$3.isHexDigit; + var cmpChar$1 = tokenizer$3.cmpChar; + var TYPE$6 = tokenizer$3.TYPE; + var NAME = tokenizer$3.NAME; + + var IDENT$4 = TYPE$6.Ident; + var NUMBER$2 = TYPE$6.Number; + var DIMENSION$2 = TYPE$6.Dimension; + var PLUSSIGN$2 = 0x002B; // U+002B PLUS SIGN (+) + var HYPHENMINUS$1 = 0x002D; // U+002D HYPHEN-MINUS (-) + var QUESTIONMARK = 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$1 && allowDash && len !== 0) { + if (eatHexSequence.call(this, offset + len + 1, false) === 0) { + this.error(); + } + + return -1; + } + + if (!isHexDigit(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)) { + if (++count > max) { + this.error('Too many question marks'); + } + + this.scanner.next(); + } + } + + function startsWith(code) { + if (this.scanner.source.charCodeAt(this.scanner.tokenStart) !== code) { + this.error(NAME[code] + ' is expected'); + } + } + + // https://drafts.csswg.org/css-syntax/#urange + // Informally, the 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). + // + // = + // u '+' '?'* | + // u '?'* | + // u '?'* | + // u | + // u | + // u '+' '?'+ + function scanUnicodeRange() { + var hexLength = 0; + + // u '+' '?'* + // u '+' '?'+ + if (this.scanner.isDelim(PLUSSIGN$2)) { + this.scanner.next(); + + if (this.scanner.tokenType === IDENT$4) { + hexLength = eatHexSequence.call(this, 0, true); + if (hexLength > 0) { + eatQuestionMarkSequence.call(this, 6 - hexLength); + } + return; + } + + if (this.scanner.isDelim(QUESTIONMARK)) { + this.scanner.next(); + eatQuestionMarkSequence.call(this, 5); + return; + } + + this.error('Hex digit or question mark is expected'); + return; + } + + // u '?'* + // u + // u + if (this.scanner.tokenType === NUMBER$2) { + startsWith.call(this, PLUSSIGN$2); + hexLength = eatHexSequence.call(this, 1, true); + + if (this.scanner.isDelim(QUESTIONMARK)) { + eatQuestionMarkSequence.call(this, 6 - hexLength); + return; + } + + if (this.scanner.tokenType === DIMENSION$2 || + this.scanner.tokenType === NUMBER$2) { + startsWith.call(this, HYPHENMINUS$1); + eatHexSequence.call(this, 1, false); + return; + } + + return; + } + + // u '?'* + if (this.scanner.tokenType === DIMENSION$2) { + startsWith.call(this, PLUSSIGN$2); + 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$1(this.scanner.source, start, U$1)) { + this.error('U is expected'); + } + + if (!cmpChar$1(this.scanner.source, start + 1, PLUSSIGN$2)) { + 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 = tokenizer$3.isWhiteSpace; + var cmpStr$1 = tokenizer$3.cmpStr; + var TYPE$5 = tokenizer$3.TYPE; + + var FUNCTION$3 = TYPE$5.Function; + var URL$3 = TYPE$5.Url; + var RIGHTPARENTHESIS = TYPE$5.RightParenthesis; + + // | ) + var Url = { + name: 'Url', + structure: { + value: ['String', 'Raw'] + }, + parse: function() { + var start = this.scanner.tokenStart; + var value; + + switch (this.scanner.tokenType) { + case URL$3: + var rawStart = start + 4; + var rawEnd = this.scanner.tokenEnd - 1; + + while (rawStart < rawEnd && isWhiteSpace(this.scanner.source.charCodeAt(rawStart))) { + rawStart++; + } + + while (rawStart < rawEnd && isWhiteSpace(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$3); + break; + + case FUNCTION$3: + if (!cmpStr$1(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); + 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$2 = tokenizer$3.TYPE.WhiteSpace; + var SPACE = Object.freeze({ + type: 'WhiteSpace', + loc: null, + value: ' ' + }); + + var WhiteSpace = { + name: 'WhiteSpace', + structure: { + value: String + }, + parse: function() { + this.eat(WHITESPACE$2); + return SPACE; + + // 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, + Hash: Hash, + 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 + }; + + var data = data$1; + + var lexer = { + generic: true, + types: data.types, + atrules: data.atrules, + properties: data.properties, + node: node + }; + + var cmpChar = tokenizer$3.cmpChar; + var cmpStr = tokenizer$3.cmpStr; + var TYPE$4 = tokenizer$3.TYPE; + + var IDENT$3 = TYPE$4.Ident; + var STRING$1 = TYPE$4.String; + var NUMBER$1 = TYPE$4.Number; + var FUNCTION$2 = TYPE$4.Function; + var URL$2 = TYPE$4.Url; + var HASH$1 = TYPE$4.Hash; + var DIMENSION$1 = TYPE$4.Dimension; + var PERCENTAGE$1 = TYPE$4.Percentage; + var LEFTPARENTHESIS$2 = TYPE$4.LeftParenthesis; + var LEFTSQUAREBRACKET$1 = TYPE$4.LeftSquareBracket; + var COMMA$1 = TYPE$4.Comma; + var DELIM$1 = TYPE$4.Delim; + var NUMBERSIGN$1 = 0x0023; // U+0023 NUMBER SIGN (#) + var ASTERISK$1 = 0x002A; // U+002A ASTERISK (*) + var PLUSSIGN$1 = 0x002B; // U+002B PLUS SIGN (+) + var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-) + var SOLIDUS$1 = 0x002F; // U+002F SOLIDUS (/) + var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u) + + var _default = function defaultRecognizer(context) { + switch (this.scanner.tokenType) { + case HASH$1: + return this.Hash(); + + case COMMA$1: + context.space = null; + context.ignoreWSAfter = true; + return this.Operator(); + + case LEFTPARENTHESIS$2: + return this.Parentheses(this.readSequence, context.recognizer); + + case LEFTSQUAREBRACKET$1: + return this.Brackets(this.readSequence, context.recognizer); + + case STRING$1: + return this.String(); + + case DIMENSION$1: + return this.Dimension(); + + case PERCENTAGE$1: + return this.Percentage(); + + case NUMBER$1: + return this.Number(); + + case FUNCTION$2: + return cmpStr(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(') + ? this.Url() + : this.Function(this.readSequence, context.recognizer); + + case URL$2: + return this.Url(); + + case IDENT$3: + // check for unicode range, it should start with u+ or U+ + if (cmpChar(this.scanner.source, this.scanner.tokenStart, U) && + cmpChar(this.scanner.source, this.scanner.tokenStart + 1, PLUSSIGN$1)) { + return this.UnicodeRange(); + } else { + return this.Identifier(); + } + + case DELIM$1: + var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); + + if (code === SOLIDUS$1 || + code === ASTERISK$1 || + code === PLUSSIGN$1 || + code === HYPHENMINUS) { + return this.Operator(); // TODO: replace with Delim + } + + // TODO: produce a node with Delim node type + + if (code === NUMBERSIGN$1) { + this.error('Hex or identifier is expected', this.scanner.tokenStart + 1); + } + + break; + } + }; + + var atrulePrelude = { + getNode: _default + }; + + var TYPE$3 = tokenizer$3.TYPE; + + var DELIM = TYPE$3.Delim; + var IDENT$2 = TYPE$3.Ident; + var DIMENSION = TYPE$3.Dimension; + var PERCENTAGE = TYPE$3.Percentage; + var NUMBER = TYPE$3.Number; + var HASH = TYPE$3.Hash; + var COLON$1 = TYPE$3.Colon; + var LEFTSQUAREBRACKET = TYPE$3.LeftSquareBracket; + var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#) + var ASTERISK = 0x002A; // U+002A ASTERISK (*) + var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+) + var SOLIDUS = 0x002F; // U+002F SOLIDUS (/) + var FULLSTOP = 0x002E; // U+002E FULL STOP (.) + var GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>) + var VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|) + var TILDE = 0x007E; // U+007E TILDE (~) + + function getNode(context) { + switch (this.scanner.tokenType) { + case LEFTSQUAREBRACKET: + return this.AttributeSelector(); + + case HASH: + return this.IdSelector(); + + case COLON$1: + if (this.scanner.lookupType(1) === COLON$1) { + return this.PseudoElementSelector(); + } else { + return this.PseudoClassSelector(); + } + + case IDENT$2: + return this.TypeSelector(); + + case NUMBER: + case PERCENTAGE: + return this.Percentage(); + + case DIMENSION: + // throws when .123ident + if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === FULLSTOP) { + this.error('Identifier is expected', this.scanner.tokenStart + 1); + } + break; + + case DELIM: + var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); + + switch (code) { + case PLUSSIGN: + case GREATERTHANSIGN: + case TILDE: + context.space = null; + context.ignoreWSAfter = true; + return this.Combinator(); + + case SOLIDUS: // /deep/ + return this.Combinator(); + + case FULLSTOP: + return this.ClassSelector(); + + case ASTERISK: + case VERTICALLINE: + return this.TypeSelector(); + + case NUMBERSIGN: + return this.IdSelector(); + } + + break; + } + } + var selector = { + getNode: getNode + }; + + // legacy IE function + // expression( ) + var expression = function() { + return this.createSingleNodeList( + this.Raw(this.scanner.tokenIndex, null, false) + ); + }; + + var TYPE$2 = tokenizer$3.TYPE; + var rawMode = Raw.mode; + + var COMMA = TYPE$2.Comma; + var WHITESPACE$1 = TYPE$2.WhiteSpace; + + // var( , ? ) + 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) { + children.push(this.Operator()); + + const startIndex = this.scanner.tokenIndex; + const value = this.parseCustomProperty + ? this.Value(null) + : this.Raw(this.scanner.tokenIndex, rawMode.exclamationMarkOrSemicolon, false); + + if (value.type === 'Value' && value.children.isEmpty()) { + for (let offset = startIndex - this.scanner.tokenIndex; offset <= 0; offset++) { + if (this.scanner.lookupType(offset) === WHITESPACE$1) { + value.children.appendData({ + type: 'WhiteSpace', + loc: null, + value: ' ' + }); + break; + } + } + } + + children.push(value); + } + + return children; + }; + + var value$2 = { + getNode: _default, + 'expression': expression, + 'var': _var + }; + + var scope = { + AtrulePrelude: atrulePrelude, + Selector: selector, + Value: value$2 + }; + + var fontFace = { + parse: { + prelude: null, + block: function() { + return this.Block(true); + } + } + }; + + var TYPE$1 = tokenizer$3.TYPE; + + var STRING = TYPE$1.String; + var IDENT$1 = TYPE$1.Ident; + var URL$1 = TYPE$1.Url; + var FUNCTION$1 = TYPE$1.Function; + var LEFTPARENTHESIS$1 = TYPE$1.LeftParenthesis; + + var _import = { + parse: { + prelude: function() { + var children = this.createList(); + + this.scanner.skipSC(); + + switch (this.scanner.tokenType) { + case STRING: + children.push(this.String()); + break; + + case URL$1: + case FUNCTION$1: + children.push(this.Url()); + break; + + default: + this.error('String or url() is expected'); + } + + if (this.lookupNonWSType(0) === IDENT$1 || + this.lookupNonWSType(0) === LEFTPARENTHESIS$1) { + 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 = tokenizer$3.TYPE; + + var WHITESPACE = TYPE.WhiteSpace; + var COMMENT = TYPE.Comment; + var IDENT = TYPE.Ident; + var FUNCTION = TYPE.Function; + var COLON = TYPE.Colon; + var LEFTPARENTHESIS = TYPE.LeftParenthesis; + + function consumeRaw() { + return this.createSingleNodeList( + this.Raw(this.scanner.tokenIndex, null, false) + ); + } + + function parentheses() { + this.scanner.skipSC(); + + if (this.scanner.tokenType === IDENT && + this.lookupNonWSType(1) === COLON) { + 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: + space = this.WhiteSpace(); + continue; + + case COMMENT: + this.scanner.next(); + continue; + + case FUNCTION: + child = this.Function(consumeRaw, this.scope.AtrulePrelude); + break; + + case IDENT: + child = this.Identifier(); + break; + + case LEFTPARENTHESIS: + 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 = { + 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 = { + parse: function nth() { + return this.createSingleNodeList( + this.Nth(DISALLOW_OF_CLAUSE) + ); + } + }; + + var nthLastOfType = nth; + + var nthOfType = nth; + + var slotted = { + parse: function compoundSelector() { + return this.createSingleNodeList( + this.Selector() + ); + } + }; + + var pseudo = { + 'dir': dir, + 'has': has, + '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 + }; + + var _args = [ + [ + "css-tree@1.1.3", + "/home/gitlab-runner/builds/BQJy2NwB/0/pagedjs/pagedjs" + ] + ]; + var _from = "css-tree@1.1.3"; + var _id = "css-tree@1.1.3"; + var _inBundle = false; + var _integrity = "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q=="; + var _location = "/css-tree"; + var _phantomChildren = { + }; + var _requested = { + type: "version", + registry: true, + raw: "css-tree@1.1.3", + name: "css-tree", + escapedName: "css-tree", + rawSpec: "1.1.3", + saveSpec: null, + fetchSpec: "1.1.3" + }; + var _requiredBy = [ + "/" + ]; + var _resolved = "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz"; + var _spec = "1.1.3"; + var _where = "/home/gitlab-runner/builds/BQJy2NwB/0/pagedjs/pagedjs"; + var author = { + name: "Roman Dvornov", + email: "rdvornov@gmail.com", + url: "https://github.com/lahmatiy" + }; + var bugs = { + url: "https://github.com/csstree/csstree/issues" + }; + var dependencies = { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }; + var description = "A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations"; + var devDependencies = { + "@rollup/plugin-commonjs": "^11.0.2", + "@rollup/plugin-json": "^4.0.2", + "@rollup/plugin-node-resolve": "^7.1.1", + coveralls: "^3.0.9", + eslint: "^6.8.0", + "json-to-ast": "^2.1.0", + mocha: "^6.2.3", + nyc: "^14.1.1", + rollup: "^1.32.1", + "rollup-plugin-terser": "^5.3.0" + }; + var engines = { + node: ">=8.0.0" + }; + var files = [ + "data", + "dist", + "lib" + ]; + var homepage = "https://github.com/csstree/csstree#readme"; + var jsdelivr = "dist/csstree.min.js"; + var keywords = [ + "css", + "ast", + "tokenizer", + "parser", + "walker", + "lexer", + "generator", + "utils", + "syntax", + "validation" + ]; + var license = "MIT"; + var main = "lib/index.js"; + var name = "css-tree"; + var repository = { + type: "git", + url: "git+https://github.com/csstree/csstree.git" + }; + var scripts = { + build: "rollup --config", + coverage: "nyc npm test", + coveralls: "nyc report --reporter=text-lcov | coveralls", + hydrogen: "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/parse --stat -o /dev/null", + lint: "eslint data lib scripts test && node scripts/review-syntax-patch --lint && node scripts/update-docs --lint", + "lint-and-test": "npm run lint && npm test", + prepublishOnly: "npm run build", + "review:syntax-patch": "node scripts/review-syntax-patch", + test: "mocha --reporter progress", + travis: "nyc npm run lint-and-test && npm run coveralls", + "update:docs": "node scripts/update-docs" + }; + var unpkg = "dist/csstree.min.js"; + var version = "1.1.3"; + var require$$4 = { + _args: _args, + _from: _from, + _id: _id, + _inBundle: _inBundle, + _integrity: _integrity, + _location: _location, + _phantomChildren: _phantomChildren, + _requested: _requested, + _requiredBy: _requiredBy, + _resolved: _resolved, + _spec: _spec, + _where: _where, + author: author, + bugs: bugs, + dependencies: dependencies, + description: description, + devDependencies: devDependencies, + engines: engines, + files: files, + homepage: homepage, + jsdelivr: jsdelivr, + keywords: keywords, + license: license, + main: main, + name: name, + repository: repository, + scripts: scripts, + unpkg: unpkg, + version: version + }; + + 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; + } + + syntax.exports = create$4.create( + merge( + lexer, + parser, + walker + ) + ); + syntax.exports.version = require$$4.version; + + var syntaxExports = syntax.exports; + + var lib = syntaxExports; + + var csstree = /*@__PURE__*/getDefaultExportFromCjs(lib); + + 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 = csstree.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); + + this.declarations(rule); + + return inserted; + } + + urls(ast) { + csstree.walk(ast, { + visit: "Url", + enter: (node, item, list) => { + this.hooks.onUrl.trigger(node, item, list); + } + }); + } + + atrules(ast) { + csstree.walk(ast, { + visit: "Atrule", + enter: (node, item, list) => { + const basename = csstree.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) { + csstree.walk(ast, { + visit: "Rule", + enter: (ruleNode, ruleItem, rulelist) => { + + this.hooks.onRule.trigger(ruleNode, ruleItem, rulelist); + this.declarations(ruleNode, ruleItem, rulelist); + this.onSelector(ruleNode, ruleItem, rulelist); + + } + }); + } + + declarations(ruleNode, ruleItem, rulelist) { + csstree.walk(ruleNode, { + visit: "Declaration", + enter: (declarationNode, dItem, dList) => { + + this.hooks.onDeclaration.trigger(declarationNode, dItem, dList, {ruleNode, ruleItem, rulelist}); + + if (declarationNode.property === "content") { + csstree.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) { + csstree.walk(ruleNode, { + visit: "Selector", + enter: (selectNode, selectItem, selectList) => { + this.hooks.onSelector.trigger(selectNode, selectItem, selectList, {ruleNode, ruleItem, rulelist}); + + if (selectNode.children.forEach(node => {if (node.type === "PseudoElementSelector") { + csstree.walk(node, { + visit: "PseudoElementSelector", + enter: (pseudoNode, pItem, pList) => { + this.hooks.onPseudoSelector.trigger(pseudoNode, pItem, pList, {selectNode, selectItem, selectList}, {ruleNode, ruleItem, rulelist}); + } + }); + }})); + } + }); + } + + replaceUrls(ast) { + csstree.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 + csstree.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 = {}; + csstree.walk(ast, { + visit: "Rule", + enter: (node, item, list) => { + csstree.walk(node, { + visit: "Declaration", + enter: (declaration, dItem, dList) => { + if (declaration.property === "page") { + let value = declaration.value.children.first(); + let name = value.name; + let selector = csstree.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) { + csstree.walk(ast, { + visit: "Rule", + enter: (node, item, list) => { + + csstree.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 = []; + csstree.walk(node, { + visit: "MediaQuery", + enter: (mqNode, mqItem, mqList) => { + csstree.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; + } + + csstree.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 csstree.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-footnotes-height: 0mm; + --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-shadow: white; + --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; + --pagedjs-footnotes-count: 0; + --pagedjs-column-gap-offset: 1000px; +} + +@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); + box-shadow: 1px 0px 0px 0px var(--pagedjs-crop-shadow); +} + +.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); + box-shadow: -1px 0px 0px 0px var(--pagedjs-crop-shadow); +} + +.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); + box-shadow: 0px 1px 0px 0px var(--pagedjs-crop-shadow); +} + +.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); + box-shadow: 0px -1px 0px 0px var(--pagedjs-crop-shadow); +} + +.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: calc(100% - var(--pagedjs-footnotes-height)); + position: relative; + column-fill: auto; +} + +.pagedjs_pagebox > .pagedjs_area > .pagedjs_page_content > div { + height: inherit; +} + +.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area { + position: relative; + overflow: hidden; + height: var(--pagedjs-footnotes-height); + display: flex; + justify-content: flex-end; + flex-flow: column; +} + +.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_content { + overflow: hidden; +} + +.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_inner_content { + overflow: hidden; +} + +.pagedjs_area [data-footnote-call] { + all: unset; + counter-increment: footnote; +} + +.pagedjs_area [data-split-from] { + counter-increment: unset; + counter-reset: unset; +} + +[data-footnote-call]::after { + vertical-align: super; + font-size: 65%; + line-height: normal; + content: counter(footnote); +} + +@supports ( font-variant-position: super ) { + [data-footnote-call]::after { + vertical-align: baseline; + font-size: 100%; + line-height: inherit; + font-variant-position: super; + } +} + +.pagedjs_footnote_empty { + display: none; +} + +.pagedjs_area [data-split-from] { + counter-increment: unset; + counter-reset: unset; +} + +[data-footnote-marker] { + text-indent: 0; + display: list-item; + list-style-position: inside; +} + +[data-footnote-marker][data-split-from] { + list-style: none; +} + +[data-footnote-marker]:not([data-split-from]) { + counter-increment: footnote-marker; +} + +[data-footnote-marker]::marker { + content: counter(footnote-marker) ". "; +} + +[data-footnote-marker][data-split-from]::marker { + content: unset; +} + +.pagedjs_area .pagedjs_footnote_inner_content [data-note-display="inline"] { + display: inline; +} + +.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) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-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]:not([data-footnote-call]):after, +.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:not([data-footnote-call])::after { + content: unset; +} + +.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call]):before, +.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call])::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%; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + 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.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, + notes: undefined, + added: false + }; + } + + // 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 = csstree.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; + // Mark page for getting classes added again + page.added = false; + } 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 notes = this.replaceNotes(node); + page.notes = notes; + + 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) { + let dirtyPage = "*" in this.pages && this.pages["*"].added === false; + + this.addPageClasses(this.pages, ast, sheet); + + if (dirtyPage) { + 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; + + csstree.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; + csstree.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; + csstree.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 = {}; + const MARGINS = [ + "top-left-corner", "top-left", "top", "top-center", "top-right", "top-right-corner", + "bottom-left-corner", "bottom-left", "bottom", "bottom-center", "bottom-right", "bottom-right-corner", + "left-top", "left-middle", "left", "left-bottom", "top-right-corner", + "right-top", "right-middle", "right", "right-bottom", "right-right-corner" + ]; + csstree.walk(ast.block, { + visit: "Atrule", + enter: (node, item, list) => { + let name = node.name; + if (MARGINS.includes(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; + } + + replaceNotes(ast) { + let parsed = {}; + + csstree.walk(ast.block, { + visit: "Atrule", + enter: (node, item, list) => { + let name = node.name; + if (name === "footnote") { + parsed[name] = node.block; + list.remove(item); + } + } + }); + + return parsed; + } + + replaceDeclarations(ast) { + let parsed = {}; + + csstree.walk(ast.block, { + visit: "Declaration", + enter: (declaration, dItem, dList) => { + let prop = csstree.property(declaration.property).name; + // let value = declaration.value; + + if (prop === "marks") { + parsed.marks = []; + csstree.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 = csstree.generate(declaration.value); + parsed.border.right = csstree.generate(declaration.value); + parsed.border.left = csstree.generate(declaration.value); + parsed.border.bottom = csstree.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] = csstree.generate(declaration.value); + dList.remove(dItem); + + } + + else if (prop === "size") { + parsed.size = this.getSize(declaration); + dList.remove(dItem); + } else if (prop === "bleed") { + parsed.bleed = []; + + csstree.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 + csstree.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" + csstree.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 + csstree.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: {} + }; + + csstree.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: {} + }; + + csstree.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 = csstree.generate(declaration.value); + border.right = csstree.generate(declaration.value); + border.bottom = csstree.generate(declaration.value); + border.left = csstree.generate(declaration.value); + + } + else if (declaration.prop == "border-top") { + border.top = csstree.generate(declaration.value); + } + else if (declaration.prop == "border-right") { + border.right = csstree.generate(declaration.value); + + } + else if (declaration.prop == "border-bottom") { + border.bottom = csstree.generate(declaration.value); + + } + else if (declaration.prop == "border-left") { + border.left = csstree.generate(declaration.value); + } + + return border; + } + + + addPageClasses(pages, ast, sheet) { + // First add * page + if ("*" in pages && pages["*"].added === false) { + let p = this.createPage(pages["*"], ast.children, sheet); + sheet.insertRule(p); + pages["*"].added = true; + } + // Add :left & :right + if (":left" in pages && pages[":left"].added === false) { + let left = this.createPage(pages[":left"], ast.children, sheet); + sheet.insertRule(left); + pages[":left"].added = true; + } + if (":right" in pages && pages[":right"].added === false) { + let right = this.createPage(pages[":right"], ast.children, sheet); + sheet.insertRule(right); + pages[":right"].added = true; + } + // Add :first & :blank + if (":first" in pages && pages[":first"].added === false) { + let first = this.createPage(pages[":first"], ast.children, sheet); + sheet.insertRule(first); + pages[":first"].added = true; + } + if (":blank" in pages && pages[":blank"].added === false) { + let blank = this.createPage(pages[":blank"], ast.children, sheet); + sheet.insertRule(blank); + pages[":blank"].added = true; + } + // Add nth pages + for (let pg in pages) { + if (pages[pg].nth && pages[pg].added === false) { + let nth = this.createPage(pages[pg], ast.children, sheet); + sheet.insertRule(nth); + pages[pg].added = true; + } + } + + // Add named pages + for (let pg in pages) { + if (pages[pg].name && pages[pg].added === false) { + let named = this.createPage(pages[pg], ast.children, sheet); + sheet.insertRule(named); + pages[pg].added = true; + } + } + + } + + 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); + } + + if(page.notes) { + this.addNotesStyles(page.notes, 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 (const name of Object.keys(border)) { + const value = border[name]; + // value is an empty object when undefined + if (typeof value === "string") { + const borderItem = list.createItem({ + type: "Declaration", + property: "--pagedjs-border-" + name, + value: { + type: "Raw", + value: value + } + }); + list.append(borderItem, 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 = csstree.clone(page.marginalia[loc]); + let hasContent = false; + + if (block.children.isEmpty()) { + continue; + } + + csstree.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") { + csstree.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 = csstree.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 = csstree.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 = csstree.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 = csstree.clone(page.marginalia[loc]); + csstree.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 csstree.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); + } + + + addNotesStyles(notes, page, list, item, sheet) { + + for (const note in notes) { + let selectors = this.selectorsForPage(page); + + selectors.insertData({ + type: "Combinator", + name: " " + }); + + selectors.insertData({ + type: "ClassSelector", + name: "pagedjs_" + note + "_content" + }); + + let notesRule = this.createRule(selectors, notes[note]); + + list.appendData(notesRule); + } + + } + + /* + @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 csstree.List(); + let childrenLeft = new csstree.List(); + let childrenRight = new csstree.List(); + let dimensions = new csstree.List(); + let dimensionsLeft = new csstree.List(); + let dimensionsRight = new csstree.List(); + + if (bleed) { + let widthCalculations = new csstree.List(); + let heightCalculations = new csstree.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 csstree.List(); + let heightCalculationsLeft = new csstree.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 csstree.List(); + let heightCalculationsRight = new csstree.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 namedPages = [start.dataset.page]; + + if (namedPages && namedPages.length) { + for (const named of namedPages) { + if (!named) { + continue; + } + 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; + } + + finalizePage(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 csstree.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 csstree.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 csstree.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 csstree.List(); + let calculations = new csstree.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 csstree.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 csstree.List(); + + declarations.forEach((declaration) => { + block.insertData(declaration); + }); + + return { + type: "Block", + loc: null, + children: block + }; + } + + createRule(selectors, block) { + let selectorList = new csstree.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 = csstree.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 = csstree.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.includes("print")) { + rules = node.block.children; + + // Append rules to the end of main rules list + // TODO: this isn't working right, needs to check what is in the prelude + /* + rules.forEach((selectList) => { + if (selectList.prelude) { + selectList.prelude.children.forEach((rule) => { + + rule.children.prependData({ + type: "Combinator", + name: " " + }); + + rule.children.prependData({ + type: "ClassSelector", + name: "pagedjs_page" + }); + }); + } + }); + + list.insertList(rules, item); + */ + + // Append rules to the end of main rules list + list.appendList(rules); + + // Remove rules from the @media block + list.remove(item); + } else if (!media.includes("all") && !media.includes("pagedjs-ignore")) { + list.remove(item); + } + + } + + getMediaName(node) { + let media = []; + + if (typeof node.prelude === "undefined" || + node.prelude.type !== "AtrulePrelude" ) { + return; + } + + csstree.walk(node.prelude, { + visit: "Identifier", + enter: (identNode, iItem, iList) => { + media.push(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") { + this.handleIncrement(declaration, rule); + // clean up empty declaration + let hasProperities = false; + declaration.value.children.forEach((data) => { + if (data.type && data.type !== "WhiteSpace") { + hasProperities = true; + } + }); + if (!hasProperities) { + dList.remove(dItem); + } + } else if (property === "counter-reset") { + this.handleReset(declaration, rule); + // clean up empty declaration + let hasProperities = false; + declaration.value.children.forEach((data) => { + if (data.type && data.type !== "WhiteSpace") { + hasProperities = true; + } + }); + if (!hasProperities) { + dList.remove(dItem); + } + } + } + + 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) { + let increments = []; + let children = declaration.value.children; + + children.forEach((data, item) => { + if (data.type && data.type === "Identifier") { + let name = data.name; + + if (name === "page" || name.indexOf("target-counter-") === 0) { + return; + } + + let whitespace, number, value; + if (item.next && item.next.data.type === "WhiteSpace") { + whitespace = item.next; + } + if (whitespace && whitespace.next && whitespace.next.data.type === "Number") { + number = whitespace.next; + value = parseInt(number.data.value); + } + + let selector = csstree.generate(rule.ruleNode.prelude); + + let counter; + if (!(name in this.counters)) { + counter = this.addCounter(name); + } else { + counter = this.counters[name]; + } + let increment = { + selector: selector, + number: value || 1 + }; + counter.increments[selector] = increment; + increments.push(increment); + + // Remove the parsed resets + children.remove(item); + if (whitespace) { + children.remove(whitespace); + } + if (number) { + children.remove(number); + } + } + }); + + return increments; + } + + handleReset(declaration, rule) { + let children = declaration.value.children; + + children.forEach((data, item) => { + if (data.type && data.type === "Identifier") { + let name = data.name; + let whitespace, number, value; + if (item.next && item.next.data.type === "WhiteSpace") { + whitespace = item.next; + } + if (whitespace && whitespace.next) { + if (whitespace.next.data.type === "Number") { + // The counter reset value is specified using a number. E.g. counter-reset: c2 5; + number = whitespace.next; + value = parseInt(number.data.value); + } else if (whitespace.next.data.type === "Function" && whitespace.next.data.name === "var") { + // The counter reset value is specified using a CSS variable (custom property). + // E.g. counter-reset: c2 var(--my-variable); + // See https://developer.mozilla.org/en-US/docs/Web/CSS/var + number = whitespace.next; + // Use the variable name (e.g. '--my-variable') as value for now. The actual value is resolved later by the + // processCounterResets function. + value = whitespace.next.data.children.head.data.name; + } + } + + let counter; + let selector; + let prelude = rule.ruleNode.prelude; + + if (rule.ruleNode.type === "Atrule" && rule.ruleNode.name === "page") { + selector = ".pagedjs_page"; + } else { + selector = csstree.generate(prelude || rule.ruleNode); + } + + if (name === "footnote") { + this.addFootnoteMarkerCounter(declaration.value.children); + } + + if (!(name in this.counters)) { + counter = this.addCounter(name); + } else { + counter = this.counters[name]; + } + + let reset = { + selector: selector, + number: value || 0 + }; + + counter.resets[selector] = reset; + + if (selector !== ".pagedjs_page") { + // Remove the parsed resets + children.remove(item); + if (whitespace) { + children.remove(whitespace); + } + if (number) { + children.remove(number); + } + } + } + }); + } + + 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) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-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); + if (incrementElements[i].getAttribute("data-counter-increment")) { + incrementElements[i].setAttribute("data-counter-increment", incrementElements[i].getAttribute("data-counter-increment") + " " + counter.name); + } else { + 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++) { + let value = reset.number; + if (typeof value === "string" && value.startsWith("--")) { + // The value is specified using a CSS variable (custom property). + // FIXME: We get the variable value only from the inline style of the element because at this point the + // element is detached and thus using: + // + // getComputedStyle(resetElements[i]).getPropertyValue(value) + // + // always returns an empty string. We could try to temporarily attach the element to get its computed style, + // but for now using the inline style is enough for us. + value = resetElements[i].style.getPropertyValue(value) || 0; + } + resetElements[i].setAttribute("data-counter-"+ counter.name +"-reset", value); + if (resetElements[i].getAttribute("data-counter-reset")) { + resetElements[i].setAttribute("data-counter-reset", resetElements[i].getAttribute("data-counter-reset") + " " + counter.name); + } else { + resetElements[i].setAttribute("data-counter-reset", counter.name); + } + } + } + } + + addCounterValues(parsed, counter) { + let counterName = counter.name; + + if (counterName === "page" || counterName === "footnote") { + return; + } + + let 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); + } + + } + } + + addFootnoteMarkerCounter(list) { + let markers = []; + csstree.walk(list, { + visit: "Identifier", + enter: (identNode, iItem, iList) => { + markers.push(identNode.name); + } + }); + + // Already added + if (markers.includes("footnote-maker")) { + return; + } + + list.insertData({ + type: "WhiteSpace", + value: " " + }); + + list.insertData({ + type: "Identifier", + name: "footnote-marker" + }); + + list.insertData({ + type: "WhiteSpace", + value: " " + }); + + list.insertData({ + type: "Number", + value: 0 + }); + } + + incrementCounterForElement(element, incrementArray) { + if (!element || !incrementArray || incrementArray.length === 0) return; + + const ref = element.dataset.ref; + const increments = Array.from(this.styleSheet.cssRules).filter((rule) => { + return rule.selectorText === `[data-ref="${element.dataset.ref}"]:not([data-split-from])` + && rule.style[0] === "counter-increment"; + }).map(rule => rule.style.counterIncrement); + + // Merge the current increments by summing the values because we generate both a decrement and an increment when the + // element resets and increments the counter at the same time. E.g. ['c1 -7', 'c1 1'] should lead to 'c1 -6'. + increments.push(this.mergeIncrements(incrementArray, + (prev, next) => (parseInt(prev) || 0) + (parseInt(next) || 0))); + + // Keep the last value for each counter when merging with the previous increments. E.g. ['c1 -7 c2 3', 'c1 1'] + // should lead to 'c1 1 c2 3'. + const counterIncrement = this.mergeIncrements(increments, (prev, next) => next); + this.insertRule(`[data-ref="${ref}"]:not([data-split-from]) { counter-increment: ${counterIncrement} }`); + } + + /** + * Merge multiple values of a counter-increment CSS rule, using the specified operator. + * + * @param {Array} incrementArray the values to merge, e.g. ['c1 1', 'c1 -7 c2 1'] + * @param {Function} operator the function used to merge counter values (e.g. keep the last value of a counter or sum + * the counter values) + * @return {string} the merged value of the counter-increment CSS rule + */ + mergeIncrements(incrementArray, operator) { + const increments = {}; + incrementArray.forEach(increment => { + let values = increment.split(" "); + for (let i = 0; i < values.length; i+=2) { + increments[values[i]] = operator(increments[values[i]], values[i + 1]); + } + }); + + return Object.entries(increments).map(([key, value]) => `${key} ${value}`).join(" "); + } + + afterPageLayout(pageElement, page) { + let resets = []; + + let pgreset = pageElement.querySelectorAll("[data-counter-page-reset]:not([data-split-from])"); + 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; + resets.push(`page ${value}`); + } + }); + + let notereset = pageElement.querySelectorAll("[data-counter-footnote-reset]:not([data-split-from])"); + notereset.forEach((reset) => { + let value = reset.dataset.counterFootnoteReset; + resets.push(`footnote ${value}`); + resets.push(`footnote-marker ${value}`); + }); + + if (resets.length) { + this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] { counter-increment: none; counter-reset: ${resets.join(" ")} }`, 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.firstElementChild) { + list.start = list.firstElementChild.dataset.itemNum; + } + } + } + + 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 = csstree.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 && 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 = csstree.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 = csstree.generate(ruleNode.prelude); + if (selector.match(/:(first|last|nth)-of-type/)) { + + let declarations = csstree.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 = csstree.generate(ruleNode.prelude); + if (selector.match(/\+/)) { + + let declarations = csstree.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); + } + } + } + + class Footnotes extends Handler { + constructor(chunker, polisher, caller) { + super(chunker, polisher, caller); + + this.footnotes = {}; + this.needsLayout = []; + } + + onDeclaration(declaration, dItem, dList, rule) { + let property = declaration.property; + if (property === "float") { + let identifier = declaration.value.children && declaration.value.children.first(); + let location = identifier && identifier.name; + if (location === "footnote") { + let selector = csstree.generate(rule.ruleNode.prelude); + this.footnotes[selector] = { + selector: selector, + policy: "auto", + display: "block" + }; + dList.remove(dItem); + } + } + if (property === "footnote-policy") { + let identifier = declaration.value.children && declaration.value.children.first(); + let policy = identifier && identifier.name; + if (policy) { + let selector = csstree.generate(rule.ruleNode.prelude); + let note = this.footnotes[selector]; + if (note) { + note.policy = policy; + } + } + } + if (property === "footnote-display") { + let identifier = declaration.value.children && declaration.value.children.first(); + let display = identifier && identifier.name; + let selector = csstree.generate(rule.ruleNode.prelude); + if (display && this.footnotes[selector]) { + let note = this.footnotes[selector]; + if (note) { + note.display = display; + } + } + } + } + + onPseudoSelector(pseudoNode, pItem, pList, selector, rule) { + let name = pseudoNode.name; + if (name === "footnote-marker") { + // switch ::footnote-marker to [data-footnote-marker]::before + let prelude = rule.ruleNode.prelude; + let newPrelude = new csstree.List(); + + // Can't get remove to work, so just copying everything else + prelude.children.first().children.each((node) => { + if (node.type !== "PseudoElementSelector") { + newPrelude.appendData(node); + } + }); + + // Add our data call + newPrelude.appendData({ + type: "AttributeSelector", + name: { + type: "Identifier", + name: "data-footnote-marker", + }, + flags: null, + loc: null, + matcher: null, + value: null + }); + + // Add new pseudo element + newPrelude.appendData({ + type: "PseudoElementSelector", + name: "marker", + loc: null, + children: null + }); + + prelude.children.first().children = newPrelude; + } + + if (name === "footnote-call") { + // switch ::footnote-call to [data-footnote-call]::after + + let prelude = rule.ruleNode.prelude; + let newPrelude = new csstree.List(); + + // Can't get remove to work, so just copying everything else + prelude.children.first().children.each((node) => { + if (node.type !== "PseudoElementSelector") { + newPrelude.appendData(node); + } + }); + + // Add our data call + newPrelude.appendData({ + type: "AttributeSelector", + name: { + type: "Identifier", + name: "data-footnote-call", + }, + flags: null, + loc: null, + matcher: null, + value: null + }); + + // Add new pseudo element + newPrelude.appendData({ + type: "PseudoElementSelector", + name: "after", + loc: null, + children: null + }); + + prelude.children.first().children = newPrelude; + } + } + + afterParsed(parsed) { + this.processFootnotes(parsed, this.footnotes); + } + + processFootnotes(parsed, notes) { + for (let n in notes) { + // Find elements + let elements = parsed.querySelectorAll(n); + let element; + let note = notes[n]; + for (var i = 0; i < elements.length; i++) { + element = elements[i]; + // Add note type + element.setAttribute("data-note", "footnote"); + element.setAttribute("data-break-before", "avoid"); + element.setAttribute("data-note-policy", note.policy || "auto"); + element.setAttribute("data-note-display", note.display || "block"); + // Mark all parents + this.processFootnoteContainer(element); + } + } + } + + processFootnoteContainer(node) { + // Find the container + let element = node.parentElement; + let prevElement = element; + // Walk up the dom until we find a container element + while (element) { + if (isContainer(element)) { + // Add flag to the previous non-container element that will render with children + prevElement.setAttribute("data-has-notes", "true"); + break; + } + + prevElement = element; + element = element.parentElement; + + // If no containers were found and there are no further parents flag the last element + if (!element) { + prevElement.setAttribute("data-has-notes", "true"); + } + } + } + + renderNode(node) { + if (node.nodeType == 1) { + // Get all notes + let notes; + + // Ingnore html element nodes, like mathml + if (!node.dataset) { + return; + } + + if (node.dataset.note === "footnote") { + notes = [node]; + } else if (node.dataset.hasNotes || node.querySelectorAll("[data-note='footnote']")) { + notes = node.querySelectorAll("[data-note='footnote']"); + } + + if (notes && notes.length) { + this.findVisibleFootnotes(notes, node); + } + } + } + + findVisibleFootnotes(notes, node) { + let area, size, right; + area = node.closest(".pagedjs_page_content"); + size = area.getBoundingClientRect(); + right = size.left + size.width; + + for (let i = 0; i < notes.length; ++i) { + let currentNote = notes[i]; + let bounds = currentNote.getBoundingClientRect(); + let left = bounds.left; + + if (left < right) { + // Add call for the note + this.moveFootnote(currentNote, node.closest(".pagedjs_area"), true); + } + } + } + + moveFootnote(node, pageArea, needsNoteCall) { + // let pageArea = node.closest(".pagedjs_area"); + let noteArea = pageArea.querySelector(".pagedjs_footnote_area"); + let noteContent = noteArea.querySelector(".pagedjs_footnote_content"); + let noteInnerContent = noteContent.querySelector(".pagedjs_footnote_inner_content"); + + if (!isElement(node)) { + return; + } + + // Add call for the note + let noteCall; + if (needsNoteCall) { + noteCall = this.createFootnoteCall(node); + } + + // Remove the break before attribute for future layout + node.removeAttribute("data-break-before"); + + // Check if note already exists for overflow + let existing = noteInnerContent.querySelector(`[data-ref="${node.dataset.ref}"]`); + if (existing) { + // Remove the note from the flow but no need to render it again + node.remove(); + return; + } + + // Add the note node + noteInnerContent.appendChild(node); + + // Remove empty class + if (noteContent.classList.contains("pagedjs_footnote_empty")) { + noteContent.classList.remove("pagedjs_footnote_empty"); + } + + // Add marker + node.dataset.footnoteMarker = node.dataset.ref; + + // Add Id + node.id = `note-${node.dataset.ref}`; + + // Get note content size + let height = noteContent.scrollHeight; + + // Check the noteCall is still on screen + let area = pageArea.querySelector(".pagedjs_page_content"); + let size = area.getBoundingClientRect(); + let right = size.left + size.width; + + // TODO: add a max height in CSS + + // Check element sizes + let noteCallBounds = noteCall && noteCall.getBoundingClientRect(); + let noteAreaBounds = noteArea.getBoundingClientRect(); + + // Get the @footnote margins + let noteContentMargins = this.marginsHeight(noteContent); + let noteContentPadding = this.paddingHeight(noteContent); + let noteContentBorders = this.borderHeight(noteContent); + let total = noteContentMargins + noteContentPadding + noteContentBorders; + + // Get the top of the @footnote area + let notAreaTop = Math.floor(noteAreaBounds.top); + // If the height isn't set yet, remove the margins from the top + if (noteAreaBounds.height === 0) { + notAreaTop -= this.marginsHeight(noteContent, false); + notAreaTop -= this.paddingHeight(noteContent, false); + notAreaTop -= this.borderHeight(noteContent, false); + } + // Determine the note call position and offset per policy + let notePolicy = node.dataset.notePolicy; + let noteCallPosition = 0; + let noteCallOffset = 0; + if (noteCall) { + // Get the correct line bottom for super or sub styled callouts + let prevSibling = noteCall.previousSibling; + let range = new Range(); + if (prevSibling) { + range.setStartBefore(prevSibling); + } else { + range.setStartBefore(noteCall); + } + range.setEndAfter(noteCall); + let rangeBounds = range.getBoundingClientRect(); + noteCallPosition = rangeBounds.bottom; + if (!notePolicy || notePolicy === "auto") { + noteCallOffset = Math.ceil(rangeBounds.bottom); + } else if (notePolicy === "line") { + noteCallOffset = Math.ceil(rangeBounds.top); + } else if (notePolicy === "block") { + // Check that there is a previous element on the page + let parentParagraph = noteCall.closest("p").previousElementSibling; + if (parentParagraph) { + noteCallOffset = Math.ceil( + parentParagraph.getBoundingClientRect().bottom + ); + } else { + noteCallOffset = Math.ceil(rangeBounds.bottom); + } + } + } + + let contentDelta = height + total - noteAreaBounds.height; + // Space between the top of the footnotes area and the bottom of the footnote call + let noteDelta = noteCallPosition ? notAreaTop - noteCallPosition : 0; + // Space needed for the force a break for the policy of the footnote + let notePolicyDelta = noteCallPosition ? Math.floor(noteAreaBounds.top) - noteCallOffset : 0; + let hasNotes = noteArea.querySelector("[data-note='footnote']"); + if (needsNoteCall && noteCallBounds.left > right) { + // Note is offscreen and will be chunked to the next page on overflow + node.remove(); + } else if (!hasNotes && needsNoteCall && total > noteDelta) { + // No space to add even the footnote area + pageArea.style.setProperty("--pagedjs-footnotes-height", "0px"); + // Add a wrapper as this div is removed later + let wrapperDiv = document.createElement("div"); + wrapperDiv.appendChild(node); + // Push to the layout queue for the next page + this.needsLayout.push(wrapperDiv); + } else if (!needsNoteCall) { + // Call was previously added, force adding footnote + pageArea.style.setProperty( + "--pagedjs-footnotes-height", + `${height + total}px` + ); + } else if (noteCallPosition < noteAreaBounds.top - contentDelta) { + // the current note content will fit without pushing the call to the next page + pageArea.style.setProperty( + "--pagedjs-footnotes-height", + `${height + noteContentMargins + noteContentBorders}px` + ); + } else { + // set height to just before note call + pageArea.style.setProperty( + "--pagedjs-footnotes-height", + `${noteAreaBounds.height + notePolicyDelta}px` + ); + noteInnerContent.style.height = + noteAreaBounds.height + notePolicyDelta - total + "px"; + } + } + + createFootnoteCall(node) { + let parentElement = node.parentElement; + let footnoteCall = document.createElement("a"); + for (const className of node.classList) { + footnoteCall.classList.add(`${className}`); + } + + footnoteCall.dataset.footnoteCall = node.dataset.ref; + footnoteCall.dataset.ref = node.dataset.ref; + + // Increment for counters + footnoteCall.dataset.dataCounterFootnoteIncrement = 1; + + // Add link + footnoteCall.href = `#note-${node.dataset.ref}`; + + parentElement.insertBefore(footnoteCall, node); + + return footnoteCall; + } + + afterPageLayout(pageElement, page, breakToken, chunker) { + let pageArea = pageElement.querySelector(".pagedjs_area"); + let noteArea = page.footnotesArea; + let noteContent = noteArea.querySelector(".pagedjs_footnote_content"); + let noteInnerContent = noteArea.querySelector(".pagedjs_footnote_inner_content"); + + let noteContentBounds = noteContent.getBoundingClientRect(); + let { width } = noteContentBounds; + + noteInnerContent.style.columnWidth = Math.round(width) + "px"; + noteInnerContent.style.columnGap = "calc(var(--pagedjs-margin-right) + var(--pagedjs-margin-left))"; + + // Get overflow + let layout = new Layout(noteArea, undefined, chunker.settings); + let overflow = layout.findOverflow(noteInnerContent, noteContentBounds); + + if (overflow) { + let { startContainer, startOffset } = overflow; + let startIsNode; + if (isElement(startContainer)) { + let start = startContainer.childNodes[startOffset]; + startIsNode = isElement(start) && start.hasAttribute("data-footnote-marker"); + } + + let extracted = overflow.extractContents(); + + if (!startIsNode) { + let splitChild = extracted.firstElementChild; + splitChild.dataset.splitFrom = splitChild.dataset.ref; + + this.handleAlignment(noteInnerContent.lastElementChild); + } + + this.needsLayout.push(extracted); + + noteContent.style.removeProperty("height"); + noteInnerContent.style.removeProperty("height"); + + let noteInnerContentBounds = noteInnerContent.getBoundingClientRect(); + let { height } = noteInnerContentBounds; + + // Get the @footnote margins + let noteContentMargins = this.marginsHeight(noteContent); + let noteContentPadding = this.paddingHeight(noteContent); + let noteContentBorders = this.borderHeight(noteContent); + pageArea.style.setProperty( + "--pagedjs-footnotes-height", + `${height + noteContentMargins + noteContentBorders + noteContentPadding}px` + ); + + // Hide footnote content if empty + if (noteInnerContent.childNodes.length === 0) { + noteContent.classList.add("pagedjs_footnote_empty"); + } + + if (!breakToken) { + chunker.clonePage(page); + } else { + let breakBefore, previousBreakAfter; + if ( + breakToken.node && + typeof breakToken.node.dataset !== "undefined" && + typeof breakToken.node.dataset.previousBreakAfter !== "undefined" + ) { + previousBreakAfter = breakToken.node.dataset.previousBreakAfter; + } + + if ( + breakToken.node && + typeof breakToken.node.dataset !== "undefined" && + typeof breakToken.node.dataset.breakBefore !== "undefined" + ) { + breakBefore = breakToken.node.dataset.breakBefore; + } + + if (breakBefore || previousBreakAfter) { + chunker.clonePage(page); + } + } + } + noteInnerContent.style.height = "auto"; + } + + handleAlignment(node) { + let styles = window.getComputedStyle(node); + let alignLast = styles["text-align-last"]; + node.dataset.lastSplitElement = "true"; + if (alignLast === "auto") { + node.dataset.alignLastSplitElement = "justify"; + } else { + node.dataset.alignLastSplitElement = alignLast; + } + } + + beforePageLayout(page) { + while (this.needsLayout.length) { + let fragment = this.needsLayout.shift(); + + Array.from(fragment.childNodes).forEach((node) => { + this.moveFootnote( + node, + page.element.querySelector(".pagedjs_area"), + false + ); + }); + } + } + + afterOverflowRemoved(removed, rendered) { + // Find the page area + let area = rendered.closest(".pagedjs_area"); + // Get any rendered footnotes + let notes = area.querySelectorAll(".pagedjs_footnote_area [data-note='footnote']"); + for (let n = 0; n < notes.length; n++) { + const note = notes[n]; + // Check if the call for that footnote has been removed with the overflow + let call = removed.querySelector(`[data-footnote-call="${note.dataset.ref}"]`); + if (call) { + note.remove(); + } + } + // Hide footnote content if empty + let noteInnerContent = area.querySelector(".pagedjs_footnote_inner_content"); + if (noteInnerContent && noteInnerContent.childNodes.length === 0) { + noteInnerContent.parentElement.classList.add("pagedjs_footnote_empty"); + } + } + + marginsHeight(element, total=true) { + let styles = window.getComputedStyle(element); + let marginTop = parseInt(styles.marginTop); + let marginBottom = parseInt(styles.marginBottom); + let margin = 0; + if (marginTop) { + margin += marginTop; + } + if (marginBottom && total) { + margin += marginBottom; + } + return margin; + } + + paddingHeight(element, total=true) { + let styles = window.getComputedStyle(element); + let paddingTop = parseInt(styles.paddingTop); + let paddingBottom = parseInt(styles.paddingBottom); + let padding = 0; + if (paddingTop) { + padding += paddingTop; + } + if (paddingBottom && total) { + padding += paddingBottom; + } + return padding; + } + + borderHeight(element, total=true) { + let styles = window.getComputedStyle(element); + let borderTop = parseInt(styles.borderTop); + let borderBottom = parseInt(styles.borderBottom); + let borders = 0; + if (borderTop) { + borders += borderTop; + } + if (borderBottom && total) { + borders += borderBottom; + } + return borders; + } + } + + var pagedMediaHandlers = [ + PrintMedia, + AtPage, + Breaks, + Splits, + Counters, + Lists, + PositionFixed, + PageCounterIncrement, + NthOfType, + Following, + Footnotes + ]; + + 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 = csstree.generate(rule.ruleNode.prelude); + let identifier = declaration.value.children.first().name; + + if (identifier === "running") { + let value; + csstree.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") { + + csstree.walk(declaration, { + visit: "Function", + enter: (funcNode, fItem, fList) => { + + if (funcNode.name.indexOf("element") > -1) { + + let selector = csstree.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 (/^pagedjs_[\w-]+_first_page$/.test(parts[3])) { + 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 = csstree.generate(rule.ruleNode.prelude); + + let identifiers = []; + let functions = []; + let values = []; + + declaration.value.children.forEach((child) => { + if (child.type === "Identifier") { + identifiers.push(child.name); + } + if (child.type === "Function") { + functions.push(child.name); + child.children.forEach((subchild) => { + if (subchild.type === "Identifier") { + values.push(subchild.name); + } + }); + } + }); + + identifiers.forEach((identifier, index) => { + let func = functions[index]; + let value = values[index]; + this.stringSetSelectors[identifier] = { + identifier, + func, + 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 csstree.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 value = set.value; + let func = set.func; + 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. + if (func === "content") { + this.pageLastString[name] = selected[selected.length - 1].textContent; + } + + if (func === "attr") { + this.pageLastString[name] = selected[selected.length - 1].getAttribute(value) || ""; + } + + }); + + /* FIRST */ + + if (func === "content") { + varFirst = selected[0].textContent; + } + + if (func === "attr") { + varFirst = selected[0].getAttribute(value) || ""; + } + + + /* LAST */ + + if (func === "content") { + varLast = selected[selected.length - 1].textContent; + } + + if (func === "attr") { + varLast = selected[selected.length - 1].getAttribute(value) || ""; + } + + + /* 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 = csstree.generate(rule.ruleNode.prelude); + + let first = funcNode.children.first(); + let func = first.name; + + let value = csstree.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 = csstree.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 csstree.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(/::?/g); + 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 page = pages[i]; + let styles = window.getComputedStyle(page); + 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 (page.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); + } + } + + // force redraw + let el = document.querySelector(`[data-${target.variable}="${selector}"]`); + if (el) { + el.style.display = "none"; + el.clientHeight; + el.style.removeProperty("display"); + } + } + }); + }); + } + } + + // 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 = csstree.generate(rule.ruleNode.prelude); + let first = funcNode.children.first(); + let last = funcNode.children.last(); + let func = first.name; + + let value = csstree.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 csstree.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
elements. + // + // pre-wrap + // Sequences of white space are preserved. Lines are broken at newline characters, at
, and as necessary to fill line boxes. + // + // pre-line + // Sequences of white space are collapsed. Lines are broken at newline characters, at
, 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 = {}; + + /** + * 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 + */ + + (function (exports) { + // 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; + } + }; + } (clearCut)); + + 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 = csstree.generate(rule.ruleNode.prelude); + let value = declaration.value.children.first().name; + + selector.split(",").forEach((s) => { + this.displayRules[s] = { + value: value, + selector: s, + specificity: clearCut.calculateSpecificity(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 isImplemented$2; + var hasRequiredIsImplemented; + + function requireIsImplemented () { + if (hasRequiredIsImplemented) return isImplemented$2; + hasRequiredIsImplemented = 1; + + var validTypes = { object: true, symbol: true }; + + isImplemented$2 = 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; + }; + return isImplemented$2; + } + + var isSymbol; + var hasRequiredIsSymbol; + + function requireIsSymbol () { + if (hasRequiredIsSymbol) return isSymbol; + hasRequiredIsSymbol = 1; + + 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'); + }; + return isSymbol; + } + + var validateSymbol; + var hasRequiredValidateSymbol; + + function requireValidateSymbol () { + if (hasRequiredValidateSymbol) return validateSymbol; + hasRequiredValidateSymbol = 1; + + var isSymbol = requireIsSymbol(); + + validateSymbol = function (value) { + if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); + return value; + }; + return validateSymbol; + } + + var polyfill; + var hasRequiredPolyfill; + + function requirePolyfill () { + if (hasRequiredPolyfill) return polyfill; + hasRequiredPolyfill = 1; + + var d = dExports + , validateSymbol = requireValidateSymbol() + + , create = Object.create, defineProperties = Object.defineProperties + , defineProperty = Object.defineProperty, objPrototype = Object.prototype + , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create(null) + , isNativeSafe; + + if (typeof Symbol === 'function') { + NativeSymbol = Symbol; + try { + String(NativeSymbol()); + isNativeSafe = true; + } catch (ignore) {} + } + + var generateName = (function () { + var created = create(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.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(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) + 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(HiddenSymbol.prototype); + description = (description === undefined ? '' : String(description)); + return defineProperties(symbol, { + __description__: d('', description), + __name__: d('', generateName(description)) + }); + }; + defineProperties(SymbolPolyfill, { + for: d(function (key) { + if (globalSymbols[key]) return globalSymbols[key]; + return (globalSymbols[key] = SymbolPolyfill(String(key))); + }), + keyFor: d(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('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), + isConcatSpreadable: d('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || + SymbolPolyfill('isConcatSpreadable')), + iterator: d('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), + match: d('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), + replace: d('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), + search: d('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), + species: d('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), + split: d('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), + toPrimitive: d('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), + toStringTag: d('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), + unscopables: d('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) + }); + + // Internal tweaks for real symbol producer + defineProperties(HiddenSymbol.prototype, { + constructor: d(SymbolPolyfill), + toString: d('', 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(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), + valueOf: d(function () { return validateSymbol(this); }) + }); + defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d('', function () { + var symbol = validateSymbol(this); + if (typeof symbol === 'symbol') return symbol; + return symbol.toString(); + })); + defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d('c', 'Symbol')); + + // Proper implementaton of toPrimitive and toStringTag for returned symbol instances + defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, + d('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('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])); + return polyfill; + } + + var es6Symbol; + var hasRequiredEs6Symbol; + + function requireEs6Symbol () { + if (hasRequiredEs6Symbol) return es6Symbol; + hasRequiredEs6Symbol = 1; + + es6Symbol = requireIsImplemented()() ? Symbol : requirePolyfill(); + return es6Symbol; + } + + var isArguments; + var hasRequiredIsArguments; + + function requireIsArguments () { + if (hasRequiredIsArguments) return isArguments; + hasRequiredIsArguments = 1; + + var objToString = Object.prototype.toString + , id = objToString.call( + (function () { + return arguments; + })() + ); + + isArguments = function (value) { + return objToString.call(value) === id; + }; + return isArguments; + } + + var isFunction; + var hasRequiredIsFunction; + + function requireIsFunction () { + if (hasRequiredIsFunction) return isFunction; + hasRequiredIsFunction = 1; + + var objToString = Object.prototype.toString, id = objToString.call(noop$4); + + isFunction = function (value) { + return typeof value === "function" && objToString.call(value) === id; + }; + return isFunction; + } + + var isImplemented$1 = function () { + var sign = Math.sign; + if (typeof sign !== "function") return false; + return (sign(10) === 1) && (sign(-20) === -1); + }; + + var shim$2; + var hasRequiredShim$2; + + function requireShim$2 () { + if (hasRequiredShim$2) return shim$2; + hasRequiredShim$2 = 1; + + shim$2 = function (value) { + value = Number(value); + if (isNaN(value) || (value === 0)) return value; + return value > 0 ? 1 : -1; + }; + return shim$2; + } + + var sign$1 = isImplemented$1() + ? Math.sign + : requireShim$2(); + + var sign = sign$1 + + , abs$1 = Math.abs, floor$1 = Math.floor; + + var toInteger$1 = function (value) { + if (isNaN(value)) return 0; + value = Number(value); + if ((value === 0) || !isFinite(value)) return value; + return sign(value) * floor$1(abs$1(value)); + }; + + var toInteger = toInteger$1 + + , max = Math.max; + + var toPosInteger = function (value) { + return max(0, toInteger(value)); + }; + + var isString; + var hasRequiredIsString; + + function requireIsString () { + if (hasRequiredIsString) return isString; + hasRequiredIsString = 1; + + var objToString = Object.prototype.toString, id = objToString.call(""); + + isString = function (value) { + return ( + typeof value === "string" || + (value && + typeof value === "object" && + (value instanceof String || objToString.call(value) === id)) || + false + ); + }; + return isString; + } + + var shim$1; + var hasRequiredShim$1; + + function requireShim$1 () { + if (hasRequiredShim$1) return shim$1; + hasRequiredShim$1 = 1; + + var iteratorSymbol = requireEs6Symbol().iterator + , isArguments = requireIsArguments() + , isFunction = requireIsFunction() + , toPosInt = toPosInteger + , callable = validCallable + , validValue$1 = validValue + , isValue = isValue$3 + , isString = requireIsString() + , isArray = Array.isArray + , call = Function.prototype.call + , desc = { configurable: true, enumerable: true, writable: true, value: null } + , defineProperty = Object.defineProperty; + + // eslint-disable-next-line complexity + shim$1 = function (arrayLike /*, mapFn, thisArg*/) { + var mapFn = arguments[1] + , thisArg = arguments[2] + , Context + , i + , j + , arr + , length + , code + , iterator + , result + , getIterator + , value; + + arrayLike = Object(validValue$1(arrayLike)); + + if (isValue(mapFn)) callable(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 = callable(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(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(arr, j, desc); + } else { + arr[j] = value; + } + ++j; + } + length = j; + } + } + if (length === undefined) { + // Source: array or array-like + length = toPosInt(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(arr, i, desc); + } else { + arr[i] = value; + } + } + } + if (Context) { + desc.value = null; + arr.length = length; + } + return arr; + }; + return shim$1; + } + + var from = isImplemented$3() + ? Array.from + : requireShim$1(); + + var isImplemented = function () { + var numberIsNaN = Number.isNaN; + if (typeof numberIsNaN !== "function") return false; + return !numberIsNaN({}) && numberIsNaN(NaN) && !numberIsNaN(34); + }; + + var shim; + var hasRequiredShim; + + function requireShim () { + if (hasRequiredShim) return shim; + hasRequiredShim = 1; + + shim = function (value) { + // eslint-disable-next-line no-self-compare + return value !== value; + }; + return shim; + } + + var isNan = isImplemented() + ? Number.isNaN + : requireShim(); + + var numberIsNaN = isNan + , toPosInt = toPosInteger + , value$1 = validValue + , indexOf$1 = Array.prototype.indexOf + , objHasOwnProperty = Object.prototype.hasOwnProperty + , abs = Math.abs + , floor = Math.floor; + + var eIndexOf = function (searchElement /*, fromIndex*/) { + var i, length, fromIndex, val; + if (!numberIsNaN(searchElement)) return indexOf$1.apply(this, arguments); + + length = toPosInt(value$1(this).length); + fromIndex = arguments[1]; + if (isNaN(fromIndex)) fromIndex = 0; + else if (fromIndex >= 0) fromIndex = floor(fromIndex); + else fromIndex = toPosInt(this.length) - floor(abs(fromIndex)); + + for (i = fromIndex; i < length; ++i) { + if (objHasOwnProperty.call(this, i)) { + val = this[i]; + if (numberIsNaN(val)) return i; // Jslint: ignore + } + } + return -1; + }; + + var indexOf = eIndexOf + , forEach = Array.prototype.forEach + , splice = Array.prototype.splice; + + // eslint-disable-next-line no-unused-vars + var remove$1 = function (itemToRemove /*, …item*/) { + forEach.call( + arguments, + function (item) { + var index = indexOf.call(this, item); + if (index !== -1) splice.call(this, index, 1); + }, + this + ); + }; + + var isValue = isValue$3; + + var map = { function: true, object: true }; + + var isObject$1 = function (value) { + return (isValue(value) && map[typeof value]) || false; + }; + + var isObject = isObject$1; + + var validObject = function (value) { + if (!isObject(value)) throw new TypeError(value + " is not an Object"); + return value; + }; + + var aFrom = from + , remove = remove$1 + , value = validObject + , d = dExports + , emit = eventEmitterExports.methods.emit + + , defineProperty = Object.defineProperty + , hasOwnProperty$1 = Object.prototype.hasOwnProperty + , getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + + var pipe = function (e1, e2/*, name*/) { + var pipes, pipe, desc, name; + + (value(e1) && value(e2)); + name = arguments[2]; + if (name === undefined) name = 'emit'; + + pipe = { + close: function () { remove.call(pipes, e2); } + }; + if (hasOwnProperty$1.call(e1, '__eePipes__')) { + (pipes = e1.__eePipes__).push(e2); + return pipe; + } + defineProperty(e1, '__eePipes__', d('c', pipes = [e2])); + desc = getOwnPropertyDescriptor(e1, name); + if (!desc) { + desc = d('c', undefined); + } else { + delete desc.get; + delete desc.set; + } + desc.value = function () { + var i, emitter, data = aFrom(pipes); + emit.apply(this, arguments); + for (i = 0; (emitter = data[i]); ++i) emit.apply(emitter, arguments); + }; + defineProperty(e1, name, desc); + return pipe; + }; + + var pipe$1 = /*@__PURE__*/getDefaultExportFromCjs(pipe); + + let registeredHandlers = [...pagedMediaHandlers, ...generatedContentHandlers, ...filters]; + + class Handlers { + constructor(chunker, polisher, caller) { + + registeredHandlers.forEach((Handler) => { + let handler = new Handler(chunker, polisher, caller); + pipe$1(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 + const stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']:not([data-pagedjs-ignore], [media~='screen'])")); + // Get inline styles + const inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles], [data-pagedjs-ignore], [media~='screen'])")); + const elements = [...stylesheets, ...inlineStyles]; + return elements + // preserve order + .sort(function (element1, element2) { + const position = element1.compareDocumentPosition(element2); + if (position === Node.DOCUMENT_POSITION_PRECEDING) { + return 1; + } else if (position === Node.DOCUMENT_POSITION_FOLLOWING) { + return -1; + } + return 0; + }) + // extract the href + .map((element) => { + if (element.nodeName === "STYLE") { + const obj = {}; + obj[window.location.href] = element.textContent; + element.remove(); + return obj; + } + if (element.nodeName === "LINK") { + element.remove(); + return element.href; + } + // ignore + console.warn(`Unable to process: ${element}, ignoring.`); + }); + } + + 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, + Handler: Handler, + Polisher: Polisher, + Previewer: Previewer, + initializeHandlers: initializeHandlers, + registerHandlers: registerHandlers, + registeredHandlers: registeredHandlers + }); + + 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; + +})); diff --git a/assets/template.html b/assets/template.html index ebd7fd2..381e27c 100644 --- a/assets/template.html +++ b/assets/template.html @@ -4,7 +4,7 @@ $title$ - + diff --git a/images/design-to-pack.jpg b/images/design-to-pack.jpg new file mode 100644 index 0000000..ea1c88c Binary files /dev/null and b/images/design-to-pack.jpg differ diff --git a/images/design-to-pack.png b/images/design-to-pack.png deleted file mode 100644 index d1ebc0a..0000000 Binary files a/images/design-to-pack.png and /dev/null differ diff --git a/images/resin.png b/images/resin.png index 33cb959..e440e9a 100644 Binary files a/images/resin.png and b/images/resin.png differ diff --git a/images/studio-variable_Adrien_small.png b/images/studio-variable_Adrien_small.png new file mode 100644 index 0000000..8c4a2bd Binary files /dev/null and b/images/studio-variable_Adrien_small.png differ diff --git a/images/studio-variable_Julie_small.png b/images/studio-variable_Julie_small.png new file mode 100644 index 0000000..e0b76b9 Binary files /dev/null and b/images/studio-variable_Julie_small.png differ diff --git a/index.html b/index.html index f9cd41a..8d29f1c 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Studio Variable - + @@ -16,9 +16,9 @@
@@ -27,7 +27,7 @@
-

Studio Variable – Proposition Direction 6ème

+

Studio Variable – Proposition Direction 6ème!

@@ -52,7 +52,7 @@

Équipe

- . + .

Julie Blanc

@@ -66,7 +66,7 @@
- . + .

Adrien Payet

@@ -362,7 +362,7 @@ de parfum. L’interface permet de collaborer du brief aux produits finis, en passant par les vues 3D interactives.

- . + .
diff --git a/src/equipe.md b/src/equipe.md index d81eee4..f94801f 100644 --- a/src/equipe.md +++ b/src/equipe.md @@ -2,7 +2,7 @@
-![.](images/studio-variable_Julie.jpg) +![.](images/studio-variable_Julie_small.png) # Julie Blanc @@ -14,7 +14,7 @@ Julie est designer, développeuse et chercheuse. Elle a co-fondé le studio Vari
-![.](images/studio-variable_Adrien.jpg) +![.](images/studio-variable_Adrien_small.png) # Adrien Payet diff --git a/src/meta.yaml b/src/meta.yaml index c1b442a..427d6ee 100644 --- a/src/meta.yaml +++ b/src/meta.yaml @@ -1,8 +1,8 @@ --- title: "Studio Variable" baseline: "Design × code" -client: "Proposition Direction 6ème" +client: "Proposition Direction 6ème!" date: "29 décembre 2025" -contact: "contact@studio-varible.com" -footer: "Studio Variable – Proposition Direction 6ème" +contact: "contact@studio-variable.com" +footer: "Studio Variable – Proposition Direction 6ème!" --- \ No newline at end of file diff --git a/src/portfolio-1img/design-to-pack.md b/src/portfolio-1img/design-to-pack.md index de60e66..075d943 100644 --- a/src/portfolio-1img/design-to-pack.md +++ b/src/portfolio-1img/design-to-pack.md @@ -2,7 +2,7 @@ Plateforme complète de gestion de projets de création de flacons de parfum. L'interface permet de collaborer du brief aux produits finis, en passant par les vues 3D interactives. -![.](images/design-to-pack.png) +![.](images/design-to-pack.jpg)