wikiparser-node 1.0.0-beta.4 → 1.0.1-b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -9
- package/bundle/bundle.min.js +37 -0
- package/config/llwiki.json +1 -35
- package/config/moegirl.json +1 -44
- package/config/zhwiki.json +1 -466
- package/extensions/dist/base.js +105 -0
- package/extensions/dist/editor.js +172 -0
- package/extensions/dist/highlight.js +46 -0
- package/extensions/dist/lint.js +43 -0
- package/extensions/editor.css +63 -0
- package/extensions/ui.css +119 -0
- package/package.json +29 -16
- package/config/.schema.json +0 -160
- package/dist/index.d.ts +0 -62
- package/dist/index.js +0 -305
- package/dist/internal.d.ts +0 -44
- package/dist/lib/element.d.ts +0 -190
- package/dist/lib/element.js +0 -674
- package/dist/lib/node.d.ts +0 -178
- package/dist/lib/node.js +0 -457
- package/dist/lib/range.d.ts +0 -132
- package/dist/lib/range.js +0 -384
- package/dist/lib/ranges.d.ts +0 -28
- package/dist/lib/ranges.js +0 -125
- package/dist/lib/text.d.ts +0 -78
- package/dist/lib/text.js +0 -227
- package/dist/lib/title.d.ts +0 -34
- package/dist/lib/title.js +0 -111
- package/dist/mixin/attributesParent.js +0 -93
- package/dist/mixin/fixed.js +0 -32
- package/dist/mixin/hidden.js +0 -23
- package/dist/mixin/singleLine.js +0 -26
- package/dist/mixin/sol.js +0 -44
- package/dist/parser/braces.js +0 -120
- package/dist/parser/commentAndExt.js +0 -64
- package/dist/parser/converter.js +0 -39
- package/dist/parser/externalLinks.js +0 -27
- package/dist/parser/hrAndDoubleUnderscore.js +0 -37
- package/dist/parser/html.js +0 -35
- package/dist/parser/links.js +0 -93
- package/dist/parser/list.js +0 -58
- package/dist/parser/magicLinks.js +0 -39
- package/dist/parser/quotes.js +0 -66
- package/dist/parser/selector.js +0 -162
- package/dist/parser/table.js +0 -108
- package/dist/src/arg.d.ts +0 -78
- package/dist/src/arg.js +0 -203
- package/dist/src/atom.d.ts +0 -12
- package/dist/src/atom.js +0 -24
- package/dist/src/attribute.d.ts +0 -107
- package/dist/src/attribute.js +0 -446
- package/dist/src/attributes.d.ts +0 -120
- package/dist/src/attributes.js +0 -360
- package/dist/src/converter.d.ts +0 -76
- package/dist/src/converter.js +0 -134
- package/dist/src/converterFlags.d.ts +0 -108
- package/dist/src/converterFlags.js +0 -237
- package/dist/src/converterRule.d.ts +0 -97
- package/dist/src/converterRule.js +0 -253
- package/dist/src/extLink.d.ts +0 -64
- package/dist/src/extLink.js +0 -156
- package/dist/src/gallery.d.ts +0 -72
- package/dist/src/gallery.js +0 -133
- package/dist/src/heading.d.ts +0 -84
- package/dist/src/heading.js +0 -134
- package/dist/src/hidden.d.ts +0 -20
- package/dist/src/hidden.js +0 -26
- package/dist/src/html.d.ts +0 -115
- package/dist/src/html.js +0 -247
- package/dist/src/imageParameter.d.ts +0 -83
- package/dist/src/imageParameter.js +0 -255
- package/dist/src/imagemap.d.ts +0 -79
- package/dist/src/imagemap.js +0 -164
- package/dist/src/imagemapLink.d.ts +0 -49
- package/dist/src/imagemapLink.js +0 -39
- package/dist/src/index.d.ts +0 -157
- package/dist/src/index.js +0 -818
- package/dist/src/link/base.d.ts +0 -70
- package/dist/src/link/base.js +0 -229
- package/dist/src/link/category.d.ts +0 -14
- package/dist/src/link/category.js +0 -29
- package/dist/src/link/file.d.ts +0 -106
- package/dist/src/link/file.js +0 -271
- package/dist/src/link/galleryImage.d.ts +0 -37
- package/dist/src/link/galleryImage.js +0 -101
- package/dist/src/link/index.d.ts +0 -50
- package/dist/src/link/index.js +0 -136
- package/dist/src/magicLink.d.ts +0 -47
- package/dist/src/magicLink.js +0 -130
- package/dist/src/nested.d.ts +0 -49
- package/dist/src/nested.js +0 -88
- package/dist/src/nowiki/base.d.ts +0 -39
- package/dist/src/nowiki/base.js +0 -31
- package/dist/src/nowiki/comment.d.ts +0 -43
- package/dist/src/nowiki/comment.js +0 -62
- package/dist/src/nowiki/dd.d.ts +0 -22
- package/dist/src/nowiki/dd.js +0 -47
- package/dist/src/nowiki/doubleUnderscore.d.ts +0 -37
- package/dist/src/nowiki/doubleUnderscore.js +0 -48
- package/dist/src/nowiki/hr.d.ts +0 -24
- package/dist/src/nowiki/hr.js +0 -29
- package/dist/src/nowiki/index.d.ts +0 -20
- package/dist/src/nowiki/index.js +0 -24
- package/dist/src/nowiki/list.d.ts +0 -16
- package/dist/src/nowiki/list.js +0 -14
- package/dist/src/nowiki/noinclude.d.ts +0 -21
- package/dist/src/nowiki/noinclude.js +0 -25
- package/dist/src/nowiki/quote.d.ts +0 -20
- package/dist/src/nowiki/quote.js +0 -66
- package/dist/src/onlyinclude.d.ts +0 -39
- package/dist/src/onlyinclude.js +0 -66
- package/dist/src/paramTag/index.d.ts +0 -52
- package/dist/src/paramTag/index.js +0 -78
- package/dist/src/paramTag/inputbox.d.ts +0 -8
- package/dist/src/paramTag/inputbox.js +0 -22
- package/dist/src/parameter.d.ts +0 -96
- package/dist/src/parameter.js +0 -203
- package/dist/src/pre.d.ts +0 -29
- package/dist/src/pre.js +0 -49
- package/dist/src/syntax.d.ts +0 -23
- package/dist/src/syntax.js +0 -67
- package/dist/src/table/base.d.ts +0 -61
- package/dist/src/table/base.js +0 -78
- package/dist/src/table/index.d.ts +0 -248
- package/dist/src/table/index.js +0 -782
- package/dist/src/table/td.d.ts +0 -121
- package/dist/src/table/td.js +0 -267
- package/dist/src/table/tr.d.ts +0 -32
- package/dist/src/table/tr.js +0 -51
- package/dist/src/table/trBase.d.ts +0 -62
- package/dist/src/table/trBase.js +0 -157
- package/dist/src/tagPair/ext.d.ts +0 -55
- package/dist/src/tagPair/ext.js +0 -138
- package/dist/src/tagPair/include.d.ts +0 -43
- package/dist/src/tagPair/include.js +0 -42
- package/dist/src/tagPair/index.d.ts +0 -57
- package/dist/src/tagPair/index.js +0 -107
- package/dist/src/transclude.d.ts +0 -201
- package/dist/src/transclude.js +0 -727
- package/dist/util/debug.js +0 -42
- package/dist/util/diff.js +0 -71
- package/dist/util/lint.js +0 -48
- package/dist/util/string.js +0 -75
- package/errors/README +0 -1
- package/printed/README +0 -1
package/dist/src/table/index.js
DELETED
|
@@ -1,782 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TableToken = void 0;
|
|
4
|
-
const assert = require("assert/strict");
|
|
5
|
-
const lint_1 = require("../../util/lint");
|
|
6
|
-
const string_1 = require("../../util/string");
|
|
7
|
-
const Parser = require("../../index");
|
|
8
|
-
const __1 = require("..");
|
|
9
|
-
const tr_1 = require("./tr");
|
|
10
|
-
const trBase_1 = require("./trBase");
|
|
11
|
-
const td_1 = require("./td");
|
|
12
|
-
const syntax_1 = require("../syntax");
|
|
13
|
-
const closingPattern = /^\n[^\S\n]*(?:\|\}|\{\{\s*!\s*\}\}\}|\{\{\s*!\)\s*\}\})$/u;
|
|
14
|
-
/**
|
|
15
|
-
* 比较两个表格坐标
|
|
16
|
-
* @param coords1 坐标1
|
|
17
|
-
* @param coords2 坐标2
|
|
18
|
-
*/
|
|
19
|
-
const cmpCoords = (coords1, coords2) => {
|
|
20
|
-
const diff = coords1.row - coords2.row;
|
|
21
|
-
return diff === 0 ? coords1.column - coords2.column : diff;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* 是否是行尾
|
|
25
|
-
* @param {Token} cell 表格单元格
|
|
26
|
-
*/
|
|
27
|
-
const isRowEnd = ({ type }) => type === 'tr' || type === 'table-syntax';
|
|
28
|
-
/**
|
|
29
|
-
* 是否是合并单元格的第一列
|
|
30
|
-
* @param rowLayout 行布局
|
|
31
|
-
* @param i 单元格序号
|
|
32
|
-
* @param oneCol 是否仅有一列
|
|
33
|
-
*/
|
|
34
|
-
const isStartCol = (rowLayout, i, oneCol = false) => {
|
|
35
|
-
const coords = rowLayout[i];
|
|
36
|
-
return rowLayout[i - 1] !== coords && (!oneCol || rowLayout[i + 1] !== coords);
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* 设置表格格式
|
|
40
|
-
* @param cells 单元格
|
|
41
|
-
* @param attr 属性
|
|
42
|
-
* @param multi 是否对所有单元格设置,或是仅对行首单元格设置
|
|
43
|
-
*/
|
|
44
|
-
const format = (cells, attr = {}, multi = false) => {
|
|
45
|
-
for (const [token, start] of cells) {
|
|
46
|
-
if (multi || start) {
|
|
47
|
-
if (typeof attr === 'string') {
|
|
48
|
-
token.setSyntax(attr);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
for (const [k, v] of Object.entries(attr)) {
|
|
52
|
-
token.setAttr(k, v);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* 填补缺失单元格
|
|
60
|
-
* @param y 行号
|
|
61
|
-
* @param rowToken 表格行
|
|
62
|
-
* @param layout 表格布局
|
|
63
|
-
* @param maxCol 最大列数
|
|
64
|
-
* @param token 待填充的单元格
|
|
65
|
-
*/
|
|
66
|
-
const fill = (y, rowToken, layout, maxCol, token) => {
|
|
67
|
-
const rowLayout = layout[y], lastIndex = rowToken.childNodes.findLastIndex(child => child instanceof td_1.TdToken && child.subtype !== 'caption'), pos = lastIndex + 1 || undefined;
|
|
68
|
-
Parser.run(() => {
|
|
69
|
-
for (let i = 0; i < maxCol; i++) {
|
|
70
|
-
if (!rowLayout[i]) {
|
|
71
|
-
rowToken.insertAt(token.cloneNode(), pos);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
};
|
|
76
|
-
/** @extends {Array<TableCoords[]>} */
|
|
77
|
-
class Layout extends Array {
|
|
78
|
-
/** 打印表格布局 */
|
|
79
|
-
print() {
|
|
80
|
-
const hBorders = new Array(this.length + 1).fill(undefined).map((_, i) => {
|
|
81
|
-
const prev = this[i - 1] ?? [], next = this[i] ?? [];
|
|
82
|
-
return new Array(Math.max(prev.length, next.length)).fill(undefined)
|
|
83
|
-
.map((__, j) => prev[j] !== next[j]);
|
|
84
|
-
}), vBorders = this.map(cur => new Array(cur.length + 1).fill(undefined).map((_, j) => cur[j - 1] !== cur[j]));
|
|
85
|
-
let out = '';
|
|
86
|
-
for (let i = 0; i <= this.length; i++) {
|
|
87
|
-
const hBorder = hBorders[i].map(Number), vBorderTop = (vBorders[i - 1] ?? []).map(Number), vBorderBottom = (vBorders[i] ?? []).map(Number),
|
|
88
|
-
// eslint-disable-next-line no-sparse-arrays
|
|
89
|
-
border = [' ', , , '┌', , '┐', '─', '┬', , '│', '└', '├', '┘', '┤', '┴', '┼'];
|
|
90
|
-
for (let j = 0; j <= hBorder.length; j++) {
|
|
91
|
-
const bit = (vBorderTop[j] << 3) + (vBorderBottom[j] << 0)
|
|
92
|
-
+ (hBorder[j - 1] << 2) + (hBorder[j] << 1);
|
|
93
|
-
out += `${border[bit]}${hBorder[j] ? '─' : ' '}`;
|
|
94
|
-
}
|
|
95
|
-
out += '\n';
|
|
96
|
-
}
|
|
97
|
-
console.log(out.slice(0, -1));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* 表格
|
|
102
|
-
* @classdesc `{childNodes: [SyntaxToken, AttributesToken, ?Token, ...TdToken, ...TrToken, ?SyntaxToken]}`
|
|
103
|
-
*/
|
|
104
|
-
// @ts-expect-error not implementing all abstract methods
|
|
105
|
-
class TableToken extends trBase_1.TrBaseToken {
|
|
106
|
-
/** @browser */
|
|
107
|
-
type = 'table';
|
|
108
|
-
/**
|
|
109
|
-
* 表格是否闭合
|
|
110
|
-
* @browser
|
|
111
|
-
*/
|
|
112
|
-
get closed() {
|
|
113
|
-
return this.lastChild.type === 'table-syntax';
|
|
114
|
-
}
|
|
115
|
-
set closed(closed) {
|
|
116
|
-
if (closed && !this.closed) {
|
|
117
|
-
this.close(this.closest('parameter') ? '\n{{!)}}' : '\n|}');
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* @browser
|
|
122
|
-
* @param syntax 表格语法
|
|
123
|
-
* @param attr 表格属性
|
|
124
|
-
*/
|
|
125
|
-
constructor(syntax, attr, config = Parser.getConfig(), accum = []) {
|
|
126
|
-
super(/^(?:\{\||\{\{\{\s*!\s*\}\}|\{\{\s*\(!\s*\}\})$/u, syntax, attr, config, accum, {
|
|
127
|
-
Token: 2, SyntaxToken: [0, -1], AttributesToken: 1, TdToken: '2:', TrToken: '2:',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* @override
|
|
132
|
-
* @browser
|
|
133
|
-
*/
|
|
134
|
-
lint(start = this.getAbsoluteIndex()) {
|
|
135
|
-
const errors = super.lint(start);
|
|
136
|
-
if (!this.closed) {
|
|
137
|
-
const { firstChild, lastChild: tr } = this, { lastChild: td } = tr, error = (0, lint_1.generateForChild)(firstChild, { start }, 'unclosed table');
|
|
138
|
-
errors.push({ ...error, excerpt: String(td?.type === 'td' ? td : tr).slice(0, 50) });
|
|
139
|
-
}
|
|
140
|
-
return errors;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* 闭合表格语法
|
|
144
|
-
* @browser
|
|
145
|
-
* @param syntax 表格结尾语法
|
|
146
|
-
* @param halfParsed
|
|
147
|
-
* @throws `SyntaxError` 表格的闭合部分不符合语法
|
|
148
|
-
*/
|
|
149
|
-
close(syntax = '\n|}', halfParsed = false) {
|
|
150
|
-
halfParsed &&= Parser.running;
|
|
151
|
-
const config = this.getAttribute('config'), accum = this.getAttribute('accum'), inner = !halfParsed && Parser.parse(syntax, this.getAttribute('include'), 2, config), { lastChild } = this;
|
|
152
|
-
if (inner && !closingPattern.test(inner.text())) {
|
|
153
|
-
throw new SyntaxError(`表格的闭合部分不符合语法:${(0, string_1.noWrap)(syntax)}`);
|
|
154
|
-
}
|
|
155
|
-
else if (lastChild instanceof syntax_1.SyntaxToken) {
|
|
156
|
-
lastChild.replaceChildren(...inner.childNodes);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
super.insertAt(Parser.run(() => {
|
|
160
|
-
const token = new syntax_1.SyntaxToken(syntax, closingPattern, 'table-syntax', config, accum, {
|
|
161
|
-
'Stage-1': ':', '!ExtToken': '', TranscludeToken: ':',
|
|
162
|
-
});
|
|
163
|
-
if (inner) {
|
|
164
|
-
token.replaceChildren(...inner.childNodes);
|
|
165
|
-
}
|
|
166
|
-
return token;
|
|
167
|
-
}));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* @override
|
|
172
|
-
* @param token 待插入的子节点
|
|
173
|
-
* @param i 插入位置
|
|
174
|
-
* @throws `SyntaxError` 表格的闭合部分非法
|
|
175
|
-
*/
|
|
176
|
-
insertAt(token, i = this.length) {
|
|
177
|
-
const previous = this.childNodes.at(i - 1);
|
|
178
|
-
if (typeof token !== 'string' && token.type === 'td' && previous?.type === 'tr') {
|
|
179
|
-
Parser.warn('改为将单元格插入当前行。');
|
|
180
|
-
return previous.insertAt(token);
|
|
181
|
-
}
|
|
182
|
-
else if (i > 0 && i === this.length && token instanceof syntax_1.SyntaxToken
|
|
183
|
-
&& (token.getAttribute('pattern') !== closingPattern || !closingPattern.test(token.text()))) {
|
|
184
|
-
throw new SyntaxError(`表格的闭合部分不符合语法:${(0, string_1.noWrap)(String(token))}`);
|
|
185
|
-
}
|
|
186
|
-
return super.insertAt(token, i);
|
|
187
|
-
}
|
|
188
|
-
/** @override */
|
|
189
|
-
getRowCount() {
|
|
190
|
-
return super.getRowCount() + this.childNodes.filter(child => child.type === 'tr' && child.getRowCount()).length;
|
|
191
|
-
}
|
|
192
|
-
/** 获取下一行 */
|
|
193
|
-
getNextRow() {
|
|
194
|
-
return this.getNthRow(super.getRowCount() ? 1 : 0, false, false);
|
|
195
|
-
}
|
|
196
|
-
/** @ignore */
|
|
197
|
-
getNthRow(n, force = false, insert = false) {
|
|
198
|
-
const nRows = this.getRowCount(), isRow = super.getRowCount();
|
|
199
|
-
n += n < 0 ? nRows : 0;
|
|
200
|
-
if (n === 0 && (isRow || force && nRows === 0)) {
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
|
-
else if (n < 0 || n > nRows || n === nRows && !insert) {
|
|
204
|
-
throw new RangeError(`不存在第 ${n} 行!`);
|
|
205
|
-
}
|
|
206
|
-
else if (isRow) {
|
|
207
|
-
n--;
|
|
208
|
-
}
|
|
209
|
-
for (const child of this.childNodes.slice(2)) {
|
|
210
|
-
if (child.type === 'tr' && child.getRowCount()) {
|
|
211
|
-
n--;
|
|
212
|
-
if (n < 0) {
|
|
213
|
-
return child;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
else if (child.type === 'table-syntax') {
|
|
217
|
-
return child;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return undefined;
|
|
221
|
-
}
|
|
222
|
-
/** 获取所有行 */
|
|
223
|
-
getAllRows() {
|
|
224
|
-
return [
|
|
225
|
-
...super.getRowCount() ? [this] : [],
|
|
226
|
-
...this.childNodes.slice(1).filter(child => child.type === 'tr' && child.getRowCount()),
|
|
227
|
-
];
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* 获取指定坐标的单元格
|
|
231
|
-
* @param coords 表格坐标
|
|
232
|
-
*/
|
|
233
|
-
getNthCell(coords) {
|
|
234
|
-
const rawCoords = coords.row === undefined ? this.toRawCoords(coords) : coords;
|
|
235
|
-
return rawCoords && this.getNthRow(rawCoords.row, false, false)?.getNthCol(rawCoords.column);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* 获取表格布局
|
|
239
|
-
* @param stop 中止条件
|
|
240
|
-
* @param stop.row 中止行
|
|
241
|
-
* @param stop.column 中止列
|
|
242
|
-
* @param stop.x 中止行
|
|
243
|
-
* @param stop.y 中止列
|
|
244
|
-
*/
|
|
245
|
-
getLayout(stop) {
|
|
246
|
-
const rows = this.getAllRows(), { length } = rows, layout = new Layout(...new Array(length).fill(undefined).map(() => []));
|
|
247
|
-
for (let i = 0; i < length; i++) {
|
|
248
|
-
if (i > (stop?.row ?? stop?.y ?? NaN)) {
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
const rowLayout = layout[i];
|
|
252
|
-
let j = 0, k = 0, last;
|
|
253
|
-
for (const cell of rows[i].childNodes.slice(2)) {
|
|
254
|
-
if (cell instanceof td_1.TdToken) {
|
|
255
|
-
if (cell.isIndependent()) {
|
|
256
|
-
last = cell.subtype !== 'caption';
|
|
257
|
-
}
|
|
258
|
-
if (last) {
|
|
259
|
-
const coords = { row: i, column: j }, { rowspan, colspan } = cell;
|
|
260
|
-
j++;
|
|
261
|
-
while (rowLayout[k]) {
|
|
262
|
-
k++;
|
|
263
|
-
}
|
|
264
|
-
if (i === stop?.row && j > (stop.column ?? NaN)) {
|
|
265
|
-
layout[i][k] = coords;
|
|
266
|
-
return layout;
|
|
267
|
-
}
|
|
268
|
-
for (let y = i; y < Math.min(i + rowspan, length); y++) {
|
|
269
|
-
for (let x = k; x < k + colspan; x++) {
|
|
270
|
-
layout[y][x] = coords;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
k += colspan;
|
|
274
|
-
if (i === stop?.y && k > (stop.x ?? NaN)) {
|
|
275
|
-
return layout;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
else if (isRowEnd(cell)) {
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return layout;
|
|
285
|
-
}
|
|
286
|
-
/** 打印表格布局 */
|
|
287
|
-
printLayout() {
|
|
288
|
-
this.getLayout().print();
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* 转换为渲染后的表格坐标
|
|
292
|
-
* @param {TableCoords} coord wikitext中的表格坐标
|
|
293
|
-
*/
|
|
294
|
-
toRenderedCoords({ row, column }) {
|
|
295
|
-
const rowLayout = this.getLayout({ row, column })[row], x = rowLayout?.findIndex(coords => cmpCoords(coords, { row, column }) === 0);
|
|
296
|
-
return rowLayout && (x === -1 ? undefined : { y: row, x: x });
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* 转换为wikitext中的表格坐标
|
|
300
|
-
* @param {TableRenderedCoords} coord 渲染后的表格坐标
|
|
301
|
-
*/
|
|
302
|
-
toRawCoords({ x, y }) {
|
|
303
|
-
const rowLayout = this.getLayout({ x, y })[y], coords = rowLayout?.[x];
|
|
304
|
-
if (coords) {
|
|
305
|
-
return { ...coords, start: coords.row === y && rowLayout[x - 1] !== coords };
|
|
306
|
-
}
|
|
307
|
-
else if (rowLayout || y > 0) {
|
|
308
|
-
return x === rowLayout?.length
|
|
309
|
-
? { row: y, column: (rowLayout.findLast(({ row }) => row === y)?.column ?? -1) + 1, start: true }
|
|
310
|
-
: undefined;
|
|
311
|
-
}
|
|
312
|
-
return { row: 0, column: 0, start: true };
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* 获取完整行
|
|
316
|
-
* @param y 行号
|
|
317
|
-
*/
|
|
318
|
-
getFullRow(y) {
|
|
319
|
-
const rows = this.getAllRows();
|
|
320
|
-
return new Map(this.getLayout({ y })[y]?.map(({ row, column }) => [rows[row].getNthCol(column), row === y]));
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* 获取完整列
|
|
324
|
-
* @param x 列号
|
|
325
|
-
*/
|
|
326
|
-
getFullCol(x) {
|
|
327
|
-
const layout = this.getLayout(), colLayout = layout.map(row => row[x]).filter(Boolean), rows = this.getAllRows();
|
|
328
|
-
return new Map(colLayout.map(coords => [rows[coords.row].getNthCol(coords.column), layout[coords.row][x - 1] !== coords]));
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* 设置行格式
|
|
332
|
-
* @param y 行号
|
|
333
|
-
* @param attr 表格属性
|
|
334
|
-
* @param multiRow 是否对所有单元格设置,或是仅对行首单元格设置
|
|
335
|
-
*/
|
|
336
|
-
formatTableRow(y, attr = {}, multiRow = false) {
|
|
337
|
-
format(this.getFullRow(y), attr, multiRow);
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* 设置列格式
|
|
341
|
-
* @param x 列号
|
|
342
|
-
* @param attr 表格属性
|
|
343
|
-
* @param multiCol 是否对所有单元格设置,或是仅对行首单元格设置
|
|
344
|
-
*/
|
|
345
|
-
formatTableCol(x, attr = {}, multiCol = false) {
|
|
346
|
-
format(this.getFullCol(x), attr, multiCol);
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* 填补表格行
|
|
350
|
-
* @param y 行号
|
|
351
|
-
* @param inner 填充内容
|
|
352
|
-
* @param subtype 单元格类型
|
|
353
|
-
* @param attr 表格属性
|
|
354
|
-
*/
|
|
355
|
-
fillTableRow(y, inner, subtype = 'td', attr = {}) {
|
|
356
|
-
const rowToken = this.getNthRow(y), layout = this.getLayout({ y }), maxCol = Math.max(...layout.map(({ length }) => length)), token = td_1.TdToken.create(inner, subtype, attr, this.getAttribute('include'), this.getAttribute('config'));
|
|
357
|
-
fill(y, rowToken, layout, maxCol, token);
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* 填补表格
|
|
361
|
-
* @param inner 填充内容
|
|
362
|
-
* @param subtype 单元格类型
|
|
363
|
-
* @param attr 表格属性
|
|
364
|
-
*/
|
|
365
|
-
fillTable(inner, subtype = 'td', attr = {}) {
|
|
366
|
-
const rowTokens = this.getAllRows(), layout = this.getLayout(), maxCol = Math.max(...layout.map(({ length }) => length)), token = td_1.TdToken.create(inner, subtype, attr, this.getAttribute('include'), this.getAttribute('config'));
|
|
367
|
-
for (let y = 0; y < rowTokens.length; y++) {
|
|
368
|
-
fill(y, rowTokens[y], layout, maxCol, token);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* @override
|
|
373
|
-
* @param inner 单元格内部wikitext
|
|
374
|
-
* @param coords 单元格坐标
|
|
375
|
-
* @param subtype 单元格类型
|
|
376
|
-
* @param attr 单元格属性
|
|
377
|
-
* @throws `RangeError` 指定的坐标不是单元格起始点
|
|
378
|
-
*/
|
|
379
|
-
insertTableCell(inner, coords, subtype = 'td', attr = {}) {
|
|
380
|
-
let rawCoords;
|
|
381
|
-
if (coords.column === undefined) {
|
|
382
|
-
const { x, y } = coords;
|
|
383
|
-
rawCoords = this.toRawCoords(coords);
|
|
384
|
-
if (!rawCoords?.start) {
|
|
385
|
-
throw new RangeError(`指定的坐标不是单元格起始点:(${x}, ${y})`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
rawCoords = coords;
|
|
390
|
-
}
|
|
391
|
-
const rowToken = this.getNthRow(rawCoords.row, true);
|
|
392
|
-
return rowToken === this
|
|
393
|
-
? super.insertTableCell(inner, rawCoords, subtype, attr)
|
|
394
|
-
: rowToken.insertTableCell(inner, rawCoords, subtype, attr);
|
|
395
|
-
}
|
|
396
|
-
/** 在开头插入一行 */
|
|
397
|
-
#prependTableRow() {
|
|
398
|
-
const row = Parser.run(() => new tr_1.TrToken('\n|-', undefined, this.getAttribute('config'))), { childNodes } = this, [, , plain] = childNodes,
|
|
399
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
400
|
-
start = plain?.constructor === __1.Token ? 3 : 2, tdChildren = childNodes.slice(start), index = tdChildren.findIndex(({ type }) => type !== 'td');
|
|
401
|
-
this.insertAt(row, index === -1 ? -1 : index + start);
|
|
402
|
-
Parser.run(() => {
|
|
403
|
-
for (const cell of tdChildren.slice(0, index === -1 ? undefined : index)) {
|
|
404
|
-
if (cell.subtype !== 'caption') {
|
|
405
|
-
row.insertAt(cell);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
return row;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* 插入表格行
|
|
413
|
-
* @param y 行号
|
|
414
|
-
* @param attr 表格行属性
|
|
415
|
-
* @param inner 内部wikitext
|
|
416
|
-
* @param subtype 单元格类型
|
|
417
|
-
* @param innerAttr 单元格属性
|
|
418
|
-
*/
|
|
419
|
-
insertTableRow(y, attr = {}, inner, subtype = 'td', innerAttr = {}) {
|
|
420
|
-
let reference = this.getNthRow(y, false, true);
|
|
421
|
-
const token = Parser.run(() => new tr_1.TrToken('\n|-', undefined, this.getAttribute('config')));
|
|
422
|
-
for (const [k, v] of Object.entries(attr)) {
|
|
423
|
-
token.setAttr(k, v);
|
|
424
|
-
}
|
|
425
|
-
if (reference?.type === 'table') { // `row === 0`且表格自身是有效行
|
|
426
|
-
reference = this.#prependTableRow();
|
|
427
|
-
}
|
|
428
|
-
this.insertBefore(token, reference);
|
|
429
|
-
if (inner !== undefined) {
|
|
430
|
-
const td = token.insertTableCell(inner, { row: 0, column: 0 }, subtype, innerAttr), set = new WeakSet(), layout = this.getLayout({ y }), maxCol = Math.max(...layout.map(({ length }) => length)), rowLayout = layout[y];
|
|
431
|
-
Parser.run(() => {
|
|
432
|
-
for (let i = 0; i < maxCol; i++) {
|
|
433
|
-
const coords = rowLayout[i];
|
|
434
|
-
if (!coords) {
|
|
435
|
-
token.insertAt(td.cloneNode());
|
|
436
|
-
}
|
|
437
|
-
else if (!set.has(coords)) {
|
|
438
|
-
set.add(coords);
|
|
439
|
-
if (coords.row < y) {
|
|
440
|
-
this.getNthCell(coords).rowspan++;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
return token;
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* 插入表格列
|
|
450
|
-
* @param x 列号
|
|
451
|
-
* @param inner 内部wikitext
|
|
452
|
-
* @param subtype 单元格类型
|
|
453
|
-
* @param attr 单元格属性
|
|
454
|
-
* @throws `RangeError` 列号过大
|
|
455
|
-
*/
|
|
456
|
-
insertTableCol(x, inner, subtype = 'td', attr = {}) {
|
|
457
|
-
const layout = this.getLayout(), rowLength = layout.map(({ length }) => length), minCol = Math.min(...rowLength);
|
|
458
|
-
if (x > minCol) {
|
|
459
|
-
throw new RangeError(`表格第 ${rowLength.indexOf(minCol)} 行仅有 ${minCol} 列!`);
|
|
460
|
-
}
|
|
461
|
-
const token = td_1.TdToken.create(inner, subtype, attr, this.getAttribute('include'), this.getAttribute('config'));
|
|
462
|
-
for (let i = 0; i < layout.length; i++) {
|
|
463
|
-
const coords = layout[i][x], prevCoords = x === 0 ? true : layout[i][x - 1];
|
|
464
|
-
if (!prevCoords) {
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
else if (prevCoords !== coords) {
|
|
468
|
-
const rowToken = this.getNthRow(i);
|
|
469
|
-
rowToken.insertBefore(token.cloneNode(), rowToken.getNthCol(coords.column, true));
|
|
470
|
-
}
|
|
471
|
-
else if (coords.row === i) {
|
|
472
|
-
this.getNthCell(coords).colspan++;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
* 移除表格行
|
|
478
|
-
* @param y 行号
|
|
479
|
-
*/
|
|
480
|
-
removeTableRow(y) {
|
|
481
|
-
const rows = this.getAllRows(), layout = this.getLayout(), rowLayout = layout[y], set = new WeakSet();
|
|
482
|
-
for (let x = rowLayout.length - 1; x >= 0; x--) {
|
|
483
|
-
const coords = rowLayout[x];
|
|
484
|
-
if (set.has(coords)) {
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
set.add(coords);
|
|
488
|
-
const token = rows[coords.row].getNthCol(coords.column);
|
|
489
|
-
let { rowspan } = token;
|
|
490
|
-
if (rowspan > 1) {
|
|
491
|
-
token.rowspan = --rowspan;
|
|
492
|
-
if (coords.row === y) {
|
|
493
|
-
const { colspan, subtype } = token, attr = token.getAttrs();
|
|
494
|
-
for (let i = y + 1; rowspan && i < rows.length; i++, rowspan--) {
|
|
495
|
-
const { column } = layout[i].slice(x + colspan).find(({ row }) => row === i) ?? {};
|
|
496
|
-
if (column !== undefined) {
|
|
497
|
-
rows[i].insertTableCell('', { row: 0, column }, subtype, { ...attr, rowspan });
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
const rowToken = rows[y].type === 'table' ? this.#prependTableRow() : rows[y];
|
|
505
|
-
rowToken.remove();
|
|
506
|
-
return rowToken;
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* 移除表格列
|
|
510
|
-
* @param x 列号
|
|
511
|
-
*/
|
|
512
|
-
removeTableCol(x) {
|
|
513
|
-
for (const [token, start] of this.getFullCol(x)) {
|
|
514
|
-
const { colspan, lastChild } = token;
|
|
515
|
-
if (colspan > 1) {
|
|
516
|
-
token.colspan = colspan - 1;
|
|
517
|
-
if (start) {
|
|
518
|
-
lastChild.replaceChildren();
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
else {
|
|
522
|
-
token.remove();
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* 合并单元格
|
|
528
|
-
* @param xlim 列范围
|
|
529
|
-
* @param ylim 行范围
|
|
530
|
-
* @throws `RangeError` 待合并区域与外侧区域有重叠
|
|
531
|
-
*/
|
|
532
|
-
mergeCells(xlim, ylim) {
|
|
533
|
-
const layout = this.getLayout(), maxCol = Math.max(...layout.map(({ length }) => length)), posXlim = xlim.map(x => x < 0 ? x + maxCol : x), posYlim = ylim.map(y => y < 0 ? y + layout.length : y), [xmin, xmax] = posXlim.sort(), [ymin, ymax] = posYlim.sort(), set = new Set(layout.slice(ymin, ymax).flatMap(rowLayout => rowLayout.slice(xmin, xmax)));
|
|
534
|
-
if ([...layout[ymin - 1] ?? [], ...layout[ymax] ?? []].some(coords => set.has(coords))
|
|
535
|
-
|| layout.some(rowLayout => set.has(rowLayout[xmin - 1]) || set.has(rowLayout[xmax]))) {
|
|
536
|
-
throw new RangeError('待合并区域与外侧区域有重叠!');
|
|
537
|
-
}
|
|
538
|
-
const corner = layout[ymin][xmin], rows = this.getAllRows(), cornerCell = rows[corner.row].getNthCol(corner.column);
|
|
539
|
-
cornerCell.rowspan = ymax - ymin;
|
|
540
|
-
cornerCell.colspan = xmax - xmin;
|
|
541
|
-
set.delete(corner);
|
|
542
|
-
for (const token of [...set].map(({ row, column }) => rows[row].getNthCol(column))) {
|
|
543
|
-
token.remove();
|
|
544
|
-
}
|
|
545
|
-
return cornerCell;
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* 分裂单元格
|
|
549
|
-
* @param coords 单元格坐标
|
|
550
|
-
* @param dirs 分裂方向
|
|
551
|
-
* @throws `RangeError` 指定的坐标不是单元格起始点
|
|
552
|
-
*/
|
|
553
|
-
#split(coords, dirs) {
|
|
554
|
-
const cell = this.getNthCell(coords), attr = cell.getAttrs(), { subtype } = cell;
|
|
555
|
-
attr.rowspan ||= 1;
|
|
556
|
-
attr.colspan ||= 1;
|
|
557
|
-
for (const dir of dirs) {
|
|
558
|
-
if (attr[dir] === 1) {
|
|
559
|
-
dirs.delete(dir);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
if (dirs.size === 0) {
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
let { x, y } = coords;
|
|
566
|
-
const rawCoords = x === undefined ? coords : this.toRawCoords(coords);
|
|
567
|
-
if (rawCoords.start === false || x === undefined) {
|
|
568
|
-
({ x, y } = this.toRenderedCoords(rawCoords));
|
|
569
|
-
}
|
|
570
|
-
const splitting = { rowspan: 1, colspan: 1 };
|
|
571
|
-
for (const dir of dirs) {
|
|
572
|
-
cell.setAttr(dir, 1);
|
|
573
|
-
splitting[dir] = attr[dir];
|
|
574
|
-
delete attr[dir];
|
|
575
|
-
}
|
|
576
|
-
for (let j = y; j < y + splitting.rowspan; j++) {
|
|
577
|
-
for (let i = x; i < x + splitting.colspan; i++) {
|
|
578
|
-
if (i > x || j > y) {
|
|
579
|
-
try {
|
|
580
|
-
this.insertTableCell('', { x: i, y: j }, subtype, attr);
|
|
581
|
-
}
|
|
582
|
-
catch (e) {
|
|
583
|
-
if (e instanceof RangeError && e.message.startsWith('指定的坐标不是单元格起始点:')) {
|
|
584
|
-
break;
|
|
585
|
-
}
|
|
586
|
-
throw e;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* 分裂成多行
|
|
594
|
-
* @param coords 单元格坐标
|
|
595
|
-
*/
|
|
596
|
-
splitIntoRows(coords) {
|
|
597
|
-
this.#split(coords, new Set(['rowspan']));
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* 分裂成多列
|
|
601
|
-
* @param coords 单元格坐标
|
|
602
|
-
*/
|
|
603
|
-
splitIntoCols(coords) {
|
|
604
|
-
this.#split(coords, new Set(['colspan']));
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* 分裂成单元格
|
|
608
|
-
* @param coords 单元格坐标
|
|
609
|
-
*/
|
|
610
|
-
splitIntoCells(coords) {
|
|
611
|
-
this.#split(coords, new Set(['rowspan', 'colspan']));
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* 复制一行并插入该行之前
|
|
615
|
-
* @param row 行号
|
|
616
|
-
*/
|
|
617
|
-
replicateTableRow(row) {
|
|
618
|
-
let rowToken = this.getNthRow(row);
|
|
619
|
-
if (rowToken.type === 'table') {
|
|
620
|
-
rowToken = this.#prependTableRow();
|
|
621
|
-
}
|
|
622
|
-
const replicated = this.insertBefore(rowToken.cloneNode(), rowToken);
|
|
623
|
-
for (const [token, start] of this.getFullRow(row)) {
|
|
624
|
-
if (start) {
|
|
625
|
-
token.rowspan = 1;
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
token.rowspan++;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return replicated;
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* 复制一列并插入该列之前
|
|
635
|
-
* @param x 列号
|
|
636
|
-
*/
|
|
637
|
-
replicateTableCol(x) {
|
|
638
|
-
const replicated = [];
|
|
639
|
-
for (const [token, start] of this.getFullCol(x)) {
|
|
640
|
-
if (start) {
|
|
641
|
-
const newToken = token.cloneNode();
|
|
642
|
-
newToken.colspan = 1;
|
|
643
|
-
token.before(newToken);
|
|
644
|
-
replicated.push(newToken);
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
647
|
-
token.colspan++;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
return replicated;
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
|
-
* 移动表格行
|
|
654
|
-
* @param y 行号
|
|
655
|
-
* @param before 新位置
|
|
656
|
-
* @throws `RangeError` 无法移动
|
|
657
|
-
*/
|
|
658
|
-
moveTableRowBefore(y, before) {
|
|
659
|
-
const layout = this.getLayout(),
|
|
660
|
-
/** @ignore */
|
|
661
|
-
occupied = (i) => layout[i].map(({ row }, j) => row === i ? j : undefined).filter(j => j !== undefined);
|
|
662
|
-
try {
|
|
663
|
-
assert.deepEqual(occupied(y), occupied(before));
|
|
664
|
-
}
|
|
665
|
-
catch (e) {
|
|
666
|
-
if (e instanceof assert.AssertionError) {
|
|
667
|
-
throw new RangeError(`第 ${y} 行与第 ${before} 行的构造不同,无法移动!`);
|
|
668
|
-
}
|
|
669
|
-
throw e;
|
|
670
|
-
}
|
|
671
|
-
const rowToken = this.removeTableRow(y);
|
|
672
|
-
for (const coords of layout[before]) {
|
|
673
|
-
if (coords.row < before) {
|
|
674
|
-
this.getNthCell(coords).rowspan++;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
let beforeToken = this.getNthRow(before);
|
|
678
|
-
if (beforeToken.type === 'table') {
|
|
679
|
-
beforeToken = this.#prependTableRow();
|
|
680
|
-
}
|
|
681
|
-
this.insertBefore(rowToken, beforeToken);
|
|
682
|
-
return rowToken;
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* 移动表格行
|
|
686
|
-
* @param y 行号
|
|
687
|
-
* @param after 新位置
|
|
688
|
-
* @throws `RangeError` 无法移动
|
|
689
|
-
*/
|
|
690
|
-
moveTableRowAfter(y, after) {
|
|
691
|
-
const layout = this.getLayout(), afterToken = this.getNthRow(after), cells = afterToken.childNodes.filter(child => child instanceof td_1.TdToken && child.subtype !== 'caption'),
|
|
692
|
-
/** @ignore */
|
|
693
|
-
occupied = (i, oneRow = false) => layout[i].map(({ row, column }, j) => row === i && (!oneRow || cells[column].rowspan === 1) ? j : undefined).filter(j => j !== undefined);
|
|
694
|
-
try {
|
|
695
|
-
assert.deepEqual(occupied(y), occupied(after, true));
|
|
696
|
-
}
|
|
697
|
-
catch (e) {
|
|
698
|
-
if (e instanceof assert.AssertionError) {
|
|
699
|
-
throw new RangeError(`第 ${y} 行与第 ${after} 行的构造不同,无法移动!`);
|
|
700
|
-
}
|
|
701
|
-
throw e;
|
|
702
|
-
}
|
|
703
|
-
const rowToken = this.removeTableRow(y);
|
|
704
|
-
for (const coords of layout[after]) {
|
|
705
|
-
if (coords.row < after) {
|
|
706
|
-
this.getNthCell(coords).rowspan++;
|
|
707
|
-
}
|
|
708
|
-
else {
|
|
709
|
-
const cell = cells[coords.column], { rowspan } = cell;
|
|
710
|
-
if (rowspan > 1) {
|
|
711
|
-
cell.rowspan = rowspan + 1;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
if (afterToken === this) {
|
|
716
|
-
const index = this.childNodes.slice(2).findIndex(isRowEnd);
|
|
717
|
-
this.insertAt(rowToken, index + 2);
|
|
718
|
-
}
|
|
719
|
-
else {
|
|
720
|
-
this.insertBefore(rowToken, afterToken);
|
|
721
|
-
}
|
|
722
|
-
return rowToken;
|
|
723
|
-
}
|
|
724
|
-
/**
|
|
725
|
-
* 移动表格列
|
|
726
|
-
* @param x 列号
|
|
727
|
-
* @param reference 新位置
|
|
728
|
-
* @param after 在新位置之后或之前
|
|
729
|
-
* @throws `RangeError` 无法移动
|
|
730
|
-
*/
|
|
731
|
-
#moveCol(x, reference, after = false) {
|
|
732
|
-
const layout = this.getLayout();
|
|
733
|
-
if (layout.some(rowLayout => isStartCol(rowLayout, x) !== isStartCol(rowLayout, reference, after))) {
|
|
734
|
-
throw new RangeError(`第 ${x} 列与第 ${reference} 列的构造不同,无法移动!`);
|
|
735
|
-
}
|
|
736
|
-
const setX = new WeakSet(), setRef = new WeakSet(), rows = this.getAllRows();
|
|
737
|
-
for (let i = 0; i < layout.length; i++) {
|
|
738
|
-
const rowLayout = layout[i], coords = rowLayout[x], refCoords = rowLayout[reference], start = isStartCol(rowLayout, x);
|
|
739
|
-
if (refCoords && !start && !setRef.has(refCoords)) {
|
|
740
|
-
setRef.add(refCoords);
|
|
741
|
-
rows[refCoords.row].getNthCol(refCoords.column).colspan++;
|
|
742
|
-
}
|
|
743
|
-
if (coords && !setX.has(coords)) {
|
|
744
|
-
setX.add(coords);
|
|
745
|
-
const rowToken = rows[i];
|
|
746
|
-
let token = rowToken.getNthCol(coords.column);
|
|
747
|
-
const { colspan } = token;
|
|
748
|
-
if (colspan > 1) {
|
|
749
|
-
token.colspan = colspan - 1;
|
|
750
|
-
if (start) {
|
|
751
|
-
const original = token;
|
|
752
|
-
token = token.cloneNode();
|
|
753
|
-
original.lastChild.replaceChildren();
|
|
754
|
-
token.colspan = 1;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
if (start) {
|
|
758
|
-
const col = rowLayout.slice(reference + Number(after)).find(({ row }) => row === i)?.column;
|
|
759
|
-
rowToken.insertBefore(token, col === undefined ? rowToken.childNodes.slice(2).find(isRowEnd) : rowToken.getNthCol(col));
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* 移动表格列
|
|
766
|
-
* @param x 列号
|
|
767
|
-
* @param before 新位置
|
|
768
|
-
*/
|
|
769
|
-
moveTableColBefore(x, before) {
|
|
770
|
-
this.#moveCol(x, before);
|
|
771
|
-
}
|
|
772
|
-
/**
|
|
773
|
-
* 移动表格列
|
|
774
|
-
* @param x 列号
|
|
775
|
-
* @param after 新位置
|
|
776
|
-
*/
|
|
777
|
-
moveTableColAfter(x, after) {
|
|
778
|
-
this.#moveCol(x, after, true);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
exports.TableToken = TableToken;
|
|
782
|
-
Parser.classes['TableToken'] = __filename;
|