// lineBreak.js
/**
 * @file
 * UAで長い半角英数記号文字列が自動途中改行されるように変更する.
 * '.','/','\'の直後、'&','%','-'の直前、更には特定文字数毎に&shy;文字(0xAD)を
 * 挿入する.
 * 但し、&shy;非対応なGeckoの場合は<wbr>を挿入する.
 *
 * @par 使用法
 * 適用する(X)HTML文章のbody要素を閉じる直前にscript要素で参照する.
 *
 * @par このスクリプトについて
 * このスクリプトは、
 * bookmarklet: Wrap! ― 長い1byte文字列を折り返す（Mozilla） - airhead の日記
 * (http://slashdot.jp/journal.pl?op=display&uid=13423&id=270308)
 * の複行リストに手を加えたものである。
 *
 * @par 参考
 * +bookmarklet: Wrap! ― 長い1byte文字列を折り返す（Mozilla） - airhead の日記
 *  http://slashdot.jp/journal.pl?op=display&uid=13423&id=270308
 * +url_breaker - あすかぜ・ねっと
 *  http://www.asukaze.net/soft/url_breaker/
 * +shyなやつ - 徒書
 *  http://www.akatsukinishisu.net/itazuragaki/id/soft_hyphen
 * +長い文字列の改行方法 - wbr, &shy;, css - World Wide Walker
 *  http://yoosee.net/d/archives/2005/01/04/002.html
 *
 * @warning
 * Geckoの場合に非標準要素である<wbr>を入れているので、その場合のみ
 * 処理後の(X)HTML文章はinvalidなものになる.
 * 又、Internet Explorer(ver6.0以下)はNodeFilter.SHOW_TEXTに対応していない為、
 * 動作しない(エラーとなる).
 */
function lineBreak() {
  if(navigator.appName == 'Netscape'){
    // 処理を行う文字列の条件.
    var threshold = new RegExp(/[\x21-\xff]{50}/);
    // 改行許可する条件($1=改行許可直前の文字, $2=改行許可直後の文字)
    var wrapChr = new RegExp(/([\.\/\?])|([&%\-])/g);
    // 処理を行わないHTML要素.
    var avoidElm
        = new RegExp(/SCRIPT|INPUT|TEXTAREA|OPTION|PRE|XMP|PLAINTEXT/);
    // 必ず改行許可を与える文字数.
    var lineMin = 16;

    var walker = document.createTreeWalker(
        document.body, NodeFilter.SHOW_TEXT, null, true);

    while (cNode = walker.nextNode()) {
        s1 = cNode.nodeValue;
        pNode = cNode.parentNode;
        pNodeName = pNode.nodeName;

        if (!pNodeName.match(avoidElm) && s1.match(threshold)) {
            s1 = s1.replace(wrapChr, '$1<dummyWBR>$2');
            s2 = s1.split('<dummyWBR>');

            // 長い文字列は分割
            for(var i = 0; i < s2.length; i++) {
                var s2Sub;
                if(s2[i].length > lineMin) {
                    var s2Current = s2[i];
                    var s2Tail = s2.slice(i + 1);   // 最後NULLになる?
                    s2 = s2.slice(0, i);
                    var partsNum = parseInt(s2Current.length / lineMin)
                        + ((s2Current.length % lineMin) != 0);
                    s2Sub = new Array(partsNum);
                    for(var j = 0; j < partsNum; j++) {
                        s2Sub[j] = s2Current.substr(lineMin * j, lineMin);
                    }
                    s2 = s2.concat(s2Sub);
                    s2 = s2.concat(s2Tail);

                    i += (s2Sub.length - 1);    // forカウンタ分マイナス
                }
            }

            cNode.nodeValue = s2.pop();

            for (i=0; i<s2.length; i++) {
                nNode = document.createTextNode(s2[i]);
                pNode.insertBefore(nNode, cNode);

                // UA別に処理を振り分け
                if(navigator.userAgent.indexOf("Gecko") == -1) {
                    nNode = document.createTextNode("\xad");    // &shy;
                } else {
                    nNode = document.createElement('WBR');
                }
                pNode.insertBefore(nNode, cNode);
            }
        }
    }

    // ページ再計算をさせる為にwidthを定義しなおす.
    var width = document.body.style.width;
    if(!width) width = '99%';   // 100%だと横に長くなるので
    document.body.style.width = width;
    focus();
  }
}