View Single Post
Old 08-11-2015, 10:47 PM   #37
dgatwood
Curmudgeon
dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.dgatwood ought to be getting tired of karma fortunes by now.
 
dgatwood's Avatar
 
Posts: 629
Karma: 1623086
Join Date: Jan 2012
Device: iPad, iPhone, Nook Simple Touch
Quote:
Originally Posted by mattmc View Post
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()
{
}
dgatwood is offline   Reply With Quote