Editor: preserve intermediary global sections on import

Because the order of sections influences which rules will apply when several matching rules are present both in a global section and previously declared scoped one.
This commit is contained in:
tophf 2016-02-02 08:30:08 +02:00
parent 426b4d37ba
commit ad8706e107

97
edit.js
View File

@ -1332,19 +1332,24 @@ function fromMozillaFormat() {
popup.querySelector(".close-icon").click(); popup.querySelector(".close-icon").click();
var mozStyle = trimNewLines(popup.codebox.getValue()); var mozStyle = trimNewLines(popup.codebox.getValue());
var parser = new exports.css.Parser(), lines = mozStyle.split("\n"); var parser = new exports.css.Parser(), lines = mozStyle.split("\n");
var sectionStack = [{code: "", cursor: {line: 1, col: 1}}]; var sectionStack = [{code: "", start: {line: 1, col: 1}}];
var errors = "", oldSectionCount = editors.length; var errors = "", oldSectionCount = editors.length;
var firstAddedCM;
parser.addListener("startdocument", function(e) { parser.addListener("startdocument", function(e) {
var outerText = getRange(sectionStack.last.cursor, (--e.col, e)); var outerText = getRange(sectionStack.last.start, (--e.col, e));
var gapComment = outerText.match(/(\/\*[\s\S]*?\*\/)[\s\n]*$/); var gapComment = outerText.match(/(\/\*[\s\S]*?\*\/)[\s\n]*$/);
var section = {code: "", cursor: backtrackTo(this, exports.css.Tokens.LBRACE, "end")}; var section = {code: "", start: backtrackTo(this, exports.css.Tokens.LBRACE, "end")};
// move last comment before @-moz-document inside the section // move last comment before @-moz-document inside the section
if (gapComment && !gapComment[1].match(/\/\*\s*AGENT_SHEET\s*\*\//)) { if (gapComment && !gapComment[1].match(/\/\*\s*AGENT_SHEET\s*\*\//)) {
section.code = gapComment[1] + "\n"; section.code = gapComment[1] + "\n";
outerText = trimNewLines(outerText.substring(0, gapComment.index)); outerText = trimNewLines(outerText.substring(0, gapComment.index));
} }
addContinuation(sectionStack.last, outerText); if (outerText) {
sectionStack.last.code = outerText;
doAddSection(sectionStack.last);
sectionStack.last.code = "";
}
e.functions.forEach(function(f) { e.functions.forEach(function(f) {
var m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/); var m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/);
var aType = CssToProperty[m[1]]; var aType = CssToProperty[m[1]];
@ -1355,50 +1360,27 @@ function fromMozillaFormat() {
}); });
parser.addListener("enddocument", function(e) { parser.addListener("enddocument", function(e) {
var cursor = backtrackTo(this, exports.css.Tokens.RBRACE, "start"); var end = backtrackTo(this, exports.css.Tokens.RBRACE, "start");
var section = sectionStack.pop(); var section = sectionStack.pop();
addContinuation(section, getRange(section.cursor, cursor)); section.code += getRange(section.start, end);
sectionStack.last.cursor = (++cursor.col, cursor); sectionStack.last.start = (++end.col, end);
doAddSection(section); doAddSection(section);
}); });
parser.addListener("endstylesheet", function() { parser.addListener("endstylesheet", function() {
// add nonclosed (broken) outer sections except for the global one // add nonclosed outer sections (either broken or the last global one)
sectionStack.slice(1).forEach(doAddSection); var endOfText = {line: lines.length, col: lines.last.length + 1};
sectionStack.last.code += getRange(sectionStack.last.start, endOfText);
if (!replaceOldStyle) { sectionStack.forEach(doAddSection);
var lastOldCM = editors[oldSectionCount - 1];
var lastOldSection = lastOldCM.getSection();
var addAfter = {target: lastOldSection.querySelector(".add-section")};
if (oldSectionCount < editors.length
&& lastOldCM.getValue() == ""
&& lastOldSection.querySelector(".applies-to-everything")) {
removeSection(addAfter);
oldSectionCount--;
}
} else {
var addAfter = {target: editors[0].getSection().previousElementSibling.firstElementChild};
}
var globalSection = sectionStack[0];
addContinuation(globalSection,
getRange(sectionStack.last.cursor, {line: lines.length, col: lines.last.length + 1}));
// only add global section if it contains actual code
if (globalSection.code
.replace("@namespace url(http://www.w3.org/1999/xhtml);", "") /* strip boilerplate NS */
.replace(/\/\*[\s\S]*?\*\//g, "") /* strip comments */
.replace(/[\s\n]/g, "")) { /* strip all whitespace including new lines */
setCleanItem(addSection(addAfter, {code: globalSection.code}), false);
}
delete maximizeCodeHeight.stats; delete maximizeCodeHeight.stats;
editors.forEach(function(cm, i) { editors.forEach(function(cm) {
maximizeCodeHeight(cm.getSection(), i == editors.length - 1); maximizeCodeHeight(cm.getSection(), cm == editors.last);
}); });
makeSectionVisible(editors[oldSectionCount]); makeSectionVisible(firstAddedCM);
editors[oldSectionCount].focus(); firstAddedCM.focus();
if (errors) { if (errors) {
showHelp(t("issues"), errors); showHelp(t("issues"), errors);
} }
@ -1412,7 +1394,7 @@ function fromMozillaFormat() {
function getRange(start, end) { function getRange(start, end) {
if (start.line == end.line) { if (start.line == end.line) {
return lines[start.line - 1].substring(start.col - 1, end.col - 1).trim(); return lines[start.line - 1].substr(start.col - 1, end.col - start.col + 1).trim();
} else { } else {
return trimNewLines(lines[start.line - 1].substr(start.col - 1) + "\n" + return trimNewLines(lines[start.line - 1].substr(start.col - 1) + "\n" +
lines.slice(start.line, end.line - 1).join("\n") + lines.slice(start.line, end.line - 1).join("\n") +
@ -1420,13 +1402,36 @@ function fromMozillaFormat() {
} }
} }
function doAddSection(section) { function doAddSection(section) {
if (replaceOldStyle && oldSectionCount > 0) { if (!firstAddedCM) {
oldSectionCount = 0; if (!initFirstSection(section)) {
return;
}
}
// don't add empty sections
if (!(section.code || section.urls || section.urlPrefixes || section.domains || section.regexps)) {
return;
}
setCleanItem(addSection(null, section), false);
firstAddedCM = firstAddedCM || editors.last;
}
// do onetime housekeeping as the imported text is confirmed to be a valid style
function initFirstSection(section) {
// skip adding the first global section when there's no code/comments
if (!section.code.replace("@namespace url(http://www.w3.org/1999/xhtml);", "") /* ignore boilerplate NS */
.replace(/[\s\n]/g, "")) { /* ignore all whitespace including new lines */
return false;
}
if (replaceOldStyle) {
editors.slice(0).reverse().forEach(function(cm) { editors.slice(0).reverse().forEach(function(cm) {
removeSection({target: cm.getSection().firstElementChild}); removeSection({target: cm.getSection().firstElementChild});
}); });
} else if (!editors.last.getValue()) {
// nuke the last blank section
if (editors.last.getSection().querySelector(".applies-to-everything")) {
removeSection({target: editors.last.getSection()});
} }
setCleanItem(addSection(null, section), false); }
return true;
} }
} }
function backtrackTo(parser, tokenType, startEnd) { function backtrackTo(parser, tokenType, startEnd) {
@ -1440,12 +1445,6 @@ function fromMozillaFormat() {
function trimNewLines(s) { function trimNewLines(s) {
return s.replace(/^[\s\n]+/, "").replace(/[\s\n]+$/, ""); return s.replace(/^[\s\n]+/, "").replace(/[\s\n]+$/, "");
} }
function addContinuation(section, addendum) {
section.code = section.code && addendum
? section.code + "\n/**************************/\n" + addendum
: section.code || addendum;
return section.code;
}
} }
function showSectionHelp() { function showSectionHelp() {