【点我打开】

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

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

1
2
3
4
5
6
7
8
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函数里面是文本分割的方法,先对文本均匀切几刀放到不同列中,然后渲染出页面,根据不同列的高度差乘以一个越来越小的“动量项”得到的数值来调整切的那一刀的位置,循环多次直到达到最大迭代次数或者最大允许高度差位置就停止。(我把最大允许高度差写死了,实际中可能要根据经验计算出来会比较好)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
<!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>