Skip to content

Commit 67ed791

Browse files
chore: release v0.3.22
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8b319b6 commit 67ed791

27 files changed

Lines changed: 1023 additions & 132 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ Canvas-based document editor for the web. High-performance rendering via HTML5 C
1515

1616
| Package | Description | Version |
1717
|---------|-------------|---------|
18-
| [@windoc/core](./core) | Canvas editor engine | 0.3.21 |
19-
| [@windoc/react](./react) | React bindings & composable UI | 0.3.21 |
18+
| [@windoc/core](./core) | Canvas editor engine | 0.3.22 |
19+
| [@windoc/react](./react) | React bindings & composable UI | 0.3.22 |
2020

2121
## Getting Started
2222

core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@windoc/core",
3-
"version": "0.3.21",
3+
"version": "0.3.22",
44
"description": "Canvas-based document editor engine",
55
"homepage": "https://aliansyahfirdaus.github.io/windoc/",
66
"repository": {

core/src/core/command/CommandAdapt.ts

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,38 @@ export class CommandAdapt {
163163
this.tableOperate = draw.getTableOperate();
164164
}
165165

166+
private getStyleSelectionElementList(options: {
167+
textLikeOnly?: boolean;
168+
} = {}): IElement[] | null {
169+
const selection = this.range.getSelectionElementList();
170+
if (!selection?.length) return null;
171+
const { textLikeOnly = false } = options;
172+
const result: IElement[] = [];
173+
const collect = (elementList: IElement[]) => {
174+
for (let i = 0; i < elementList.length; i++) {
175+
const element = elementList[i];
176+
if (element.type === ElementType.TABLE && element.trList?.length) {
177+
for (let t = 0; t < element.trList.length; t++) {
178+
const tr = element.trList[t];
179+
for (let d = 0; d < tr.tdList.length; d++) {
180+
collect(tr.tdList[d].value);
181+
}
182+
}
183+
continue;
184+
}
185+
result.push(element);
186+
}
187+
};
188+
collect(selection);
189+
if (!textLikeOnly) {
190+
return result;
191+
}
192+
return result.filter(
193+
element =>
194+
isTextLikeElement(element) || element.type === ElementType.LABEL
195+
);
196+
}
197+
166198
public mode(payload: EditorMode) {
167199
this.draw.setMode(payload);
168200
}
@@ -338,7 +370,7 @@ export class CommandAdapt {
338370
!isIgnoreDisabledRule &&
339371
(this.draw.isReadonly() || this.draw.isDisabled());
340372
if (isDisabled) return;
341-
const selection = this.range.getSelectionElementList();
373+
const selection = this.getStyleSelectionElementList();
342374
let renderOption: IDrawOption = {};
343375
let changeElementList: IElement[] = [];
344376
if (selection?.length) {
@@ -368,7 +400,7 @@ export class CommandAdapt {
368400
!isIgnoreDisabledRule &&
369401
(this.draw.isReadonly() || this.draw.isDisabled());
370402
if (isDisabled) return;
371-
const selection = this.range.getSelectionElementList();
403+
const selection = this.getStyleSelectionElementList();
372404
if (selection?.length) {
373405
selection.forEach(el => {
374406
el.font = payload;
@@ -405,7 +437,9 @@ export class CommandAdapt {
405437
if (payload < minSize || payload > maxSize) return;
406438
let renderOption: IDrawOption = {};
407439
let changeElementList: IElement[] = [];
408-
const selection = this.range.getTextLikeSelectionElementList();
440+
const selection = this.getStyleSelectionElementList({
441+
textLikeOnly: true
442+
});
409443
if (selection?.length) {
410444
changeElementList = selection;
411445
renderOption = { isSetCursor: false };
@@ -451,7 +485,9 @@ export class CommandAdapt {
451485
(this.draw.isReadonly() || this.draw.isDisabled());
452486
if (isDisabled) return;
453487
const { defaultSize, maxSize } = this.options;
454-
const selection = this.range.getTextLikeSelectionElementList();
488+
const selection = this.getStyleSelectionElementList({
489+
textLikeOnly: true
490+
});
455491
let renderOption: IDrawOption = {};
456492
let changeElementList: IElement[] = [];
457493
if (selection?.length) {
@@ -503,7 +539,9 @@ export class CommandAdapt {
503539
(this.draw.isReadonly() || this.draw.isDisabled());
504540
if (isDisabled) return;
505541
const { defaultSize, minSize } = this.options;
506-
const selection = this.range.getTextLikeSelectionElementList();
542+
const selection = this.getStyleSelectionElementList({
543+
textLikeOnly: true
544+
});
507545
let renderOption: IDrawOption = {};
508546
let changeElementList: IElement[] = [];
509547
if (selection?.length) {
@@ -554,7 +592,7 @@ export class CommandAdapt {
554592
!isIgnoreDisabledRule &&
555593
(this.draw.isReadonly() || this.draw.isDisabled());
556594
if (isDisabled) return;
557-
const selection = this.range.getSelectionElementList();
595+
const selection = this.getStyleSelectionElementList();
558596
if (selection?.length) {
559597
const noBoldIndex = selection.findIndex(s => !s.bold);
560598
selection.forEach(el => {
@@ -589,7 +627,7 @@ export class CommandAdapt {
589627
!isIgnoreDisabledRule &&
590628
(this.draw.isReadonly() || this.draw.isDisabled());
591629
if (isDisabled) return;
592-
const selection = this.range.getSelectionElementList();
630+
const selection = this.getStyleSelectionElementList();
593631
if (selection?.length) {
594632
const noItalicIndex = selection.findIndex(s => !s.italic);
595633
selection.forEach(el => {
@@ -629,7 +667,7 @@ export class CommandAdapt {
629667
!isIgnoreDisabledRule &&
630668
(this.draw.isReadonly() || this.draw.isDisabled());
631669
if (isDisabled) return;
632-
const selection = this.range.getSelectionElementList();
670+
const selection = this.getStyleSelectionElementList();
633671
if (selection?.length) {
634672
// Reset underline when not set, current/previous missing, or text decoration inconsistent
635673
const isSetUnderline = selection.some(
@@ -683,7 +721,7 @@ export class CommandAdapt {
683721
!isIgnoreDisabledRule &&
684722
(this.draw.isReadonly() || this.draw.isDisabled());
685723
if (isDisabled) return;
686-
const selection = this.range.getSelectionElementList();
724+
const selection = this.getStyleSelectionElementList();
687725
if (selection?.length) {
688726
const noStrikeoutIndex = selection.findIndex(s => !s.strikeout);
689727
selection.forEach(el => {
@@ -723,7 +761,7 @@ export class CommandAdapt {
723761
!isIgnoreDisabledRule &&
724762
(this.draw.isReadonly() || this.draw.isDisabled());
725763
if (isDisabled) return;
726-
const selection = this.range.getSelectionElementList();
764+
const selection = this.getStyleSelectionElementList();
727765
if (!selection) return;
728766
const superscriptIndex = selection.findIndex(
729767
s => s.type === ElementType.SUPERSCRIPT
@@ -753,7 +791,7 @@ export class CommandAdapt {
753791
!isIgnoreDisabledRule &&
754792
(this.draw.isReadonly() || this.draw.isDisabled());
755793
if (isDisabled) return;
756-
const selection = this.range.getSelectionElementList();
794+
const selection = this.getStyleSelectionElementList();
757795
if (!selection) return;
758796
const subscriptIndex = selection.findIndex(
759797
s => s.type === ElementType.SUBSCRIPT
@@ -783,7 +821,7 @@ export class CommandAdapt {
783821
!isIgnoreDisabledRule &&
784822
(this.draw.isReadonly() || this.draw.isDisabled());
785823
if (isDisabled) return;
786-
const selection = this.range.getSelectionElementList();
824+
const selection = this.getStyleSelectionElementList();
787825
if (selection?.length) {
788826
selection.forEach(el => {
789827
if (payload) {
@@ -827,7 +865,7 @@ export class CommandAdapt {
827865
!isIgnoreDisabledRule &&
828866
(this.draw.isReadonly() || this.draw.isDisabled());
829867
if (isDisabled) return;
830-
const selection = this.range.getSelectionElementList();
868+
const selection = this.getStyleSelectionElementList();
831869
if (selection?.length) {
832870
selection.forEach(el => {
833871
if (payload) {
@@ -1548,31 +1586,51 @@ export class CommandAdapt {
15481586
extraPickAttrs: ['id', 'controlComponent']
15491587
});
15501588
// Page info and row info
1551-
const rowList = this.draw.getRowList();
15521589
const positionList = this.position.getPositionList();
15531590
const startPosition = positionList[startIndex];
15541591
const endPosition = positionList[endIndex];
1592+
if (!startPosition || !endPosition) return null;
15551593
const startPageNo = startPosition.pageNo;
15561594
const endPageNo = endPosition.pageNo;
15571595
const startRowNo = startPosition.rowIndex;
15581596
const endRowNo = endPosition.rowIndex;
1559-
const startRow = rowList[startRowNo];
1560-
const endRow = rowList[endRowNo];
1597+
const getRowStartPositionIndex = (targetIndex: number) => {
1598+
let rowStartIndex = targetIndex;
1599+
const targetPosition = positionList[targetIndex];
1600+
while (rowStartIndex > 0) {
1601+
const prePosition = positionList[rowStartIndex - 1];
1602+
if (
1603+
!prePosition ||
1604+
prePosition.pageNo !== targetPosition.pageNo ||
1605+
prePosition.rowNo !== targetPosition.rowNo ||
1606+
prePosition.columnNo !== targetPosition.columnNo
1607+
) {
1608+
break;
1609+
}
1610+
rowStartIndex--;
1611+
}
1612+
return rowStartIndex;
1613+
};
1614+
const startRowStartIndex = getRowStartPositionIndex(startIndex);
1615+
const endRowStartIndex = getRowStartPositionIndex(endIndex);
1616+
const startRowStartsWithZero =
1617+
elementList[startRowStartIndex]?.value === ZERO;
1618+
const endRowStartsWithZero = elementList[endRowStartIndex]?.value === ZERO;
15611619
let startColNo = 0;
15621620
let endColNo = 0;
15631621
if (!this.draw.getCursor().getHitLineStartIndex()) {
15641622
startColNo =
1565-
startRow.elementList[0]?.value === ZERO
1566-
? startPosition.index! - startRow.startIndex
1567-
: startPosition.index! - startRow.startIndex + 1;
1623+
startRowStartsWithZero
1624+
? startIndex - startRowStartIndex
1625+
: startIndex - startRowStartIndex + 1;
15681626
}
15691627
if (startPosition === endPosition) {
15701628
endColNo = startColNo;
15711629
} else {
15721630
endColNo =
1573-
endRow.elementList[0]?.value === ZERO
1574-
? endPosition.index! - endRow.startIndex
1575-
: endPosition.index! - endRow.startIndex + 1;
1631+
endRowStartsWithZero
1632+
? endIndex - endRowStartIndex
1633+
: endIndex - endRowStartIndex + 1;
15761634
}
15771635

15781636
// Coordinate info (relative to editor writing area)
@@ -1583,6 +1641,7 @@ export class CommandAdapt {
15831641
if (selectionPositionList) {
15841642
// Start info and x coordinate
15851643
let currentRowNo: number | null = null;
1644+
let currentPageNo: number | null = null;
15861645
let currentX = 0;
15871646
let rangeRect: RangeRect | null = null;
15881647
for (let p = 0; p < selectionPositionList.length; p++) {
@@ -1592,7 +1651,12 @@ export class CommandAdapt {
15921651
coordinate: { leftTop, rightTop },
15931652
lineHeight
15941653
} = selectionPositionList[p];
1595-
if (currentRowNo === null || currentRowNo !== rowNo) {
1654+
if (
1655+
currentRowNo === null ||
1656+
currentPageNo === null ||
1657+
currentRowNo !== rowNo ||
1658+
currentPageNo !== pageNo
1659+
) {
15961660
if (rangeRect) {
15971661
rangeRects.push(rangeRect);
15981662
}
@@ -1603,6 +1667,7 @@ export class CommandAdapt {
16031667
height: lineHeight
16041668
};
16051669
currentRowNo = rowNo;
1670+
currentPageNo = pageNo;
16061671
currentX = leftTop[0];
16071672
} else {
16081673
rangeRect!.width = rightTop[0] - currentX;

0 commit comments

Comments
 (0)