Quote:
Originally Posted by mattmc
Heh. I may have to build this, because I have all my processing scripts in JS and I actually need to confront making sure I have my ducks in a row for KF7. Maybe in a few days I'll get to it, I'm tied up right now.
Question: It seems like you could do point #4 first, and then you'd only have to do point #2 once. Right?
|
I think so, now that you mention it. At least I can't think of any cases where that wouldn't work.
For fun, I took a crack at #2 and #3 last week. I ran into a bit of a wall where I couldn't do anything useful with the results from within a web browser, and I also ran into some data loss because Safari's CSS objects only include the bits that Safari uses, and leaves out properties that are specific to other browsers, but it might be useful as a starting point.
Code:
function translate() {
changed = false;
do {
fixup_multi_class_elements();
fixup_complex_styles();
} while (changed);
}
function fixup_multi_class_elements()
{
var changed = false;
var CSSClassMap = new Array();
var nodeIterator = document.createNodeIterator(document,
NodeFilter.SHOW_ELEMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false);
while (currentNode = nodeIterator.nextNode()) {
if (currentNode.className.match(/\S\s\S/)) {
/* Multiple words separated by a space. */
var bits = currentNode.className.split(/\s/).sort()
var newCSSName = bits.join().replace(/\s/, "");
for (var bitnum in bits) {
var bit = bits[bitnum];
if (!CSSClassMap[bit]) {
CSSClassMap[bit] = new Array();
}
CSSClassMap[bit].push(newCSSName);
}
currentNode.className = newCSSName;
changed = true;
}
}
var replacements = new Array();
var stylesheets = document.styleSheets;
for (var stylesheet = 0; stylesheet < stylesheets.length; stylesheet++)
{
var newRules = new Array();
var stylesheet = document.styleSheets[stylesheet];
var pos = 0;
for (var i = 0; i < stylesheet.cssRules.length; i++)
{
var rule = stylesheet.cssRules[i];
if (rule.type == CSSRule.MEDIA_RULE) {
// CSS media rule
alert("Media rules not implemented yet.\n");
newRules.push(constructStyleRule(null, rule.cssText))
// Eventually, need to iterate the child rules, and
// build a new rule.
} else if (rule.type == CSSRule.STYLE_RULE) {
var newrule = combinedClassRules(rule, CSSClassMap);
newRules.push(constructStyleRule(newrule["selector"], newrule["style"]))
} else {
// Just add the rule.
newRules.push(constructStyleRule(null, rule.cssText));
}
}
while (stylesheet.cssRules.length) {
stylesheet.deleteRule(0);
}
var newStylesheet = "";
var pos = 0;
for (var i=0; i < newRules.length; i++) {
var newrule = newRules[i];
//console.log("INSERTING RULE\n"); console.log(newrule);
// stylesheet.insertRule(newrule["selector"], newrule["style"], i);
if (newrule["selector"]) {
newStylesheet += "\n"+newrule["selector"]+"\n{\n"+newrule["style"]+"\n}\n";
} else {
newStylesheet += "\n"+newrule["style"]+"\n";
}
}
console.log(newStylesheet);
}
}
function constructStyleRule(selectorString, ruleString)
{
return {
"selector": selectorString,
"style": ruleString + ""
};
}
function combinedClassRules(rule, CSSClassMap)
{
var selector = rule.selectorText;
var parts = selector.split(",");
var newSelectors = new Array();
// console.log("PARTS:"); console.log(parts);
for (var partnum in parts) {
var part = parts[partnum];
// console.log("PART: "+part);
if (part.match(/\S/)) {
var replacedSelectors = mapSelectors(part, CSSClassMap)
if (replacedSelectors.length) newSelectors.push(replacedSelectors);
newSelectors.push(part);
}
}
return constructStyleRule(newSelectors.join(","), rule.style.cssText);
}
function classesAndIDsInSelector(selector, CSSClassMap)
{
var parts = selector.split(/[#.]/).slice(1);
var classes = new Array();
for (partnum in parts) {
var part = parts[partnum];
// -?[_a-zA-Z]+[_a-zA-Z0-9-]*
var possibleClassOrID = part.replace(/^\s*/, "").replace(/(\s|[#.>+~[]).*$/, "");
if (possibleClassOrID.length) {
/* Valid class or ID */
classes.push(possibleClassOrID);
}
}
// console.log("SEL "+selector+" contains "+classes.join(","));
return classes;
}
function mapSelectors(selector, CSSClassMap)
{
var candidates = classesAndIDsInSelector(selector, CSSClassMap);
var tempArray = new Array();
for (var oldClassNum in candidates) {
var oldClass = candidates[oldClassNum];
var newClasses = CSSClassMap[oldClass];
if (newClasses) {
for (var newClassNum in newClasses) {
var newClass = newClasses[newClassNum];
tempArray.push(replaceClassInSelector(selector, oldClass, newClass));
}
}
}
return tempArray.join(",");
}
/* From http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex */
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function replaceClassInSelector(selector, oldClass, newClass)
{
var quoted = escapeRegExp(oldClass);
var searchRE = new RegExp("([#.])"+quoted+"(?=$|\s|[#.>+~[])", "g");
return selector.replace(searchRE, "$1"+newClass);
}
function fixup_complex_styles()
{
}