From 87b7bb0470acd5975760bc35efe4f5ffaa33fca1 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 6 Sep 2016 15:35:50 +0200 Subject: [PATCH 001/162] Add plugin file. --- plugins/inlineStyles.js | 244 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 plugins/inlineStyles.js diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js new file mode 100644 index 000000000..e39462267 --- /dev/null +++ b/plugins/inlineStyles.js @@ -0,0 +1,244 @@ +'use strict'; + +exports.type = 'full'; + +exports.active = true; + +exports.params = { + juice: {} +}; + +exports.description = 'moves styles from + + + +@@@ + + + + + + From 8ef17ee4d6c6501ddeea93fe57dc39c703aa2d21 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 6 Sep 2016 16:45:42 +0200 Subject: [PATCH 008/162] Fix css rule match logic. --- plugins/inlineStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index e36af5009..51a3a0dc2 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -225,7 +225,7 @@ exports.fn = function(data, svgoOptions) { cssRule.selectors.forEach(function(selector, selectorIndex) { var $matches = $i(selector); - if($matches.length > 1) { // if matches more than once + if($matches.length <= 1) { // if matches only once or not at all cssRule.selectors.splice(selectorIndex, 1); } }); From 5bfd49821b03271a0fa2a4cc9f49a44c1ea35e47 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 6 Sep 2016 16:46:48 +0200 Subject: [PATCH 009/162] Add second test for removing classes that only match once or not at all. --- test/plugins/inlineStyles.02.svg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/plugins/inlineStyles.02.svg diff --git a/test/plugins/inlineStyles.02.svg b/test/plugins/inlineStyles.02.svg new file mode 100644 index 000000000..d69cd6ab2 --- /dev/null +++ b/test/plugins/inlineStyles.02.svg @@ -0,0 +1,17 @@ + + + + + +@@@ + + + + + From 3615c0e76cea49c2dd1186b22249b20d62cdf6bc Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 7 Sep 2016 00:42:02 +0200 Subject: [PATCH 010/162] Migrate to csso instead css parser. --- package.json | 3 +-- plugins/inlineStyles.js | 47 +++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 594b99d72..f711c2ce3 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,7 @@ "cheerio": "^0.22.0", "coa": "~1.0.1", "colors": "~1.1.2", - "css": "^2.2.1", - "csso": "~2.2.1", + "csso": "^2.2.1", "js-yaml": "~3.6.1", "juice": "^2.0.0", "mkdirp": "~0.5.1", diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 51a3a0dc2..9436e8e27 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -11,10 +11,10 @@ exports.params = { exports.description = 'moves styles from From 46aeebedd2cd5b5d5f8b8e4fd3da26392bac0dd3 Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 7 Sep 2016 00:43:29 +0200 Subject: [PATCH 012/162] Add further tests. --- test/plugins/inlineStyles.03.svg | 17 +++++++++++++++++ test/plugins/inlineStyles.04.svg | 15 +++++++++++++++ test/plugins/inlineStyles.05.svg | 21 +++++++++++++++++++++ test/plugins/inlineStyles.06.svg | 15 +++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 test/plugins/inlineStyles.03.svg create mode 100644 test/plugins/inlineStyles.04.svg create mode 100644 test/plugins/inlineStyles.05.svg create mode 100644 test/plugins/inlineStyles.06.svg diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg new file mode 100644 index 000000000..3d31ce343 --- /dev/null +++ b/test/plugins/inlineStyles.03.svg @@ -0,0 +1,17 @@ + + + + + +@@@ + + + + + + diff --git a/test/plugins/inlineStyles.04.svg b/test/plugins/inlineStyles.04.svg new file mode 100644 index 000000000..ae96176fc --- /dev/null +++ b/test/plugins/inlineStyles.04.svg @@ -0,0 +1,15 @@ + + + + + +@@@ + + + + + + diff --git a/test/plugins/inlineStyles.05.svg b/test/plugins/inlineStyles.05.svg new file mode 100644 index 000000000..fe8424438 --- /dev/null +++ b/test/plugins/inlineStyles.05.svg @@ -0,0 +1,21 @@ + + + + + + +@@@ + + + + + + + diff --git a/test/plugins/inlineStyles.06.svg b/test/plugins/inlineStyles.06.svg new file mode 100644 index 000000000..6b7ca40e0 --- /dev/null +++ b/test/plugins/inlineStyles.06.svg @@ -0,0 +1,15 @@ + + + + + +@@@ + + + + + + From f16abbfe407a072d92f10e10ff2f474d31d1461c Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 7 Sep 2016 00:54:14 +0200 Subject: [PATCH 013/162] Improve comment cosmetically. --- plugins/inlineStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 9436e8e27..f2d84c8f9 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -207,7 +207,7 @@ exports.fn = function(data, svgoOptions) { var $i = juice.juiceDocument($, svgoOptions); - // as last step, remove classes when they are used only by one element in document: + // as last step, remove classes when they are used only by one element in document var $styles = $('style'); $styles.each(function(si, $style) { if($style.children.length == 0) { From 814369dfcd7bf7d440cb7eaea9bb4157894f6970 Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 7 Sep 2016 00:54:43 +0200 Subject: [PATCH 014/162] Add code for removing style elements that now got empty content. --- plugins/inlineStyles.js | 17 +++++++++++++---- test/plugins/inlineStyles.04.svg | 2 -- test/plugins/inlineStyles.05.svg | 2 -- test/plugins/inlineStyles.06.svg | 2 -- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index f2d84c8f9..7d46c8648 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -225,22 +225,31 @@ exports.fn = function(data, svgoOptions) { var selectorStr = csso.translate(node); var $matches = $i(selectorStr); - if($matches.length == 1) { // if matches only once, remove it + if($matches.length == 1) { // if selector matches only once, remove the selector list.remove(item); anythingRemoved = true; } } - // clean up rulesets without selectors left + // clean up rulesets without any selectors left if(node.type === 'Ruleset' && node.selector.selectors.head == null) { list.remove(item); } }); - if(anythingRemoved) { - var newCssStr = csso.translate(cssAst); + if(!anythingRemoved) { + return; + } + + var newCssStr = csso.translate(cssAst).trim(); + if(newCssStr.length > 0) { $style.children[0].data = newCssStr; + } else { + // clean up style elements with now empty content + // note: style elements that already got empty content will + // intentionally not be removed by this plugin. + $styles.remove($style); } }); diff --git a/test/plugins/inlineStyles.04.svg b/test/plugins/inlineStyles.04.svg index ae96176fc..c94b37c1e 100644 --- a/test/plugins/inlineStyles.04.svg +++ b/test/plugins/inlineStyles.04.svg @@ -8,8 +8,6 @@ @@@ - diff --git a/test/plugins/inlineStyles.05.svg b/test/plugins/inlineStyles.05.svg index fe8424438..f1d0748cc 100644 --- a/test/plugins/inlineStyles.05.svg +++ b/test/plugins/inlineStyles.05.svg @@ -14,8 +14,6 @@ - diff --git a/test/plugins/inlineStyles.06.svg b/test/plugins/inlineStyles.06.svg index 6b7ca40e0..09cad3021 100644 --- a/test/plugins/inlineStyles.06.svg +++ b/test/plugins/inlineStyles.06.svg @@ -8,8 +8,6 @@ @@@ - From a3cec049e2baf82400c566f578a3df03cfa23d4f Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 7 Sep 2016 00:57:15 +0200 Subject: [PATCH 015/162] Move string trim() to condition in order to preserve subtleties in css output. --- plugins/inlineStyles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 7d46c8648..3e947f0d4 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -242,8 +242,8 @@ exports.fn = function(data, svgoOptions) { return; } - var newCssStr = csso.translate(cssAst).trim(); - if(newCssStr.length > 0) { + var newCssStr = csso.translate(cssAst); + if(newCssStr.trim().length > 0) { $style.children[0].data = newCssStr; } else { // clean up style elements with now empty content From 86cc4546e55333897edf257014785b8aa1f982e5 Mon Sep 17 00:00:00 2001 From: strarsis Date: Thu, 6 Oct 2016 20:50:06 +0200 Subject: [PATCH 016/162] Use juice options key. Add option for only once matching selectors. --- plugins/inlineStyles.js | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 3e947f0d4..843832aa7 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -5,7 +5,8 @@ exports.type = 'full'; exports.active = true; exports.params = { - juice: {} + juice: {}, + onlyOnceMatching: true }; exports.description = 'moves styles from - + diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg index 3d31ce343..31fb7b13c 100644 --- a/test/plugins/inlineStyles.03.svg +++ b/test/plugins/inlineStyles.03.svg @@ -1,7 +1,6 @@ @@ -10,8 +9,8 @@ - + diff --git a/test/plugins/inlineStyles.05.svg b/test/plugins/inlineStyles.05.svg index f1d0748cc..84c7bb4d9 100644 --- a/test/plugins/inlineStyles.05.svg +++ b/test/plugins/inlineStyles.05.svg @@ -14,6 +14,6 @@ - + diff --git a/test/plugins/inlineStyles.06.svg b/test/plugins/inlineStyles.06.svg index 09cad3021..65ff1a6a6 100644 --- a/test/plugins/inlineStyles.06.svg +++ b/test/plugins/inlineStyles.06.svg @@ -8,6 +8,6 @@ @@@ - + From a1f1e32e3873f6488bcfd8d4b1b261861c28fb3d Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 11 Oct 2016 00:57:33 +0200 Subject: [PATCH 022/162] Implement feature for skipping selectors that match more than once. Add further test. --- plugins/inlineStyles.js | 6 +++++- test/plugins/inlineStyles.07.svg | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/plugins/inlineStyles.07.svg diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index a4e39993d..4efc2a1ab 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -8,7 +8,7 @@ exports.params = { onlyMatchedOnce: true }; -exports.description = 'inline styles'; +exports.description = 'inline styles (optionally skip selectors that match more than once)'; var cheerioSupport = require('../lib/svgo/cheerio-support'), @@ -69,6 +69,10 @@ exports.fn = function(data, opts) { for(let selectorItem of selectorItemsSorted) { let $selectedEls = $(selectorItem.selectorStr); + if(opts.onlyMatchedOnce && $selectedEls.length > 1) { + // skip selectors that match more than once if option onlyMatchedOnce is turned on + continue; + } $selectedEls.each(function(i, el) { let $el = $(this); let elInlineCss = $el.css(); diff --git a/test/plugins/inlineStyles.07.svg b/test/plugins/inlineStyles.07.svg new file mode 100644 index 000000000..6bb4152f1 --- /dev/null +++ b/test/plugins/inlineStyles.07.svg @@ -0,0 +1,18 @@ + + + + + + +@@@ + + + + + + + From 30f01a234d244249ff03c2a5f5c40ad56c1fcb29 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 11 Oct 2016 01:00:22 +0200 Subject: [PATCH 023/162] Fix jshint errors. --- lib/svgo/cheerio-support.js | 350 ++++++++++++++++++------------------ plugins/inlineStyles.js | 6 +- 2 files changed, 179 insertions(+), 177 deletions(-) diff --git a/lib/svgo/cheerio-support.js b/lib/svgo/cheerio-support.js index f343a7efa..8d11f75d0 100644 --- a/lib/svgo/cheerio-support.js +++ b/lib/svgo/cheerio-support.js @@ -1,175 +1,177 @@ -var cheerio = require('cheerio'), - JSAPI = require('./jsAPI.js'); - -function monkeysSvgo(item, callFn, arg) { - item.content.forEach(function(childItem) { - if(callFn(item, childItem, arg) && !childItem.isEmpty()) { // recurse - monkeysSvgo(childItem, callFn, arg); - } - }); -} - -function isSvgoElem(elem) { - return typeof elem !== 'undefined'; -} - -function cheerioLoadXml(xml) { - return cheerio.load(xml, { xmlMode: true }); -} -function getXmlTag(elem) { - return '<' + elem + '>'; -} -function makeCheerioElem(elem) { - return cheerioLoadXml(getXmlTag(elem)); -} -function makeCheerioInst(elem) { - return makeCheerioElem(elem)(elem); -} - -function parsePrefixable(fullName) { - var a = fullName.split(':'); - if(a.length == 1) { - return { name: a[0] }; - } - return { prefix: a[0], name: a[1] }; -} - -function processSvgoElem(pae, ae, $) { - // note: element skipped by svgo parser - - if(pae.elem == '#document') { - pae.$ = $; // attach top cheerio ast node to top svgo ast node - } - - var textToElem = pae; - if(isSvgoElem(ae.elem)) { - var nameInfo = parsePrefixable(ae.elem); - - ae.$ = makeCheerioInst(nameInfo.name); - pae.$.append(ae.$); - - if(ae.attrs && Object.keys(ae.attrs).length > 0) { - for(var attrKey in ae.attrs) { - var attr = ae.attrs[attrKey]; - - var attrNamePrefixed = ''; - if(attr.prefix) { - attrNamePrefixed = attr.prefix + ':'; - } - attrNamePrefixed = attrNamePrefixed + attr.name; - - ae.$.attr(attrNamePrefixed, attr.value); - } - } - - if(nameInfo.prefix) { - ae.$.prefix = nameInfo.prefix; - } - - textToElem = ae; - } - - if(typeof ae.text !== 'undefined') { - textToElem.$.text(ae.text); - } - - return true; -} - -function createEmptyCheerioDoc() { - var document = makeCheerioElem('dummy'); - var $document = document.root().empty(); - return $document; -} - -function svgoAst2CheerioAst(data) { - var $document = createEmptyCheerioDoc(); - monkeysSvgo(data, processSvgoElem, $document); - var $documentProper = cheerioLoadXml($document.html()); // reload html in cheerio for proper cheerio instance - return $documentProper; -} - - -function monkeysCheerio($item, callFn, arg) { - if(typeof $item.children === 'object') { - for(var childItemIndex in $item.children) { - var $childItem = $item.children[ childItemIndex ]; - if(callFn($item, $childItem, arg) && $item.children.length > 0) { // recurse - monkeysCheerio($childItem, callFn, arg); - } - } - } else if(typeof $item.children === 'function') { - $item.children().each(function(childItemIndex, $childItem) { - if(callFn($item, $childItem, arg) && $item.children.length > 0) { // " - monkeysCheerio($childItem, callFn, arg); - } - }); - } else { - return; - } -} - -function isCheerioElem($elem) { - return typeof $elem !== 'undefined'; -} -function isCheerioText($elem) { - return $elem.type == 'text'; -} - -function makeSvgoElem(elem, parentElem) { - return new JSAPI({ elem: elem }, parentElem); -} -function makeSvgoText(text, parentElem) { - return new JSAPI({ text: text }, parentElem); -} - -function processCheerioElem($pae, $ae, s) { - - if($pae.name == 'root') { - $pae.s = s; // attach top svgo ast node to top cheerio ast node - } - - var $textToElem = $pae; - if(isCheerioElem($ae) && !isCheerioText($ae)) { - $ae.s = makeSvgoElem($ae.name, $pae.s); - - $pae.s.content = $pae.s.content || []; - $pae.s.content.push($ae.s); - - - if($ae.attribs && Object.keys($ae.attribs).length > 0) { - for(var attrName in $ae.attribs) { - var attrValue = $ae.attribs[attrName]; - var attrNameInfo = parsePrefixable(attrName); - $ae.s.addAttr({ - name: attrNameInfo.name, - prefix: attrNameInfo.prefix || '', // explicit empty string otherwise expected - local: attrNameInfo.name, - value: attrValue - }); - } - } - - $textToElem = $ae; - } - - - if(isCheerioText($ae)) { - $pae.s.content = $pae.s.content || []; - - $textToElem.s.content.push( makeSvgoText($ae.data, $pae.s) ); - } - - return true; -} - -function cheerioAst2SvgoAst($) { - var data = makeSvgoElem('#document'); - var $document = $.root()[0]; - monkeysCheerio($document, processCheerioElem, data); - return data; -} - - - module.exports.svgoAst2CheerioAst = svgoAst2CheerioAst; +'use strict'; + +var cheerio = require('cheerio'), + JSAPI = require('./jsAPI.js'); + +function monkeysSvgo(item, callFn, arg) { + item.content.forEach(function(childItem) { + if(callFn(item, childItem, arg) && !childItem.isEmpty()) { // recurse + monkeysSvgo(childItem, callFn, arg); + } + }); +} + +function isSvgoElem(elem) { + return typeof elem !== 'undefined'; +} + +function cheerioLoadXml(xml) { + return cheerio.load(xml, { xmlMode: true }); +} +function getXmlTag(elem) { + return '<' + elem + '>'; +} +function makeCheerioElem(elem) { + return cheerioLoadXml(getXmlTag(elem)); +} +function makeCheerioInst(elem) { + return makeCheerioElem(elem)(elem); +} + +function parsePrefixable(fullName) { + var a = fullName.split(':'); + if(a.length == 1) { + return { name: a[0] }; + } + return { prefix: a[0], name: a[1] }; +} + +function processSvgoElem(pae, ae, $) { + // note: element skipped by svgo parser + + if(pae.elem == '#document') { + pae.$ = $; // attach top cheerio ast node to top svgo ast node + } + + var textToElem = pae; + if(isSvgoElem(ae.elem)) { + var nameInfo = parsePrefixable(ae.elem); + + ae.$ = makeCheerioInst(nameInfo.name); + pae.$.append(ae.$); + + if(ae.attrs && Object.keys(ae.attrs).length > 0) { + for(var attrKey in ae.attrs) { + var attr = ae.attrs[attrKey]; + + var attrNamePrefixed = ''; + if(attr.prefix) { + attrNamePrefixed = attr.prefix + ':'; + } + attrNamePrefixed = attrNamePrefixed + attr.name; + + ae.$.attr(attrNamePrefixed, attr.value); + } + } + + if(nameInfo.prefix) { + ae.$.prefix = nameInfo.prefix; + } + + textToElem = ae; + } + + if(typeof ae.text !== 'undefined') { + textToElem.$.text(ae.text); + } + + return true; +} + +function createEmptyCheerioDoc() { + var document = makeCheerioElem('dummy'); + var $document = document.root().empty(); + return $document; +} + +function svgoAst2CheerioAst(data) { + var $document = createEmptyCheerioDoc(); + monkeysSvgo(data, processSvgoElem, $document); + var $documentProper = cheerioLoadXml($document.html()); // reload html in cheerio for proper cheerio instance + return $documentProper; +} + + +function monkeysCheerio($item, callFn, arg) { + if(typeof $item.children === 'object') { + for(var childItemIndex in $item.children) { + var $childItem = $item.children[ childItemIndex ]; + if(callFn($item, $childItem, arg) && $item.children.length > 0) { // recurse + monkeysCheerio($childItem, callFn, arg); + } + } + } else if(typeof $item.children === 'function') { + $item.children().each(function(childItemIndex, $childItem) { + if(callFn($item, $childItem, arg) && $item.children.length > 0) { // " + monkeysCheerio($childItem, callFn, arg); + } + }); + } else { + return; + } +} + +function isCheerioElem($elem) { + return typeof $elem !== 'undefined'; +} +function isCheerioText($elem) { + return $elem.type == 'text'; +} + +function makeSvgoElem(elem, parentElem) { + return new JSAPI({ elem: elem }, parentElem); +} +function makeSvgoText(text, parentElem) { + return new JSAPI({ text: text }, parentElem); +} + +function processCheerioElem($pae, $ae, s) { + + if($pae.name == 'root') { + $pae.s = s; // attach top svgo ast node to top cheerio ast node + } + + var $textToElem = $pae; + if(isCheerioElem($ae) && !isCheerioText($ae)) { + $ae.s = makeSvgoElem($ae.name, $pae.s); + + $pae.s.content = $pae.s.content || []; + $pae.s.content.push($ae.s); + + + if($ae.attribs && Object.keys($ae.attribs).length > 0) { + for(var attrName in $ae.attribs) { + var attrValue = $ae.attribs[attrName]; + var attrNameInfo = parsePrefixable(attrName); + $ae.s.addAttr({ + name: attrNameInfo.name, + prefix: attrNameInfo.prefix || '', // explicit empty string otherwise expected + local: attrNameInfo.name, + value: attrValue + }); + } + } + + $textToElem = $ae; + } + + + if(isCheerioText($ae)) { + $pae.s.content = $pae.s.content || []; + + $textToElem.s.content.push( makeSvgoText($ae.data, $pae.s) ); + } + + return true; +} + +function cheerioAst2SvgoAst($) { + var data = makeSvgoElem('#document'); + var $document = $.root()[0]; + monkeysCheerio($document, processCheerioElem, data); + return data; +} + + + module.exports.svgoAst2CheerioAst = svgoAst2CheerioAst; module.exports.cheerioAst2SvgoAst = cheerioAst2SvgoAst; \ No newline at end of file diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 4efc2a1ab..a92e9d4e1 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -48,7 +48,7 @@ exports.fn = function(data, opts) { cssAst: cssAst }); - csso.walk(cssAst, function(node, item, list) { + csso.walk(cssAst, function(node, item) { // single selector if(node.type === 'SimpleSelector') { let selectorStr = csso.translate(node); @@ -73,10 +73,10 @@ exports.fn = function(data, opts) { // skip selectors that match more than once if option onlyMatchedOnce is turned on continue; } - $selectedEls.each(function(i, el) { + $selectedEls.each(function() { let $el = $(this); let elInlineCss = $el.css(); - csso.walk(selectorItem.rulesetNode, function(node, item, list) { + csso.walk(selectorItem.rulesetNode, function(node) { if(node.type !== 'Declaration') { return; } From 91554efd70747b4cfbca141af88f87016263e908 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 11 Oct 2016 01:10:17 +0200 Subject: [PATCH 024/162] Fix jshint issue on node v0.12.x. Improve code cosmetically. --- plugins/inlineStyles.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index a92e9d4e1..aed1e1375 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -1,6 +1,6 @@ 'use strict'; -exports.type = 'full'; +exports.type = 'full'; exports.active = true; @@ -27,20 +27,20 @@ exports.fn = function(data, opts) { // svgo ast to cheerio ast var $ = cheerioSupport.svgoAst2CheerioAst(data); - var $styles = $('style'); - var styleItems = []; + var $styles = $('style'); + var styleItems = []; var selectorItems = []; $styles.each(function(si, $style) { if($style.children.length == 0) { return; } - let cssStr = $style.children[0].data; + var cssStr = $style.children[0].data; if(cssStr.length == 0) { return; } - let cssAst = csso.parse(cssStr, { + var cssAst = csso.parse(cssStr, { context: 'stylesheet' }); styleItems.push({ @@ -51,8 +51,8 @@ exports.fn = function(data, opts) { csso.walk(cssAst, function(node, item) { // single selector if(node.type === 'SimpleSelector') { - let selectorStr = csso.translate(node); - let selectorItem = { + var selectorStr = csso.translate(node); + var selectorItem = { selectorStr: selectorStr, simpleSelectorItem: item, rulesetNode: this.ruleset @@ -67,20 +67,20 @@ exports.fn = function(data, opts) { return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); }); - for(let selectorItem of selectorItemsSorted) { - let $selectedEls = $(selectorItem.selectorStr); + for(var selectorItem of selectorItemsSorted) { + var $selectedEls = $(selectorItem.selectorStr); if(opts.onlyMatchedOnce && $selectedEls.length > 1) { // skip selectors that match more than once if option onlyMatchedOnce is turned on continue; } $selectedEls.each(function() { - let $el = $(this); - let elInlineCss = $el.css(); + var $el = $(this); + var elInlineCss = $el.css(); csso.walk(selectorItem.rulesetNode, function(node) { if(node.type !== 'Declaration') { return; } - let propertyName = node.property.name, + var propertyName = node.property.name, propertyValue = csso.translate(node.value); $el.css(propertyName, propertyValue); }); @@ -94,8 +94,11 @@ exports.fn = function(data, opts) { } } + + var styleItem = {}; + // clean up rulesets without any selectors left - for(let styleItem of styleItems) { + for(styleItem of styleItems) { csso.walk(styleItem.cssAst, function(node, item, list) { // clean up rulesets without any selectors left if(node.type === 'Ruleset' && @@ -106,7 +109,7 @@ exports.fn = function(data, opts) { } // update the css selectors / blocks - for(let styleItem of styleItems) { + for(styleItem of styleItems) { // clean up now emtpy style elements if(styleItem.cssAst.rules.isEmpty()){ $styles.remove(styleItem.$style); @@ -115,6 +118,7 @@ exports.fn = function(data, opts) { styleItem.$style.children[0].data = csso.translate(styleItem.cssAst); } + // cheerio ast back to svgo ast var dataNew = cheerioSupport.cheerioAst2SvgoAst($); return dataNew; From e123e293ea966e339eda864eba6a5cbecb07881a Mon Sep 17 00:00:00 2001 From: strarsis Date: Thu, 13 Oct 2016 15:01:10 +0200 Subject: [PATCH 025/162] Improve comment. --- plugins/inlineStyles.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index aed1e1375..b7037f0af 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -100,7 +100,6 @@ exports.fn = function(data, opts) { // clean up rulesets without any selectors left for(styleItem of styleItems) { csso.walk(styleItem.cssAst, function(node, item, list) { - // clean up rulesets without any selectors left if(node.type === 'Ruleset' && node.selector.selectors.head == null) { list.remove(item); From ebcd712bb982801fe9d841241ae90bea6e120e1b Mon Sep 17 00:00:00 2001 From: strarsis Date: Thu, 13 Oct 2016 15:35:26 +0200 Subject: [PATCH 026/162] Add comments. --- lib/svgo/cheerio-support.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/svgo/cheerio-support.js b/lib/svgo/cheerio-support.js index 8d11f75d0..c693a101f 100644 --- a/lib/svgo/cheerio-support.js +++ b/lib/svgo/cheerio-support.js @@ -94,6 +94,7 @@ function svgoAst2CheerioAst(data) { function monkeysCheerio($item, callFn, arg) { if(typeof $item.children === 'object') { + // children object for(var childItemIndex in $item.children) { var $childItem = $item.children[ childItemIndex ]; if(callFn($item, $childItem, arg) && $item.children.length > 0) { // recurse @@ -101,6 +102,7 @@ function monkeysCheerio($item, callFn, arg) { } } } else if(typeof $item.children === 'function') { + // children() function $item.children().each(function(childItemIndex, $childItem) { if(callFn($item, $childItem, arg) && $item.children.length > 0) { // " monkeysCheerio($childItem, callFn, arg); From 6740ab00234cc25aa8b0f642fd0fddabd5335751 Mon Sep 17 00:00:00 2001 From: strarsis Date: Thu, 13 Oct 2016 16:01:15 +0200 Subject: [PATCH 027/162] Use for-in loops instead for-of loops for compatibility for node 0.10. --- plugins/inlineStyles.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index b7037f0af..162833014 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -67,7 +67,8 @@ exports.fn = function(data, opts) { return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); }); - for(var selectorItem of selectorItemsSorted) { + for(var selectorItemIndex in selectorItemsSorted) { + var selectorItem = selectorItemsSorted[selectorItemIndex]; var $selectedEls = $(selectorItem.selectorStr); if(opts.onlyMatchedOnce && $selectedEls.length > 1) { // skip selectors that match more than once if option onlyMatchedOnce is turned on @@ -95,10 +96,12 @@ exports.fn = function(data, opts) { } - var styleItem = {}; + var styleItemIndex = 0, + styleItem = {}; // clean up rulesets without any selectors left - for(styleItem of styleItems) { + for(styleItemIndex in styleItems) { + styleItem = styleItems[styleItemIndex]; csso.walk(styleItem.cssAst, function(node, item, list) { if(node.type === 'Ruleset' && node.selector.selectors.head == null) { @@ -108,7 +111,8 @@ exports.fn = function(data, opts) { } // update the css selectors / blocks - for(styleItem of styleItems) { + for(styleItemIndex in styleItems) { + styleItem = styleItems[styleItemIndex]; // clean up now emtpy style elements if(styleItem.cssAst.rules.isEmpty()){ $styles.remove(styleItem.$style); From 150868db004659e3de016e42b6613eb5c563d669 Mon Sep 17 00:00:00 2001 From: strarsis Date: Fri, 18 Nov 2016 17:17:48 +0100 Subject: [PATCH 028/162] Replace juice with css-select. --- lib/ext/add-parent-refs.js | 22 ++++ lib/ext/domutils-svgo.js | 108 +++++++++++++++++++ lib/svgo/cheerio-support.js | 179 ------------------------------- package.json | 3 +- plugins/inlineStyles.js | 131 ++++++++++++---------- test/plugins/inlineStyles.02.svg | 2 +- test/plugins/inlineStyles.03.svg | 2 +- test/plugins/inlineStyles.04.svg | 4 +- test/plugins/inlineStyles.05.svg | 2 +- test/plugins/inlineStyles.06.svg | 2 +- test/plugins/inlineStyles.07.svg | 2 +- 11 files changed, 214 insertions(+), 243 deletions(-) create mode 100644 lib/ext/add-parent-refs.js create mode 100644 lib/ext/domutils-svgo.js delete mode 100644 lib/svgo/cheerio-support.js diff --git a/lib/ext/add-parent-refs.js b/lib/ext/add-parent-refs.js new file mode 100644 index 000000000..9e5be1073 --- /dev/null +++ b/lib/ext/add-parent-refs.js @@ -0,0 +1,22 @@ +'use strict'; + +// Adds parent reference to each item +// (except the topmost root item which got no parent). + +var addParentRefs = function(data) { + if(!data.content) { + return; + } + var i = 0, + length = data.content.length, + item; + while(i < length) { + item = data.content[i]; + item.parent = data; + addParentRefs(item); + i++; + } + return data; +}; + +module.exports = addParentRefs; diff --git a/lib/ext/domutils-svgo.js b/lib/ext/domutils-svgo.js new file mode 100644 index 000000000..7224255b3 --- /dev/null +++ b/lib/ext/domutils-svgo.js @@ -0,0 +1,108 @@ +'use strict'; + +// DOMUtils API for SVGO AST (used by css-select) + +var domUtilsSvgo = {}; + +domUtilsSvgo.isTag = function(node) { + return node.elem; +}; + +domUtilsSvgo.getParent = function(node) { + return node.parent || null; // root item my be passed which got no parent +}; + +domUtilsSvgo.getChildren = function(node) { + var childNodes = []; + node.content.forEach(function(childNode) { + childNodes.push(childNode); + }); + return childNodes; +}; + +domUtilsSvgo.getSiblings = function(node) { + var parent = domUtilsSvgo.getParent(node); + return domUtilsSvgo.getChildren(parent); +}; + +domUtilsSvgo.getName = function(node) { + return node.elem; +}; + +domUtilsSvgo.getText = function(node) { + var nodeText = node.content[0].text || node.content[0].cdata || [], + DATA = nodeText.indexOf('>') >= 0 || nodeText.indexOf('<') >= 0 ? 'cdata' : 'text'; + return DATA; +}; + +domUtilsSvgo.hasAttrib = function(node, name) { + return node.hasAttr(name); +}; + +domUtilsSvgo.findAll = function(test, nodes) { + var result = []; + for(var i = 0, j = nodes.length; i < j; i++){ + if(!domUtilsSvgo.isTag(nodes[i])) continue; + if(test(nodes[i])) result.push(nodes[i]); // TODO! + + if(nodes[i].content && nodes[i].content.length > 0){ + result = result.concat(domUtilsSvgo.findAll(test, nodes[i].content)); + } + } + return result; +}; + +domUtilsSvgo.findOne = function(test, nodes) { + var node = null; + + for(var i = 0, l = nodes.length; i < l && !node; i++){ + if(!domUtilsSvgo.isTag(nodes[i])){ + continue; + } else if(test(nodes[i])){ + node = nodes[i]; + } else if(nodes[i].content && nodes[i].content.length > 0){ + node = domUtilsSvgo.findOne(test, nodes[i].content); + } + } + + return node; +}; + +// Given an array of nodes, remove any member that is contained by another. +domUtilsSvgo.removeSubsets = function(nodes) { + var idx = nodes.length, node, ancestor, replace; + + // Check if each node (or one of its ancestors) is already contained in the + // array. + while (--idx > -1) { + node = ancestor = nodes[idx]; + + // Temporarily remove the node under consideration + nodes[idx] = null; + replace = true; + + while (ancestor) { + if (nodes.indexOf(ancestor) > -1) { + replace = false; + nodes.splice(idx, 1); + break; + } + ancestor = domUtilsSvgo.getParent(ancestor); + } + + // If the node has been found to be unique, re-insert it. + if (replace) { + nodes[idx] = node; + } + } + + return nodes; +}; + +domUtilsSvgo.getAttributeValue = function(elem, name) { + var attr = elem.attr(name); + return attr && attr.value; +}; + + +module.exports = domUtilsSvgo; diff --git a/lib/svgo/cheerio-support.js b/lib/svgo/cheerio-support.js deleted file mode 100644 index c693a101f..000000000 --- a/lib/svgo/cheerio-support.js +++ /dev/null @@ -1,179 +0,0 @@ -'use strict'; - -var cheerio = require('cheerio'), - JSAPI = require('./jsAPI.js'); - -function monkeysSvgo(item, callFn, arg) { - item.content.forEach(function(childItem) { - if(callFn(item, childItem, arg) && !childItem.isEmpty()) { // recurse - monkeysSvgo(childItem, callFn, arg); - } - }); -} - -function isSvgoElem(elem) { - return typeof elem !== 'undefined'; -} - -function cheerioLoadXml(xml) { - return cheerio.load(xml, { xmlMode: true }); -} -function getXmlTag(elem) { - return '<' + elem + '>'; -} -function makeCheerioElem(elem) { - return cheerioLoadXml(getXmlTag(elem)); -} -function makeCheerioInst(elem) { - return makeCheerioElem(elem)(elem); -} - -function parsePrefixable(fullName) { - var a = fullName.split(':'); - if(a.length == 1) { - return { name: a[0] }; - } - return { prefix: a[0], name: a[1] }; -} - -function processSvgoElem(pae, ae, $) { - // note: element skipped by svgo parser - - if(pae.elem == '#document') { - pae.$ = $; // attach top cheerio ast node to top svgo ast node - } - - var textToElem = pae; - if(isSvgoElem(ae.elem)) { - var nameInfo = parsePrefixable(ae.elem); - - ae.$ = makeCheerioInst(nameInfo.name); - pae.$.append(ae.$); - - if(ae.attrs && Object.keys(ae.attrs).length > 0) { - for(var attrKey in ae.attrs) { - var attr = ae.attrs[attrKey]; - - var attrNamePrefixed = ''; - if(attr.prefix) { - attrNamePrefixed = attr.prefix + ':'; - } - attrNamePrefixed = attrNamePrefixed + attr.name; - - ae.$.attr(attrNamePrefixed, attr.value); - } - } - - if(nameInfo.prefix) { - ae.$.prefix = nameInfo.prefix; - } - - textToElem = ae; - } - - if(typeof ae.text !== 'undefined') { - textToElem.$.text(ae.text); - } - - return true; -} - -function createEmptyCheerioDoc() { - var document = makeCheerioElem('dummy'); - var $document = document.root().empty(); - return $document; -} - -function svgoAst2CheerioAst(data) { - var $document = createEmptyCheerioDoc(); - monkeysSvgo(data, processSvgoElem, $document); - var $documentProper = cheerioLoadXml($document.html()); // reload html in cheerio for proper cheerio instance - return $documentProper; -} - - -function monkeysCheerio($item, callFn, arg) { - if(typeof $item.children === 'object') { - // children object - for(var childItemIndex in $item.children) { - var $childItem = $item.children[ childItemIndex ]; - if(callFn($item, $childItem, arg) && $item.children.length > 0) { // recurse - monkeysCheerio($childItem, callFn, arg); - } - } - } else if(typeof $item.children === 'function') { - // children() function - $item.children().each(function(childItemIndex, $childItem) { - if(callFn($item, $childItem, arg) && $item.children.length > 0) { // " - monkeysCheerio($childItem, callFn, arg); - } - }); - } else { - return; - } -} - -function isCheerioElem($elem) { - return typeof $elem !== 'undefined'; -} -function isCheerioText($elem) { - return $elem.type == 'text'; -} - -function makeSvgoElem(elem, parentElem) { - return new JSAPI({ elem: elem }, parentElem); -} -function makeSvgoText(text, parentElem) { - return new JSAPI({ text: text }, parentElem); -} - -function processCheerioElem($pae, $ae, s) { - - if($pae.name == 'root') { - $pae.s = s; // attach top svgo ast node to top cheerio ast node - } - - var $textToElem = $pae; - if(isCheerioElem($ae) && !isCheerioText($ae)) { - $ae.s = makeSvgoElem($ae.name, $pae.s); - - $pae.s.content = $pae.s.content || []; - $pae.s.content.push($ae.s); - - - if($ae.attribs && Object.keys($ae.attribs).length > 0) { - for(var attrName in $ae.attribs) { - var attrValue = $ae.attribs[attrName]; - var attrNameInfo = parsePrefixable(attrName); - $ae.s.addAttr({ - name: attrNameInfo.name, - prefix: attrNameInfo.prefix || '', // explicit empty string otherwise expected - local: attrNameInfo.name, - value: attrValue - }); - } - } - - $textToElem = $ae; - } - - - if(isCheerioText($ae)) { - $pae.s.content = $pae.s.content || []; - - $textToElem.s.content.push( makeSvgoText($ae.data, $pae.s) ); - } - - return true; -} - -function cheerioAst2SvgoAst($) { - var data = makeSvgoElem('#document'); - var $document = $.root()[0]; - monkeysCheerio($document, processCheerioElem, data); - return data; -} - - - module.exports.svgoAst2CheerioAst = svgoAst2CheerioAst; - module.exports.cheerioAst2SvgoAst = cheerioAst2SvgoAst; \ No newline at end of file diff --git a/package.json b/package.json index ae6938752..1c839b6f2 100644 --- a/package.json +++ b/package.json @@ -48,12 +48,13 @@ "jshint": "jshint --show-non-errors ." }, "dependencies": { - "cheerio": "^0.22.0", "coa": "~1.0.1", "colors": "~1.1.2", + "css-select": "^1.2.0", "csso": "^2.2.1", "js-yaml": "~3.6.1", "mkdirp": "~0.5.1", + "mock-require": "^2.0.0", "sax": "~1.2.1", "specificity": "^0.3.0", "stable": "^0.1.5", diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 162833014..b35bfe817 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -5,52 +5,57 @@ exports.type = 'full'; exports.active = true; exports.params = { - onlyMatchedOnce: true + onlyMatchedOnce: true, + removeMatchedSelectors: true }; exports.description = 'inline styles (optionally skip selectors that match more than once)'; -var cheerioSupport = require('../lib/svgo/cheerio-support'), - SPECIFICITY = require('specificity'), - stable = require('stable'), - csso = require('csso'); +var SPECIFICITY = require('specificity'), + stable = require('stable'), + csso = require('csso'), + mock = require('mock-require'), + domutilsSvgo = require('../lib/ext/domutils-svgo'), + addParentRefs = require('../lib/ext/add-parent-refs'); + mock('domutils', domutilsSvgo); +var cssSelect = require('css-select'); /** - * Moves styles from - + diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg index 31fb7b13c..8893eec7f 100644 --- a/test/plugins/inlineStyles.03.svg +++ b/test/plugins/inlineStyles.03.svg @@ -11,6 +11,6 @@ - + diff --git a/test/plugins/inlineStyles.04.svg b/test/plugins/inlineStyles.04.svg index c94b37c1e..361a56b08 100644 --- a/test/plugins/inlineStyles.04.svg +++ b/test/plugins/inlineStyles.04.svg @@ -1,6 +1,6 @@ @@ -8,6 +8,6 @@ @@@ - + diff --git a/test/plugins/inlineStyles.05.svg b/test/plugins/inlineStyles.05.svg index 84c7bb4d9..2ab36d77d 100644 --- a/test/plugins/inlineStyles.05.svg +++ b/test/plugins/inlineStyles.05.svg @@ -14,6 +14,6 @@ - + diff --git a/test/plugins/inlineStyles.06.svg b/test/plugins/inlineStyles.06.svg index 65ff1a6a6..1f3956b48 100644 --- a/test/plugins/inlineStyles.06.svg +++ b/test/plugins/inlineStyles.06.svg @@ -8,6 +8,6 @@ @@@ - + diff --git a/test/plugins/inlineStyles.07.svg b/test/plugins/inlineStyles.07.svg index 6bb4152f1..93868953d 100644 --- a/test/plugins/inlineStyles.07.svg +++ b/test/plugins/inlineStyles.07.svg @@ -12,7 +12,7 @@ - + From 193d93bfcda185692c924f114e14db5e556eebec Mon Sep 17 00:00:00 2001 From: strarsis Date: Fri, 18 Nov 2016 17:33:44 +0100 Subject: [PATCH 029/162] Adjust plugin to use new css-select adapter option, remove mocking. Add adapter/domutils API comments to svgo domutils adapter from updated css-select readme. Use css-select from github commit until it has been released to npm. --- lib/ext/domutils-svgo.js | 30 +++++++++++++++++++++++++++++- package.json | 3 +-- plugins/inlineStyles.js | 12 ++++++------ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/ext/domutils-svgo.js b/lib/ext/domutils-svgo.js index 7224255b3..993b49a79 100644 --- a/lib/ext/domutils-svgo.js +++ b/lib/ext/domutils-svgo.js @@ -4,14 +4,20 @@ var domUtilsSvgo = {}; +// is the node a tag? domUtilsSvgo.isTag = function(node) { return node.elem; }; +// does at least one of passed element nodes pass the test predicate? + + +// get the parent of the node domUtilsSvgo.getParent = function(node) { return node.parent || null; // root item my be passed which got no parent }; +// get the node's children domUtilsSvgo.getChildren = function(node) { var childNodes = []; node.content.forEach(function(childNode) { @@ -20,25 +26,35 @@ domUtilsSvgo.getChildren = function(node) { return childNodes; }; +/* + get the siblings of the node. Note that unlike jQuery's `siblings` method, + this is expected to include the current node as well + TODO/Clarify: Add current node on top to returned siblings list? +*/ domUtilsSvgo.getSiblings = function(node) { var parent = domUtilsSvgo.getParent(node); return domUtilsSvgo.getChildren(parent); }; +// get the name of the tag domUtilsSvgo.getName = function(node) { return node.elem; }; +// get the text content of the node, and its children if it has any domUtilsSvgo.getText = function(node) { var nodeText = node.content[0].text || node.content[0].cdata || [], DATA = nodeText.indexOf('>') >= 0 || nodeText.indexOf('<') >= 0 ? 'cdata' : 'text'; return DATA; }; +// does the element have the named attribute? domUtilsSvgo.hasAttrib = function(node, name) { return node.hasAttr(name); }; +// finds all of the element nodes in the array that match the test predicate, +// as well as any of their children that match it domUtilsSvgo.findAll = function(test, nodes) { var result = []; for(var i = 0, j = nodes.length; i < j; i++){ @@ -68,7 +84,8 @@ domUtilsSvgo.findOne = function(test, nodes) { return node; }; -// Given an array of nodes, remove any member that is contained by another. +// takes an array of nodes, and removes any duplicates, as well as any nodes +// whose ancestors are also in the array domUtilsSvgo.removeSubsets = function(nodes) { var idx = nodes.length, node, ancestor, replace; @@ -99,10 +116,21 @@ domUtilsSvgo.removeSubsets = function(nodes) { return nodes; }; +// get the attribute value domUtilsSvgo.getAttributeValue = function(elem, name) { var attr = elem.attr(name); return attr && attr.value; }; +/* + The adapter can also optionally include an equals method, if your DOM + structure needs a custom equality test to compare two objects which refer + to the same underlying node. If not provided, `css-select` will fall back to + `a === b`. +*/ +// equals: ( a:Node, b:Node ) => Boolean +// not needed for svgo AST + + module.exports = domUtilsSvgo; diff --git a/package.json b/package.json index 1c839b6f2..7d2dc8ec5 100644 --- a/package.json +++ b/package.json @@ -50,11 +50,10 @@ "dependencies": { "coa": "~1.0.1", "colors": "~1.1.2", - "css-select": "^1.2.0", + "css-select": "github:fb55/css-select#e109d4b3668354542c806a6b652410f135d679ae", "csso": "^2.2.1", "js-yaml": "~3.6.1", "mkdirp": "~0.5.1", - "mock-require": "^2.0.0", "sax": "~1.2.1", "specificity": "^0.3.0", "stable": "^0.1.5", diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index b35bfe817..50d86dcd0 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -16,11 +16,11 @@ var SPECIFICITY = require('specificity'), stable = require('stable'), csso = require('csso'), - mock = require('mock-require'), domutilsSvgo = require('../lib/ext/domutils-svgo'), - addParentRefs = require('../lib/ext/add-parent-refs'); - mock('domutils', domutilsSvgo); -var cssSelect = require('css-select'); + addParentRefs = require('../lib/ext/add-parent-refs'), + cssSelect = require('css-select'); + +var cssSelectOpts = {xmlMode: true, adapter: domutilsSvgo}; /** * Moves + merges styles from style elements to element styles @@ -31,7 +31,7 @@ exports.fn = function(data, opts) { data = addParentRefs(data); // fetch + + + +@@@ + + + + From b3ddf64f5ff40b4b44c08fa8d798fa5fb776d82d Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 6 Dec 2016 23:19:08 +0100 Subject: [PATCH 056/162] Cosmetic code change. --- plugins/inlineStyles.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 046b9773c..ff6c6509f 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -81,11 +81,7 @@ exports.fn = function(data, opts) { // merge element(inline) styles + matching - @@@ - - + From 2ef6a978f817ce38d0c3b9ac7a8cda2290c3c4bc Mon Sep 17 00:00:00 2001 From: strarsis Date: Fri, 9 Dec 2016 17:18:06 +0100 Subject: [PATCH 061/162] Update css-select package dependency reference. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 12feae137..8094df6ec 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "dependencies": { "coa": "~1.0.1", "colors": "~1.1.2", - "css-select": "github:fb55/css-select#e109d4b3668354542c806a6b652410f135d679ae", + "css-select": "github:fb55/css-select#e02737b8fd5bf8271818cefe8b6dfe7de3584dbd", "css-select-base-adapter": "^0.1.0", "csso": "^2.2.1", "js-yaml": "~3.6.1", From f6e5f40452d04d5cb66357db355b4419d2042fad Mon Sep 17 00:00:00 2001 From: strarsis Date: Sun, 11 Dec 2016 21:26:21 +0100 Subject: [PATCH 062/162] Use native spliceContent method. --- plugins/inlineStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 9a032c395..d0fa1c160 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -160,7 +160,7 @@ exports.fn = function(data, opts) { if(styleItem.cssAst.rules.isEmpty()){ // clean up now emtpy - + @@@ - + From 001977378566bba15b887d023ca661babc414623 Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 02:38:34 +0100 Subject: [PATCH 065/162] Fix !important handling/sorting. Fix !important sorting related test. --- plugins/inlineStyles.js | 46 +++++++++++++++----------------- test/plugins/inlineStyles.04.svg | 2 +- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 224a41303..6404bbea6 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -47,8 +47,7 @@ exports.fn = function(data, opts) { }); // collect css selectors and their containing ruleset - var curSelectorItem = null, - curAtRuleExpNode = null; + var curAtRuleExpNode = null; csso.walk(cssAst, function(node, item) { // "look-behind the SimpleSelector", AtruleExpression node comes _before_ the affected SimpleSelector @@ -57,7 +56,6 @@ exports.fn = function(data, opts) { curAtRuleExpNode = node; } - // retains reference to the last SimpleSelector for "look-ahead" if(node.type === 'SimpleSelector') { // csso 'SimpleSelector' to be interpreted with CSS2.1 specs, _not_ with CSS3 Selector module specs: // Selector group ('Selector' in csso) consisting of simple selectors ('SimpleSelector' in csso), separated by comma. @@ -70,7 +68,7 @@ exports.fn = function(data, opts) { mqStr = csso.translate(curAtRuleExpNode); } - curSelectorItem = { + var curSelectorItem = { selectorStr: selectorStr, simpleSelectorItem: item, @@ -82,12 +80,6 @@ exports.fn = function(data, opts) { selectorItems.push(curSelectorItem); } - // "look-ahead the SimpleSelector", Value node comes _after_ the affected SimpleSelector - if(node.type === 'Value') { - // !important value? - curSelectorItem.important = node.important; - } - }); } @@ -101,16 +93,11 @@ exports.fn = function(data, opts) { var selectorItemsSorted = stable(selectorItemsMqs, function(item1, item2) { return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); }); - // and secondly by !important - var selectorItemsSortedImp = stable(selectorItemsSorted, function(item1, item2) { - var item1Score = ~~item1.important, // (cast boolean to number) - item2Score = ~~item2.important; // " - return (item1Score - item2Score); - }); // apply + + + + + +@@@ + + + + + \ No newline at end of file From e371ef3f9a049967d1db967b27d45ec8f6a48f9b Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 06:41:42 +0100 Subject: [PATCH 068/162] Fix jshint unused variable error. --- plugins/inlineStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 90db5747a..708e1bfd5 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -121,7 +121,7 @@ exports.fn = function(data, opts) { var newInlineCssAst = csso.parse('', {context: 'block'}); // for an empty css ast (in block context) var mergedDeclarations = []; - var _fetchDeclarations = function(node, item, list) { + var _fetchDeclarations = function(node, item) { if(node.type === 'Declaration') { mergedDeclarations.push(item); } From f222530befdfa0aa839efd73deb0a527c6ee7e4b Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 06:59:08 +0100 Subject: [PATCH 069/162] Add fix for leaking declaration references (csso.translate(...)). --- plugins/inlineStyles.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 708e1bfd5..ee5a74bbe 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -126,8 +126,10 @@ exports.fn = function(data, opts) { mergedDeclarations.push(item); } }; - csso.walk(selectorItem.rulesetNode, _fetchDeclarations); - csso.walk(inlineCssAst, _fetchDeclarations); + var itemRulesetNodeCloned = csso.clone(selectorItem.rulesetNode); + // clone to prevent leaking declaration references (csso.translate(...)) + csso.walk(itemRulesetNodeCloned, _fetchDeclarations); + csso.walk(inlineCssAst, _fetchDeclarations); // sort by !important(ce) var mergedDeclarationsSorted = stable(mergedDeclarations, function(declaration1, declaration2) { From a336b3c445cee08abc23bb4561aee2a15d349375 Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 17:37:01 +0100 Subject: [PATCH 070/162] Remove !important removal for inline styles (inline-relative specificity). --- plugins/inlineStyles.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index ee5a74bbe..9d42d6cc8 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -141,7 +141,6 @@ exports.fn = function(data, opts) { // to css for(var mergedDeclarationsSortedIndex in mergedDeclarationsSorted) { var declaration = mergedDeclarationsSorted[mergedDeclarationsSortedIndex]; - declaration.data.value.important = false; // !important is irrelevant in inline styles newInlineCssAst.declarations.insert(declaration); } var newCss = csso.translate(newInlineCssAst); From 82eab751fe06d0e98b353a07c0f476d47c78076b Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 17:39:58 +0100 Subject: [PATCH 071/162] Adjust test. --- test/plugins/inlineStyles.04.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plugins/inlineStyles.04.svg b/test/plugins/inlineStyles.04.svg index 185eb22ba..7e5e3ffdd 100644 --- a/test/plugins/inlineStyles.04.svg +++ b/test/plugins/inlineStyles.04.svg @@ -9,6 +9,6 @@ @@@ - + From 94d36fed1662ba0e308d68391ba05787954b5dd7 Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 12 Dec 2016 18:21:46 +0100 Subject: [PATCH 072/162] Use more systematic tests. Fix style ordering (found out by the new tests). --- plugins/inlineStyles.js | 11 +++++++---- test/plugins/inlineStyles.01.svg | 8 ++------ test/plugins/inlineStyles.02.svg | 9 +++------ test/plugins/inlineStyles.03.svg | 29 +++++++++++++++++------------ test/plugins/inlineStyles.04.svg | 7 +++---- test/plugins/inlineStyles.05.svg | 20 ++++++++++++-------- test/plugins/inlineStyles.06.svg | 16 +++++++++++++--- test/plugins/inlineStyles.07.svg | 17 +++++++++-------- test/plugins/inlineStyles.08.svg | 13 +++++++++---- test/plugins/inlineStyles.09.svg | 28 ++++++++++++---------------- 10 files changed, 87 insertions(+), 71 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 9d42d6cc8..3e3ce0780 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -50,12 +50,15 @@ exports.fn = function(data, opts) { var curAtRuleExpNode = null; csso.walk(cssAst, function(node, item) { + // media query blocks // "look-behind the SimpleSelector", AtruleExpression node comes _before_ the affected SimpleSelector - if(node.type === 'AtruleExpression') { - // media query expression - // Node: this.atruleExpression is not set (null) for SimpleSelectors + if(node.type === 'AtruleExpression') { // marks the beginning of an Atrule curAtRuleExpNode = node; } + // "look-ahead the SimpleSelector", Atrule node comes _after_ the affected SimpleSelector + if(node.type === 'Atrule') { // marks the end of an Atrule + curAtRuleExpNode = null; + } if(node.type === 'SimpleSelector') { // csso 'SimpleSelector' to be interpreted with CSS2.1 specs, _not_ with CSS3 Selector module specs: @@ -93,7 +96,7 @@ exports.fn = function(data, opts) { // stable-sort css selectors by their specificity var selectorItemsSorted = stable(selectorItemsMqs, function(item1, item2) { return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); - }); + }).reverse(); // last style applies last (final) // apply - + @@@ - - + - diff --git a/test/plugins/inlineStyles.02.svg b/test/plugins/inlineStyles.02.svg index 13a1a6fa3..045d01b80 100644 --- a/test/plugins/inlineStyles.02.svg +++ b/test/plugins/inlineStyles.02.svg @@ -1,15 +1,12 @@ - + @@@ - - + diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg index 8893eec7f..bbc8f17cf 100644 --- a/test/plugins/inlineStyles.03.svg +++ b/test/plugins/inlineStyles.03.svg @@ -1,16 +1,21 @@ - - - + + + + + @@@ - - - - - + + + + \ No newline at end of file diff --git a/test/plugins/inlineStyles.04.svg b/test/plugins/inlineStyles.04.svg index 7e5e3ffdd..8f3f0cb27 100644 --- a/test/plugins/inlineStyles.04.svg +++ b/test/plugins/inlineStyles.04.svg @@ -1,14 +1,13 @@ - + @@@ - + - diff --git a/test/plugins/inlineStyles.05.svg b/test/plugins/inlineStyles.05.svg index 2ab36d77d..2a03f9fb2 100644 --- a/test/plugins/inlineStyles.05.svg +++ b/test/plugins/inlineStyles.05.svg @@ -1,19 +1,23 @@ - - + @@@ - + - diff --git a/test/plugins/inlineStyles.06.svg b/test/plugins/inlineStyles.06.svg index 1f3956b48..5895243e9 100644 --- a/test/plugins/inlineStyles.06.svg +++ b/test/plugins/inlineStyles.06.svg @@ -1,13 +1,23 @@ - + + @@@ - + + +@@@ + +{"onlyMatchedOnce":false} \ No newline at end of file diff --git a/test/plugins/inlineStyles.07.svg b/test/plugins/inlineStyles.07.svg index 3e3aba672..6c770bd50 100644 --- a/test/plugins/inlineStyles.07.svg +++ b/test/plugins/inlineStyles.07.svg @@ -1,16 +1,17 @@ - + @@@ - - - - + + \ No newline at end of file diff --git a/test/plugins/inlineStyles.08.svg b/test/plugins/inlineStyles.08.svg index 045d01b80..01552ef9b 100644 --- a/test/plugins/inlineStyles.08.svg +++ b/test/plugins/inlineStyles.08.svg @@ -1,12 +1,17 @@ - + @@@ - - + + \ No newline at end of file diff --git a/test/plugins/inlineStyles.09.svg b/test/plugins/inlineStyles.09.svg index 95e1a3958..469c09368 100644 --- a/test/plugins/inlineStyles.09.svg +++ b/test/plugins/inlineStyles.09.svg @@ -1,21 +1,17 @@ - - - - - + + + @@@ - - - + + \ No newline at end of file From f5eed30a718cdb9d4df46ba6c9b7ca0a7f607c56 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 13 Dec 2016 15:24:51 +0100 Subject: [PATCH 073/162] Simplify loops to one. --- plugins/inlineStyles.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 3e3ce0780..106325f35 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -174,10 +174,6 @@ exports.fn = function(data, opts) { list.remove(item); } }); - } - - // update / clean up s with their changed ast - for(styleItemIndex in styleItems) { styleItem = styleItems[styleItemIndex]; if(styleItem.cssAst.rules.isEmpty()){ // clean up now emtpy s From f9eda396c3b0cd47f4e8466f7a056881812aabe6 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 13 Dec 2016 15:28:02 +0100 Subject: [PATCH 074/162] Add test + support for styles in CDATA. --- plugins/inlineStyles.js | 2 +- test/plugins/inlineStyles.10.svg | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/plugins/inlineStyles.10.svg diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index 106325f35..fc3027add 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -37,7 +37,7 @@ exports.fn = function(data, opts) { // skip empty s continue; } - var cssStr = styleEl.content[0].text; + var cssStr = styleEl.content[0].text || styleEl.content[0].cdata || []; // collect s and their css ast var cssAst = csso.parse(cssStr, {context: 'stylesheet'}); diff --git a/test/plugins/inlineStyles.10.svg b/test/plugins/inlineStyles.10.svg new file mode 100644 index 000000000..f0cbd1dc4 --- /dev/null +++ b/test/plugins/inlineStyles.10.svg @@ -0,0 +1,14 @@ + + + + + +@@@ + + + + From 5688e3b47dccb2b919784f9dc03dd0dd44df5cbd Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 13 Dec 2016 15:32:59 +0100 Subject: [PATCH 075/162] Improve comment. --- plugins/inlineStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index fc3027add..eeb491e72 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -96,7 +96,7 @@ exports.fn = function(data, opts) { // stable-sort css selectors by their specificity var selectorItemsSorted = stable(selectorItemsMqs, function(item1, item2) { return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); - }).reverse(); // last style applies last (final) + }).reverse(); // last declaration applies last (final) // apply styles to matched elements for(var selectorItemIndex in selectorItemsSorted) { From ccff9b2733399d52958fe08a2f82c2b4a2744896 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 13 Dec 2016 15:40:56 +0100 Subject: [PATCH 076/162] Improve code. --- plugins/inlineStyles.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index eeb491e72..da731f758 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -94,8 +94,8 @@ exports.fn = function(data, opts) { }); // stable-sort css selectors by their specificity - var selectorItemsSorted = stable(selectorItemsMqs, function(item1, item2) { - return SPECIFICITY.compare(item1.selectorStr, item2.selectorStr); + var selectorItemsSorted = stable(selectorItemsMqs, function(itemA, itemB) { + return SPECIFICITY.compare(itemA.selectorStr, itemB.selectorStr); }).reverse(); // last declaration applies last (final) // apply styles to matched elements @@ -135,10 +135,10 @@ exports.fn = function(data, opts) { csso.walk(inlineCssAst, _fetchDeclarations); // sort by !important(ce) - var mergedDeclarationsSorted = stable(mergedDeclarations, function(declaration1, declaration2) { - var declaration1Score = ~~declaration1.important, // (cast boolean to number) - declaration2Score = ~~declaration2.important; // " - return (declaration1Score - declaration2Score); + var mergedDeclarationsSorted = stable(mergedDeclarations, function(declarationA, declarationB) { + var declarationAScore = ~~declarationA.important, // (cast boolean to number) + declarationBScore = ~~declarationB.important; // " + return (declarationAScore - declarationBScore); }); // to css From 8784548dcb28d61ea076897d60690188980afb85 Mon Sep 17 00:00:00 2001 From: strarsis Date: Tue, 13 Dec 2016 15:49:10 +0100 Subject: [PATCH 077/162] Fix !important(ce) sorting + tests. --- plugins/inlineStyles.js | 4 ++-- test/plugins/inlineStyles.07.svg | 2 +- test/plugins/inlineStyles.08.svg | 2 +- test/plugins/inlineStyles.09.svg | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index da731f758..64f6095e9 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -136,8 +136,8 @@ exports.fn = function(data, opts) { // sort by !important(ce) var mergedDeclarationsSorted = stable(mergedDeclarations, function(declarationA, declarationB) { - var declarationAScore = ~~declarationA.important, // (cast boolean to number) - declarationBScore = ~~declarationB.important; // " + var declarationAScore = ~~declarationA.data.value.important, // (cast boolean to number) + declarationBScore = ~~declarationB.data.value.important; // " return (declarationAScore - declarationBScore); }); diff --git a/test/plugins/inlineStyles.07.svg b/test/plugins/inlineStyles.07.svg index 6c770bd50..d64e28b6b 100644 --- a/test/plugins/inlineStyles.07.svg +++ b/test/plugins/inlineStyles.07.svg @@ -13,5 +13,5 @@ @@@ - + \ No newline at end of file diff --git a/test/plugins/inlineStyles.08.svg b/test/plugins/inlineStyles.08.svg index 01552ef9b..ce9a296d4 100644 --- a/test/plugins/inlineStyles.08.svg +++ b/test/plugins/inlineStyles.08.svg @@ -13,5 +13,5 @@ @@@ - + \ No newline at end of file diff --git a/test/plugins/inlineStyles.09.svg b/test/plugins/inlineStyles.09.svg index 469c09368..4505467b7 100644 --- a/test/plugins/inlineStyles.09.svg +++ b/test/plugins/inlineStyles.09.svg @@ -13,5 +13,5 @@ @@@ - + \ No newline at end of file From cc27c46a9a7d0cf2920018c016fd05f22be6226b Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 14 Dec 2016 17:59:37 +0100 Subject: [PATCH 078/162] Simplified select-css method + adapter. --- lib/ext/select-css.js | 6 +----- lib/ext/svgo-css-adapter.js | 10 ++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/ext/select-css.js b/lib/ext/select-css.js index 7902d3314..7bfe330ef 100644 --- a/lib/ext/select-css.js +++ b/lib/ext/select-css.js @@ -3,16 +3,12 @@ var cssSelect = require('css-select'), SvgoCssAdapter = require('./svgo-css-adapter'); -var cssSelectOpts = {xmlMode: true}; +var cssSelectOpts = {xmlMode: true, adapter: SvgoCssAdapter}; /** * Returns array of csso AST nodes that match a passed css selector * against a passed node (usually the root node). */ module.exports = function(selector, rootNode) { - if(!cssSelectOpts.adapter) { - cssSelectOpts.adapter = new SvgoCssAdapter(rootNode); - } - return cssSelect(selector, rootNode, cssSelectOpts); }; diff --git a/lib/ext/svgo-css-adapter.js b/lib/ext/svgo-css-adapter.js index fc77a2230..dee1f21b4 100644 --- a/lib/ext/svgo-css-adapter.js +++ b/lib/ext/svgo-css-adapter.js @@ -46,13 +46,7 @@ var svgoCssAdapterMin = { }; // use base adapter for default implementations -var svgoCssAdapterProto = baseCssAdapter(svgoCssAdapterMin); +var svgoCssAdapter = baseCssAdapter(svgoCssAdapterMin); -// svgo adapter constructor for passing root node -var SvgoCssAdapter = function(rootNode) { - this.rootNode = rootNode; -}; -SvgoCssAdapter.prototype = svgoCssAdapterProto; - -module.exports = SvgoCssAdapter; +module.exports = svgoCssAdapter; From 6709815bf120956c637892e0fd37a2a7a8c64ffd Mon Sep 17 00:00:00 2001 From: strarsis Date: Wed, 14 Dec 2016 18:00:42 +0100 Subject: [PATCH 079/162] Add comment to test. --- test/plugins/inlineStyles.03.svg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg index bbc8f17cf..ae9225cac 100644 --- a/test/plugins/inlineStyles.03.svg +++ b/test/plugins/inlineStyles.03.svg @@ -1,4 +1,5 @@ + From 751dad01120fcb786b7979f5b27d8db13a7ea642 Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 3 Apr 2017 14:42:43 +0200 Subject: [PATCH 150/162] Lock css-tree package version. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b6b557b3..c220ec97f 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "colors": "~1.1.2", "css-select": "^1.3.0-rc0", "css-select-base-adapter": "^0.1.0", - "css-tree": "github:csstree/csstree", + "css-tree": "github:csstree/csstree#e9c024b02a38d98c9eb886526709e54655eee2e1", "csso": "^3.0.1", "js-yaml": "~3.7.0", "mkdirp": "~0.5.1", From d212cee82c3d4728be0237bb8901945e96ba16de Mon Sep 17 00:00:00 2001 From: strarsis Date: Mon, 3 Apr 2017 14:43:08 +0200 Subject: [PATCH 151/162] Fix indents/formatting. --- lib/css-tools.js | 165 +++++++++-------- lib/svgo/css-select-adapter.js | 80 ++++----- lib/svgo/css-style-declaration.js | 203 ++++++++++----------- lib/svgo/svg2js.js | 2 +- plugins/inlineStyles.js | 287 +++++++++++++++--------------- test/plugins/inlineStyles.03.svg | 24 +-- test/plugins/inlineStyles.05.svg | 4 +- test/plugins/inlineStyles.06.svg | 4 +- test/plugins/inlineStyles.07.svg | 4 +- test/plugins/inlineStyles.08.svg | 4 +- test/plugins/inlineStyles.09.svg | 4 +- test/plugins/inlineStyles.13.svg | 84 ++++----- test/plugins/inlineStyles.14.svg | 22 +-- test/plugins/inlineStyles.15.svg | 100 +++++------ 14 files changed, 500 insertions(+), 487 deletions(-) diff --git a/lib/css-tools.js b/lib/css-tools.js index ba18dbbd4..9589b6955 100644 --- a/lib/css-tools.js +++ b/lib/css-tools.js @@ -1,9 +1,9 @@ 'use strict'; -var csstree = require('css-tree'), - stable = require('stable'), +var csstree = require('css-tree'), + stable = require('stable'), specificity = require('csso/lib/restructure/prepare/specificity'), - List = require('css-tree/lib/utils/list'); + List = require('css-tree/lib/utils/list'); /** @@ -13,36 +13,39 @@ var csstree = require('css-tree'), * @return {Array} selectors */ function flattenToSelectors(cssAst) { - var selectors = []; - - csstree.walkRules(cssAst, function(node) { - if (node.type !== 'Rule') { - return; - } - - var atrule = this.atrule; - var rule = node; - - node.selector.children.each(function(selectorNode, selectorItem) { - var selector = { - item: selectorItem, - atrule: atrule, - rule: rule, - pseudos: [] - }; - - selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) { - if(selectorChildNode.type === 'PseudoClassSelector' || - selectorChildNode.type === 'PseudoElementSelector') { - selector.pseudos.push({ item: selectorChildItem, list: selectorChildList }); - } + var selectors = []; + + csstree.walkRules(cssAst, function(node) { + if (node.type !== 'Rule') { + return; + } + + var atrule = this.atrule; + var rule = node; + + node.selector.children.each(function(selectorNode, selectorItem) { + var selector = { + item: selectorItem, + atrule: atrule, + rule: rule, + pseudos: [] + }; + + selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) { + if (selectorChildNode.type === 'PseudoClassSelector' || + selectorChildNode.type === 'PseudoElementSelector') { + selector.pseudos.push({ + item: selectorChildItem, + list: selectorChildList + }); + } + }); + + selectors.push(selector); }); - - selectors.push(selector); }); -}); - return selectors; + return selectors; } /** @@ -53,20 +56,20 @@ function flattenToSelectors(cssAst) { * @return {Array} Filtered selectors that match the passed media queries */ function filterByMqs(selectors, useMqs) { - return selectors.filter(function(selector) { - if(selector.atrule === null) { - return useMqs.indexOf('') > -1; - } - - var mqName = selector.atrule.name; - var mqStr = mqName; - if(selector.atrule.expression.type === 'MediaQueryList') { - var mqExpr = csstree.translate(selector.atrule.expression); - mqStr = [mqName, mqExpr].join(' '); - } - - return useMqs.indexOf(mqStr) > -1; - }); + return selectors.filter(function(selector) { + if (selector.atrule === null) { + return useMqs.indexOf('') > -1; + } + + var mqName = selector.atrule.name; + var mqStr = mqName; + if (selector.atrule.expression.type === 'MediaQueryList') { + var mqExpr = csstree.translate(selector.atrule.expression); + mqStr = [mqName, mqExpr].join(' '); + } + + return useMqs.indexOf(mqStr) > -1; + }); } /** @@ -77,15 +80,15 @@ function filterByMqs(selectors, useMqs) { * @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes */ function filterByPseudos(selectors, usePseudos) { - return selectors.filter(function(selector) { - var pseudoSelectorsStr = csstree.translate({ - type: 'Selector', - children: new List().fromArray(selector.pseudos.map(function(pseudo) { - return pseudo.item.data; - })) + return selectors.filter(function(selector) { + var pseudoSelectorsStr = csstree.translate({ + type: 'Selector', + children: new List().fromArray(selector.pseudos.map(function(pseudo) { + return pseudo.item.data; + })) + }); + return usePseudos.indexOf(pseudoSelectorsStr) > -1; }); - return usePseudos.indexOf(pseudoSelectorsStr) > -1; - }); } /** @@ -95,11 +98,11 @@ function filterByPseudos(selectors, usePseudos) { * @return {Array} Selectors without pseudo-elements and/or -classes */ function cleanPseudos(selectors) { - selectors.forEach(function(selector) { - selector.pseudos.forEach(function(pseudo) { - pseudo.list.remove(pseudo.item); + selectors.forEach(function(selector) { + selector.pseudos.forEach(function(pseudo) { + pseudo.list.remove(pseudo.item); + }); }); - }); } @@ -112,15 +115,15 @@ function cleanPseudos(selectors) { * @return {Number} Score of selector specificity A compared to selector specificity B */ function compareSpecificity(aSpecificity, bSpecificity) { - for (var i = 0; i < 4; i += 1) { - if (aSpecificity[i] < bSpecificity[i]) { - return -1; - } else if (aSpecificity[i] > bSpecificity[i]) { - return 1; + for (var i = 0; i < 4; i += 1) { + if (aSpecificity[i] < bSpecificity[i]) { + return -1; + } else if (aSpecificity[i] > bSpecificity[i]) { + return 1; + } } - } - return 0; + return 0; } @@ -132,13 +135,13 @@ function compareSpecificity(aSpecificity, bSpecificity) { * @return {Number} Score of selector A compared to selector B */ function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) { - var aSpecificity = specificity(aSimpleSelectorNode), - bSpecificity = specificity(bSimpleSelectorNode); - return compareSpecificity(aSpecificity, bSpecificity); + var aSpecificity = specificity(aSimpleSelectorNode), + bSpecificity = specificity(bSimpleSelectorNode); + return compareSpecificity(aSpecificity, bSpecificity); } function _bySelectorSpecificity(selectorA, selectorB) { - return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data); + return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data); } @@ -149,7 +152,7 @@ function _bySelectorSpecificity(selectorA, selectorB) { * @return {Array} Stable sorted selectors */ function sortSelectors(selectors) { - return stable(selectors, _bySelectorSpecificity); + return stable(selectors, _bySelectorSpecificity); } @@ -160,22 +163,26 @@ function sortSelectors(selectors) { * @return {Object} CSSStyleDeclaration property */ function cssoToStyleDeclaration(cssoDeclaration) { - var propertyName = cssoDeclaration.property, - propertyValue = csstree.translate(cssoDeclaration.value), - propertyPriority = (cssoDeclaration.important ? 'important' : ''); - return { name: propertyName, value: propertyValue, priority: propertyPriority }; + var propertyName = cssoDeclaration.property, + propertyValue = csstree.translate(cssoDeclaration.value), + propertyPriority = (cssoDeclaration.important ? 'important' : ''); + return { + name: propertyName, + value: propertyValue, + priority: propertyPriority + }; } -module.exports.flattenToSelectors = flattenToSelectors; +module.exports.flattenToSelectors = flattenToSelectors; -module.exports.filterByMqs = filterByMqs; -module.exports.filterByPseudos = filterByPseudos; -module.exports.cleanPseudos = cleanPseudos; +module.exports.filterByMqs = filterByMqs; +module.exports.filterByPseudos = filterByPseudos; +module.exports.cleanPseudos = cleanPseudos; -module.exports.compareSpecificity = compareSpecificity; +module.exports.compareSpecificity = compareSpecificity; module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode; -module.exports.sortSelectors = sortSelectors; +module.exports.sortSelectors = sortSelectors; -module.exports.cssoToStyleDeclaration = cssoToStyleDeclaration; +module.exports.cssoToStyleDeclaration = cssoToStyleDeclaration; diff --git a/lib/svgo/css-select-adapter.js b/lib/svgo/css-select-adapter.js index 54604a775..c37678cbf 100644 --- a/lib/svgo/css-select-adapter.js +++ b/lib/svgo/css-select-adapter.js @@ -3,48 +3,48 @@ var baseCssAdapter = require('css-select-base-adapter'); /** - * DOMUtils API for SVGO AST (used by css-select) - */ + * DOMUtils API for SVGO AST (used by css-select) + */ var svgoCssSelectAdapterMin = { - // is the node a tag? - // isTag: ( node:Node ) => isTag:Boolean - isTag: function(node) { - return node.isElem(); - }, - - // get the parent of the node - // getParent: ( node:Node ) => parentNode:Node - // returns null when no parent exists - getParent: function(node) { - return node.parentNode || null; - }, - - // get the node's children - // getChildren: ( node:Node ) => children:[Node] - getChildren: function(node) { - return node.content || []; - }, - - // get the name of the tag - // getName: ( elem:ElementNode ) => tagName:String - getName: function(elemAst) { - return elemAst.elem; - }, - - // get the text content of the node, and its children if it has any - // getText: ( node:Node ) => text:String - // returns empty string when there is no text - getText: function(node) { - return node.content[0].text || node.content[0].cdata || ''; - }, - - // get the attribute value - // getAttributeValue: ( elem:ElementNode, name:String ) => value:String - // returns null when attribute doesn't exist - getAttributeValue: function(elem, name) { - return elem.hasAttr(name) ? elem.attr(name).value : null; - } + // is the node a tag? + // isTag: ( node:Node ) => isTag:Boolean + isTag: function(node) { + return node.isElem(); + }, + + // get the parent of the node + // getParent: ( node:Node ) => parentNode:Node + // returns null when no parent exists + getParent: function(node) { + return node.parentNode || null; + }, + + // get the node's children + // getChildren: ( node:Node ) => children:[Node] + getChildren: function(node) { + return node.content || []; + }, + + // get the name of the tag + // getName: ( elem:ElementNode ) => tagName:String + getName: function(elemAst) { + return elemAst.elem; + }, + + // get the text content of the node, and its children if it has any + // getText: ( node:Node ) => text:String + // returns empty string when there is no text + getText: function(node) { + return node.content[0].text || node.content[0].cdata || ''; + }, + + // get the attribute value + // getAttributeValue: ( elem:ElementNode, name:String ) => value:String + // returns null when attribute doesn't exist + getAttributeValue: function(elem, name) { + return elem.hasAttr(name) ? elem.attr(name).value : null; + } }; // use base adapter for default implementation diff --git a/lib/svgo/css-style-declaration.js b/lib/svgo/css-style-declaration.js index 6f1f7d912..aaa814089 100644 --- a/lib/svgo/css-style-declaration.js +++ b/lib/svgo/css-style-declaration.js @@ -1,29 +1,29 @@ 'use strict'; -var csstree = require('css-tree'), +var csstree = require('css-tree'), csstools = require('../css-tools'); var CSSStyleDeclaration = function(node) { - this.parentNode = node; + this.parentNode = node; - this.properties = new Map(); - this.hasSynced = false; + this.properties = new Map(); + this.hasSynced = false; - this.styleAttr = null; - this.styleValue = null; + this.styleAttr = null; + this.styleValue = null; - this.parseError = false; + this.parseError = false; }; CSSStyleDeclaration.prototype.hasStyle = function() { - this.styleAttr = { // empty style attr - 'name': 'style', - 'value': null - }; + this.styleAttr = { // empty style attr + 'name': 'style', + 'value': null + }; - this.addStyleHandler(); + this.addStyleHandler(); }; @@ -33,78 +33,81 @@ CSSStyleDeclaration.prototype.hasStyle = function() { CSSStyleDeclaration.prototype.addStyleHandler = function() { - Object.defineProperty(this.parentNode.attrs, 'style', { - get: this.getStyleAttr.bind(this), - set: this.setStyleAttr.bind(this), - enumerable: true, - configurable: true - }); + Object.defineProperty(this.parentNode.attrs, 'style', { + get: this.getStyleAttr.bind(this), + set: this.setStyleAttr.bind(this), + enumerable: true, + configurable: true + }); - this.addStyleValueHandler(); + this.addStyleValueHandler(); }; // attr.style.value CSSStyleDeclaration.prototype.addStyleValueHandler = function() { - Object.defineProperty(this.styleAttr, 'value', { - get: this.getStyleValue.bind(this), - set: this.setStyleValue.bind(this), - enumerable: true, - configurable: true - }); + Object.defineProperty(this.styleAttr, 'value', { + get: this.getStyleValue.bind(this), + set: this.setStyleValue.bind(this), + enumerable: true, + configurable: true + }); }; CSSStyleDeclaration.prototype.getStyleAttr = function() { - return this.styleAttr; + return this.styleAttr; }; CSSStyleDeclaration.prototype.setStyleAttr = function(newStyleAttr) { - this.setStyleValue(newStyleAttr.value); // must before applying value handler! + this.setStyleValue(newStyleAttr.value); // must before applying value handler! - this.styleAttr = newStyleAttr; - this.addStyleValueHandler(); - this.hasSynced = false; // raw css changed + this.styleAttr = newStyleAttr; + this.addStyleValueHandler(); + this.hasSynced = false; // raw css changed }; CSSStyleDeclaration.prototype.getStyleValue = function() { - return this.getCssText(); + return this.getCssText(); }; CSSStyleDeclaration.prototype.setStyleValue = function(newValue) { - this.properties.clear(); // reset all existing properties - this.styleValue = newValue; - this.hasSynced = false; // raw css changed + this.properties.clear(); // reset all existing properties + this.styleValue = newValue; + this.hasSynced = false; // raw css changed }; CSSStyleDeclaration.prototype._loadCssText = function() { - if(this.hasSynced) { - return; - } - this.hasSynced = true; // must be set here to prevent loop in setProperty(...) - - if(!this.styleValue || this.styleValue.length === 0) { - return; - } - var inlineCssStr = this.styleValue; - - var cssoDeclarations = {}; - try { - cssoDeclarations = csstree.parse(inlineCssStr, {context: 'declarationList', parseValue: false}); - } catch(parseError) { - this.parseError = parseError; - return; - } - this.parseError = false; - - var self = this; - cssoDeclarations.children.each(function(cssoDeclaration) { - var styleDeclaration = csstools.cssoToStyleDeclaration(cssoDeclaration); - self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); - }); + if (this.hasSynced) { + return; + } + this.hasSynced = true; // must be set here to prevent loop in setProperty(...) + + if (!this.styleValue || this.styleValue.length === 0) { + return; + } + var inlineCssStr = this.styleValue; + + var cssoDeclarations = {}; + try { + cssoDeclarations = csstree.parse(inlineCssStr, { + context: 'declarationList', + parseValue: false + }); + } catch (parseError) { + this.parseError = parseError; + return; + } + this.parseError = false; + + var self = this; + cssoDeclarations.children.each(function(cssoDeclaration) { + var styleDeclaration = csstools.cssoToStyleDeclaration(cssoDeclaration); + self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); + }); }; @@ -116,34 +119,34 @@ CSSStyleDeclaration.prototype._loadCssText = function() { * @return {String} Textual representation of the declaration block (empty string for no properties) */ CSSStyleDeclaration.prototype.getCssText = function() { - var properties = this.getProperties(); + var properties = this.getProperties(); - if(this.parseError) { - // in case of a parse error, pass through original styles - return this.styleValue; - } + if (this.parseError) { + // in case of a parse error, pass through original styles + return this.styleValue; + } - var cssText = []; - properties.forEach(function(property, propertyName) { - var strImportant = property.priority === 'important' ? '!important' : ''; - cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant); - }); - return cssText.join(';'); + var cssText = []; + properties.forEach(function(property, propertyName) { + var strImportant = property.priority === 'important' ? '!important' : ''; + cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant); + }); + return cssText.join(';'); }; CSSStyleDeclaration.prototype._handleParseError = function() { - if(this.parseError) { - console.warn('Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr(\'style\').value. Error details: ' + this.parseError); - } + if (this.parseError) { + console.warn('Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr(\'style\').value. Error details: ' + this.parseError); + } }; CSSStyleDeclaration.prototype._getProperty = function(propertyName) { - var properties = this.getProperties(); - this._handleParseError(); + var properties = this.getProperties(); + this._handleParseError(); - var property = properties.get(propertyName.trim()); - return property; + var property = properties.get(propertyName.trim()); + return property; }; /** @@ -153,8 +156,8 @@ CSSStyleDeclaration.prototype._getProperty = function(propertyName) { * @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string. */ CSSStyleDeclaration.prototype.getPropertyPriority = function(propertyName) { - var property = this._getProperty(propertyName); - return property ? property.priority : ''; + var property = this._getProperty(propertyName); + return property ? property.priority : ''; }; /** @@ -164,8 +167,8 @@ CSSStyleDeclaration.prototype.getPropertyPriority = function(propertyName) { * @return {String} value containing the value of the property. If not set, returns the empty string. */ CSSStyleDeclaration.prototype.getPropertyValue = function(propertyName) { - var property = this._getProperty(propertyName); - return property ? property.value : null; + var property = this._getProperty(propertyName); + return property ? property.value : null; }; /** @@ -175,10 +178,10 @@ CSSStyleDeclaration.prototype.getPropertyValue = function(propertyName) { * @return {String} propertyName that is the name of the CSS property at the specified index. */ CSSStyleDeclaration.prototype.item = function(index) { - var properties = this.getProperties(); - this._handleParseError(); + var properties = this.getProperties(); + this._handleParseError(); - return Array.from(properties.keys())[index]; + return Array.from(properties.keys())[index]; }; /** @@ -187,8 +190,8 @@ CSSStyleDeclaration.prototype.item = function(index) { * @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value. */ CSSStyleDeclaration.prototype.getProperties = function() { - this._loadCssText(); - return this.properties; + this._loadCssText(); + return this.properties; }; @@ -201,14 +204,14 @@ CSSStyleDeclaration.prototype.getProperties = function() { * @return {String} oldValue equal to the value of the CSS property before it was removed. */ CSSStyleDeclaration.prototype.removeProperty = function(propertyName) { - this.hasStyle(); + this.hasStyle(); - var properties = this.getProperties(); - this._handleParseError(); + var properties = this.getProperties(); + this._handleParseError(); - var oldValue = this.getPropertyValue(propertyName); - properties.delete(propertyName.trim()); - return oldValue; + var oldValue = this.getPropertyValue(propertyName); + properties.delete(propertyName.trim()); + return oldValue; }; /** @@ -220,18 +223,18 @@ CSSStyleDeclaration.prototype.removeProperty = function(propertyName) { * @return {undefined} */ CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priority) { - this.hasStyle(); + this.hasStyle(); - var properties = this.getProperties(); - this._handleParseError(); + var properties = this.getProperties(); + this._handleParseError(); - var property = { - value: value.trim(), - priority: priority.trim() - }; - properties.set(propertyName.trim(), property); + var property = { + value: value.trim(), + priority: priority.trim() + }; + properties.set(propertyName.trim(), property); - return property; + return property; }; diff --git a/lib/svgo/svg2js.js b/lib/svgo/svg2js.js index e4cea9b75..385c55d16 100644 --- a/lib/svgo/svg2js.js +++ b/lib/svgo/svg2js.js @@ -96,7 +96,7 @@ module.exports = function(data, callback) { for (var name in data.attributes) { - if(name === 'style') { + if (name === 'style') { elem.style.hasStyle(); } diff --git a/plugins/inlineStyles.js b/plugins/inlineStyles.js index c3dbaa741..1fe6ba880 100644 --- a/plugins/inlineStyles.js +++ b/plugins/inlineStyles.js @@ -1,189 +1,192 @@ 'use strict'; -exports.type = 'full'; +exports.type = 'full'; exports.active = true; exports.params = { - onlyMatchedOnce: true, - removeMatchedSelectors: true, - useMqs: ['', 'screen'], - usePseudos: [''] + onlyMatchedOnce: true, + removeMatchedSelectors: true, + useMqs: ['', 'screen'], + usePseudos: [''] }; exports.description = 'inline styles (additional options)'; -var csstree = require('css-tree'), +var csstree = require('css-tree'), cssTools = require('../lib/css-tools'); /** - * Moves + merges styles from style elements to element styles - * - * Options - * onlyMatchedOnce (default: true) - * inline only selectors that match once - * - * removeMatchedSelectors (default: true) - * clean up matched selectors, - * leave selectors that hadn't matched - * - * useMqs (default: ['', 'screen']) - * what media queries to be used - * empty string element for styles outside media queries - * - * usePseudos (default: ['']) - * what pseudo-classes/-elements to be used - * empty string element for all non-pseudo-classes and/or -elements - * - * @param {Object} document document element - * @param {Object} opts plugin params - * - * @author strarsis - */ + * Moves + merges styles from style elements to element styles + * + * Options + * onlyMatchedOnce (default: true) + * inline only selectors that match once + * + * removeMatchedSelectors (default: true) + * clean up matched selectors, + * leave selectors that hadn't matched + * + * useMqs (default: ['', 'screen']) + * what media queries to be used + * empty string element for styles outside media queries + * + * usePseudos (default: ['']) + * what pseudo-classes/-elements to be used + * empty string element for all non-pseudo-classes and/or -elements + * + * @param {Object} document document element + * @param {Object} opts plugin params + * + * @author strarsis + */ exports.fn = function(document, opts) { - // collect s - var styleEls = document.querySelectorAll('style'); + // collect s + var styleEls = document.querySelectorAll('style'); - //no s, nothing to do - if(styleEls === null) { - return document; - } + //no s, nothing to do + if (styleEls === null) { + return document; + } - var styles = [], - selectors = []; + var styles = [], + selectors = []; - for(var styleEl of styleEls) { - if(styleEl.isEmpty()) { - // skip empty s - continue; - } - var cssStr = styleEl.content[0].text || styleEl.content[0].cdata || []; - - // collect s and their css ast - var cssAst = {}; - try { - cssAst = csstree.parse(cssStr, {parseValue: false, parseCustomProperty: false}); - } catch(parseError) { - console.warn('Warning: Parse error of styles of element, skipped. Error details: ' + parseError); - continue; - } + for (var styleEl of styleEls) { + if (styleEl.isEmpty()) { + // skip empty s + continue; + } + var cssStr = styleEl.content[0].text || styleEl.content[0].cdata || []; + + // collect s and their css ast + var cssAst = {}; + try { + cssAst = csstree.parse(cssStr, { + parseValue: false, + parseCustomProperty: false + }); + } catch (parseError) { + console.warn('Warning: Parse error of styles of element, skipped. Error details: ' + parseError); + continue; + } + + styles.push({ + styleEl: styleEl, + cssAst: cssAst + }); - styles.push({ - styleEl: styleEl, - cssAst: cssAst - }); + selectors = selectors.concat(cssTools.flattenToSelectors(cssAst)); + } - selectors = selectors.concat(cssTools.flattenToSelectors(cssAst)); - } + // filter for mediaqueries to be used or without any mediaquery + var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs); - // filter for mediaqueries to be used or without any mediaquery - var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs); + // filter for pseudo elements to be used + var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos); - // filter for pseudo elements to be used - var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos); + // remove PseudoClass from its SimpleSelector for proper matching + cssTools.cleanPseudos(selectorsPseudo); - // remove PseudoClass from its SimpleSelector for proper matching - cssTools.cleanPseudos(selectorsPseudo); + // stable sort selectors + var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse(); - // stable sort selectors - var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse(); + // apply styles to matched elements + for (var selector of sortedSelectors) { + var selectorStr = csstree.translate(selector.item.data), + selectedEls = null; - // apply styles to matched elements - for(var selector of sortedSelectors) { - var selectorStr = csstree.translate(selector.item.data), - selectedEls = null; + try { + selectedEls = document.querySelectorAll(selectorStr); + } catch (selectError) { + if (selectError.constructor === SyntaxError) { + console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError); + continue; + } + throw selectError; + } - try { - selectedEls = document.querySelectorAll(selectorStr); - } catch(selectError) { - if(selectError.constructor === SyntaxError) { - console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError); + if (selectedEls === null) { + // nothing selected continue; } - throw selectError; - } - if(selectedEls === null) { - // nothing selected - continue; - } + if (opts.onlyMatchedOnce && selectedEls !== null && selectedEls.length > 1) { + // skip selectors that match more than once if option onlyMatchedOnce is enabled + continue; + } - if(opts.onlyMatchedOnce && selectedEls !== null && selectedEls.length > 1) { - // skip selectors that match more than once if option onlyMatchedOnce is enabled - continue; - } + // apply to matched elements + for (var selectedEl of selectedEls) { - // apply to matched elements - for(var selectedEl of selectedEls) { + if (selector.rule === null) { + continue; + } - if(selector.rule === null) { - continue; - } + // merge declarations + csstree.walkDeclarations(selector.rule, function(styleCssoDeclaration) { + var styleDeclaration = cssTools.cssoToStyleDeclaration(styleCssoDeclaration); + if (selectedEl.style.getPropertyValue(styleDeclaration.name) !== null && + selectedEl.style.getPropertyPriority(styleDeclaration.name) >= styleDeclaration.priority) { + return; + } + selectedEl.style.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); + }); - // merge declarations - csstree.walkDeclarations(selector.rule, function(styleCssoDeclaration) { - var styleDeclaration = cssTools.cssoToStyleDeclaration(styleCssoDeclaration); - if(selectedEl.style.getPropertyValue(styleDeclaration.name) !== null && - selectedEl.style.getPropertyPriority(styleDeclaration.name) >= styleDeclaration.priority) { - return; } - selectedEl.style.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority); - }); + if (opts.removeMatchedSelectors && selectedEls !== null && selectedEls.length > 0) { + // clean up matching simple selectors if option removeMatchedSelectors is enabled + selector.rule.selector.children.remove(selector.item); + } } - if(opts.removeMatchedSelectors && selectedEls !== null && selectedEls.length > 0) { - // clean up matching simple selectors if option removeMatchedSelectors is enabled - selector.rule.selector.children.remove(selector.item); - } - } - - - for(var style of styles) { - csstree.walkRules(style.cssAst, function(node, item, list) { - // clean up atrules without any rulesets left - if(node.type === 'Atrule' && - // only Atrules containing rulesets - node.block !== null && - node.block.children.isEmpty()) { - list.remove(item); - return; - } - - // clean up rulesets without any css selectors left - if(node.type === 'Rule' && - node.selector.children.isEmpty()) { - list.remove(item); - } - }); - - - if(style.cssAst.children.isEmpty()){ - // clean up now emtpy s - var styleParentEl = style.styleEl.parentNode; - styleParentEl.spliceContent(styleParentEl.content.indexOf(style.styleEl), 1); - - if(styleParentEl.elem === 'defs' && - styleParentEl.content.length === 0) { - // also clean up now empty s - var defsParentEl = styleParentEl.parentNode; - defsParentEl.spliceContent(defsParentEl.content.indexOf(styleParentEl), 1); - } - - continue; - } + for (var style of styles) { + csstree.walkRules(style.cssAst, function(node, item, list) { + // clean up atrules without any rulesets left + if (node.type === 'Atrule' && + // only Atrules containing rulesets + node.block !== null && + node.block.children.isEmpty()) { + list.remove(item); + return; + } + + // clean up rulesets without any css selectors left + if (node.type === 'Rule' && + node.selector.children.isEmpty()) { + list.remove(item); + } + }); + + + if (style.cssAst.children.isEmpty()) { + // clean up now emtpy s + var styleParentEl = style.styleEl.parentNode; + styleParentEl.spliceContent(styleParentEl.content.indexOf(style.styleEl), 1); + + if (styleParentEl.elem === 'defs' && + styleParentEl.content.length === 0) { + // also clean up now empty s + var defsParentEl = styleParentEl.parentNode; + defsParentEl.spliceContent(defsParentEl.content.indexOf(styleParentEl), 1); + } + + continue; + } - // update existing, left over diff --git a/test/plugins/inlineStyles.14.svg b/test/plugins/inlineStyles.14.svg index dc1596048..74e17a55f 100644 --- a/test/plugins/inlineStyles.14.svg +++ b/test/plugins/inlineStyles.14.svg @@ -17,7 +17,7 @@ @@@ - + @@@ diff --git a/test/plugins/inlineStyles.16.svg b/test/plugins/inlineStyles.16.svg new file mode 100644 index 000000000..bdcb1ad5a --- /dev/null +++ b/test/plugins/inlineStyles.16.svg @@ -0,0 +1,40 @@ + + + + + button + + + + + + + +@@@ + + + + button + + + + + + + + +@@@ + +{"onlyMatchedOnce":false} From 165fec488b1412038d7b8413f0e28baee01e4341 Mon Sep 17 00:00:00 2001 From: strarsis Date: Fri, 8 Sep 2017 16:31:07 +0200 Subject: [PATCH 161/162] Fix test 03. --- test/plugins/inlineStyles.03.svg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/plugins/inlineStyles.03.svg b/test/plugins/inlineStyles.03.svg index 0335fca93..32f554268 100644 --- a/test/plugins/inlineStyles.03.svg +++ b/test/plugins/inlineStyles.03.svg @@ -4,7 +4,8 @@ .cls-7 { only-cls-7: 1; } - .cls-7 { + .cls-7, + .cls-8 { cls-7-and-8: 1; } @@ -16,5 +17,8 @@ + From 43dae25d0991dc01209a7236f6bb866cd099d14e Mon Sep 17 00:00:00 2001 From: strarsis Date: Fri, 8 Sep 2017 17:14:13 +0200 Subject: [PATCH 162/162] Update css-tree to alpha22. --- lib/css-tools.js | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/css-tools.js b/lib/css-tools.js index 0e1afcfd7..e054f6bb2 100644 --- a/lib/css-tools.js +++ b/lib/css-tools.js @@ -63,7 +63,8 @@ function filterByMqs(selectors, useMqs) { var mqName = selector.atrule.name; var mqStr = mqName; - if (selector.atrule.expression.type === 'MediaQueryList') { + if (selector.atrule.expression && + selector.atrule.expression.children.first().type === 'MediaQueryList') { var mqExpr = csstree.translate(selector.atrule.expression); mqStr = [mqName, mqExpr].join(' '); } diff --git a/package.json b/package.json index 5d554a567..a975ea1af 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "colors": "~1.1.2", "css-select": "^1.3.0-rc0", "css-select-base-adapter": "^0.1.0", - "css-tree": "1.0.0-alpha18", + "css-tree": "1.0.0-alpha22", "csso": "^3.0.1", "js-yaml": "~3.7.0", "mkdirp": "~0.5.1",