做了个文本分列工具
评论 0 热度 155
想在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打不开了,这个也算没白写)
我写的垃圾文本分列工具代码就附在最后吧。
- 值得看看的就是83行的utils对象,里面的bind函数实现了dom内数据的绑定。即用了
Object.defineProperty
来修改varobj
的val
属性的get和set。 - 用了下Prism.js实现高亮。
- 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>
|
<span id="showcodeinFontSize" format="[Font-size: {v}px]">[loading]</span>
<button onclick="varpool.codeinFontSize.val++">Bigger</button>
<button onclick="varpool.codeinFontSize.val--">Smaller</button>
|
<input id="inputlang" placeholder="language" />
|
<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>