2011年6月20日月曜日

走査しながらremove,deleteする時にはまること

また、JavaScriptのremove系メソッドではまったので記録
CSSルールを削除するdeleteRule(idx);
var ss = (function(ss) {
    var dss = document.styleSheets;
    var getRule = function(stylesheet) {
        return stylesheet.cssRules ? stylesheet.cssRules : stylesheet.rules;
    }
    // 全てのcssRuleに対して、iteratorを処理する
    var forEachRule = function(iterator) {
        var some = Array.some;

        return some(dss, function (styleSheet) {
            return some(getRule(styleSheet), function (cssRule, idx, sheet) {
                iterator.call(styleSheet, cssRule, idx, sheet);
            });
        });
    }
    var deleteRule = function(matchSelector) {
        // 引数なし or * の場合、全てのruleを削除する
        if (!matchSelector || matchSelector === "*") {
            matchSelector = true;
        } else if (typeof matchSelector === "string") {
            matchSelector = new RegExp("^" + matchSelector + "$", "i");
        }
        // iteratorを作りcssRuleごとに処理させる
        var iterator = function(cssRule, idx, sheet) {
            var selectorText = cssRule.selectorText;
            if (!selectorText) {
                return;
            }
            var stylesheet = this;
            if (matchSelector.test(selectorText)) {
                //console.log(stylesheet, selectorText, cssRule, idx);
                stylesheet.deleteRule(idx);
            }
        }
        forEachRule(iterator);
    }
    return {
        deleteRule : deleteRule
    }
})(ss || {});
ss.deleteRule(/\.[fc]\d+/i); 
という感じで、渡した正規表現(文字列とかでもいけるようになってるけど工事中)にマッチするセレクタを持っているなら、そのCSSルールを削除する関数を書いていた訳だけど、どうも中途半端に消えたりしていて動作がおかしかった。
コンソールを見てると、1個飛びで消えていたりしたので、replaceChildの注意点 - prog*sigを思い出してた。上の書き方だとsomeで0から順番に走査していたので、deleteRuleする度にindexがずれるので、おかしな結果になっていた。
なので、forで後ろから回すようにした。
var ss = (function(ss) {
    var dss = document.styleSheets;
    var getRule = function(stylesheet) {
        return stylesheet.cssRules ? stylesheet.cssRules : stylesheet.rules;
    }
    // 全てのcssRuleに対して、iteratorを処理する
    var forEachRule = function(iterator) {
        var some = Array.some;

        return some(document.styleSheets, function (styleSheet) {
            var Rules = getRule(styleSheet);
            for (var i = Rules.length - 1; 0 <= i; i--) {
                var cssRule = Rules[i];
                iterator.call(styleSheet, cssRule, i, Rules);
            }
        });
    }
    var deleteRule = function(matchSelector) {
        var skipMatchTest = false;
        // 引数なし or * の場合、全てのruleを削除する
        if (!matchSelector || matchSelector === "*") {
            skipMatchTest = true;
        } else if (typeof matchSelector === "string") {
            matchSelector = new RegExp("^" + matchSelector + "$", "i");
        }
        // iteratorを作りcssRuleごとに処理させる
        var iterator = function(cssRule, idx, sheet) {
            var selectorText = cssRule.selectorText;
            if (!selectorText) { // @importなどは無視
                return;
            }
            var stylesheet = this;
            if (skipMatchTest || matchSelector.test(selectorText)) {
                //console.log(stylesheet, selectorText, cssRule, idx);
                stylesheet.deleteRule(idx);
            }
        }
        forEachRule(iterator);
    }
    return {
        deleteRule : deleteRule
    }
})(ss || {});
ss.deleteRule(/\.[fc]\d+/i);
remove*やdelete*のメソッドを使う機会があんまり無くて、使う度に同じ事にはまってて嫌な気分。
 

0 コメント:

コメントを投稿