【点我打开】

想在WORD里面分列插入代码来缩小占用空间,于是就写了这个工具,通过迭代把文字分成等高的N列(因为考虑到字符不等宽,没法计算如何分割),还加了个代码高亮的功能。但是,等我写完这玩意之后,突然想起来css3里面有个属性就是column,可以直接分列,效果还更好,我捏麻QAQ吐了!!!

如果是用CSS3的column属性,可以直接利用runoob代码高亮,然后用JS设置column属性就能分列了,这里先附带这个功能的JS书签代码,还挺好用。

javascript: (function(){
    if (window.location.host != "c.runoob.com"){
        window.location.href="https://c.runoob.com/front-end/5536/";
    }else{
        var sp = prompt("columns:");
        $("#format_code pre").css({"column-count":sp, "white-space":"pre-wrap", "word-break":"break-all"})
    }
})();

(最近好像runoob打不开了,这个也算没白写)

我写的垃圾文本分列工具代码就附在最后吧。

  1. 值得看看的就是83行的utils对象,里面的bind函数实现了dom内数据的绑定。即用了Object.defineProperty来修改varobjval属性的get和set。
  2. 用了下Prism.js实现高亮。
  3. 119行开始的plotcode函数里面是文本分割的方法,先对文本均匀切几刀放到不同列中,然后渲染出页面,根据不同列的高度差乘以一个越来越小的“动量项”得到的数值来调整切的那一刀的位置,循环多次直到达到最大迭代次数或者最大允许高度差位置就停止。(我把最大允许高度差写死了,实际中可能要根据经验计算出来会比较好)
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Text Sorting tool / 分列排版工具</title>
</head>
<body>

<style>
body{
    font-family: 'times new roman', "微软雅黑", 'STHeiti';
}
#codein{
    min-width: 200px;
    min-height: 100px;
    width: 100%;
    height: 10vh;
    font-family: serif;
    font-size: 12px;
    line-height: 1;
}

</style>

<p>
Help: paste text below and click the [DO IT] button<br />
帮助:在下方粘贴文本并点击[DO IT]按钮即可
</p>

<p>
<span id="showcolcount" format="[Columns: {v}]">[loading]</span>
<button onclick="varpool.colcount.val--;">Less</button>
<button onclick="varpool.colcount.val++;">More</button>
&nbsp;|&nbsp;
<span id="showcodeinFontSize" format="[Font-size: {v}px]">[loading]</span>
<button onclick="varpool.codeinFontSize.val++">Bigger</button>
<button onclick="varpool.codeinFontSize.val--">Smaller</button>
&nbsp;|&nbsp;
<input id="inputlang" placeholder="language" />
&nbsp;|&nbsp;
<button onclick="plotcode();">DO IT</button>
</p>

<textarea id="codein" placeholder="Text here"></textarea>

<div id="out">
    <pre id="outareas"></pre>
    <div style="clear: both"></div>
</div>

<script>
print = console.log;
dbg = 0;


function g(sel){
    return document.querySelectorAll(sel);
}

function listabsmax(list){
    var max = Math.abs(list[0]);
    for (var i = 0; i < list.length; i++){
        if (Math.abs(list[i]) > max){
            max = Math.abs(list[i]);
        }
    }
    return max;
}
function listdiv(list, div){
    for (var i = 0; i < list.length; i++){
        list[i] /= div;
    }
    return list;
}



var varpool = {
    colcount: {val: 3},
    codeinFontSize: {val: 12},
}

var utils = {
    bind: function(dom, varobj, checker = (t=>1), callback = (t=>1)){
        varobj.val_ = varobj.val; // val_ 储存真值 val对外使用
        Object.defineProperty(varobj, 'val', {
            get: function(){return this.val_},
            set: function(val) {
                if (!checker(val)) return;
                this.val_ = val;
                var fmt = dom.attributes['format'];
                if (fmt){
                    let t = fmt.value.replace("{v}", val);
                    dom.innerHTML = t;
                    return;
                }
                dom.innerHTML = val;
                callback(val);
            }
        });
        varobj.val = varobj.val; // :)
    },

}

utils.bind(g("#showcolcount")[0], varpool.colcount, checker=function(t){
    return t < 2 ? !(alert("Columns < 2 !") == undefined) : (1);
});
utils.bind(g("#showcodeinFontSize")[0], varpool.codeinFontSize, checker=function(t){
    if (t < 5){
        alert("Font-size < 5 !");
        return 0;
    }
    g('#out')[0].style.fontSize = t+'px';
    return 1;
});


function plotcode(){
    var splitnum = varpool.colcount.val;
    var outareas = g("#outareas")[0]; 
    var inarea = g("#codein")[0];
    var textin = inarea.value.split('\n');

    var sp_index = []; // sp_index决定在原文哪里切一刀
    var sp_motion = Math.floor(textin.length / splitnum / 2); // "动量"项 更新sp_index时用到
    for (let i = 0; i < splitnum-1; i++) {
        sp_index.push(Math.floor(textin.length / splitnum * (i+1))); // 初步分割
    }

    // 迭代选取最优
    // 根据sp_index放入不同木桶
    function plotit(){
        var bins = [];
        for (let i = 0; i < splitnum; i++) {
            if (i == 0){
                bins.push( textin.slice(0, sp_index[0]).join('\n') );
            }else if(i == splitnum - 1){
                bins.push( textin.slice(sp_index[i-1], textin.length).join('\n') ); // sp比splitnum小1
            }else{
                bins.push( textin.slice(sp_index[i-1], sp_index[i]).join('\n') );
            }
        }

        var classname = "";
        var alllang = g("#inputlang")[0].value.split(' ');
        for (let t = 0; t < alllang.length; t++) {
            classname += "language-"+alllang[t]+" ";
        }

        var colwidth = Math.floor(100/splitnum);
        outareas.innerHTML = "";
        for (let i = 0; i < bins.length; i++) {
            let dom = document.createElement("code");
            dom.setAttribute("class", classname);
            let textnode = document.createTextNode(bins[i]);
            dom.appendChild(textnode);

            dom.style = "white-space: pre-wrap !important; word-break: break-all !important; float: left !important;width: "+colwidth+"%; margin: 0 !important; padding: 0 !important;";

            dom.ondblclick = function(){
                var selection = window.getSelection();
                selection.removeAllRanges();
                var range = document.createRange();
                range.selectNodeContents(this);
                selection.addRange(range);
            }
            outareas.appendChild(dom);
        }

        Prism.highlightAll(); // 放这里会比较好

        var last = 0;
        var diff = []; // 高度差 右边-左边
        var doms = g('#outareas code');
        for (let index = 0; index < doms.length; index++){
            var d = doms[index];
            var h = d.clientHeight;
            if (index == 0){
                last = h;
                continue;
            }
            diff.push(h - last);
            last = h;
        }
        var maxgap = listabsmax(diff);
        diff = listdiv(diff, maxgap);
        return {'diff': diff, 'gap': maxgap};
    }

    var obj = plotit();
    var diff = obj['diff'];
    var maxgap = obj['gap'];
    var maxiteration = 50;
    var acceptGap = 26; // 最大像素差
    while (maxiteration-- > 0 && maxgap > acceptGap){
        for (var i = 0; i < sp_index.length; i++){
            let newsp = sp_index[i] + Math.round(diff[i] * sp_motion); // 更新sp_index
            // 先防止越界
            if (newsp < 1 || newsp > textin.length-1) continue;
            if (i > 0){
                if (newsp < sp_index[i-1]-1) continue;
            }
            if (i < sp_index.length-1){
                if (newsp > sp_index[i+1]+1) continue;
            }
            sp_index[i] = newsp;
            sp_motion = sp_motion / 1.2;
        }
        obj = plotit();
        diff = obj['diff'];
        maxgap = obj['gap'];
    }

    // var allnodes = g("#out pre *");
    // for (var i = 0; i < allnodes.length; i++){
    //     let c = window.getComputedStyle(allnodes[i]).color;
    //     let s = allnodes[i].getAttribute("style");
    //     if (!s) s = '';
    //     allnodes[i].setAttribute("style", s+";color: "+c+";");
    // }
}

</script>

<scirpt src="https://unpkg.com/prismjs@1.29.0/prism.js"></scirp>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<link href="https://unpkg.com/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">

</body>
</html>