Skip to content

Commit

Permalink
#154 TextFieldのコピー&ペーストを実装(WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
ienaga committed Nov 25, 2024
1 parent 5c75d6e commit bb892e9
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 40 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
textFiled.border = true;
textFiled.type = "input";
textFiled.multiline = true;
textFiled.wordWrap = true;
textFiled.text = "Hello Next2D\nTest Mode On Test Mode On Test Mode On\n\n\n\n\n\n\n\n\n\nText Field";
// textFiled.wordWrap = true;
textFiled.text = "Hello Next2D\nTest Mode On Test Mode On Test Mode On Test Mode On Test Mode On Test Mode On Test Mode On\nText Field\nText Field\n\n\n\n\nTest Mode On Test Mode On Test Mode On Test Mode On Test Mode On";

const shape = sprite.addChild(new Shape());
shape
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ export const execute = (

let tx = 2;
if (text_setting.scrollX > 0) {
const scaleX = (text_setting.textWidth - text_setting.rawWidth) / text_setting.rawWidth;
const scaleX = (text_setting.textWidth + 4 - text_setting.rawWidth) / text_setting.rawWidth;
tx += -text_setting.scrollX * scaleX;
}

let ty = 2;
if (text_setting.scrollY > 0) {
const scaleY = (text_setting.textHeight - text_setting.rawHeight) / text_setting.rawHeight;
const scaleY = (text_setting.textHeight + 2 - text_setting.rawHeight) / text_setting.rawHeight;
ty += -text_setting.scrollY * scaleY;
}

Expand Down
19 changes: 3 additions & 16 deletions packages/text/src/TextField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { execute as textFieldHtmlTextToRawTextUseCase } from "./TextField/usecas
import { execute as textFieldGetLineTextUseCase } from "./TextField/usecase/TextFieldGetLineTextUseCase";
import { execute as textFieldReplaceTextUseCase } from "./TextField/usecase/TextFieldReplaceTextUseCase";
import { execute as textFieldCopyUseCase } from "./TextField/usecase/TextFieldCopyUseCase";
import { execute as textFieldPasteService } from "./TextField/service/TextFieldPasteService";
import { execute as textFieldInsertTextUseCase } from "./TextField/usecase/TextFieldInsertTextUseCase";
import { execute as textFieldApplyChangesService } from "./TextField/service/TextFieldApplyChangesService";
import { execute as textFieldSetFocusIndexUseCase } from "./TextField/usecase/TextFieldSetFocusIndexUseCase";
Expand Down Expand Up @@ -291,7 +292,6 @@ export class TextField extends InteractiveObject
private _$autoSize: ITextFieldAutoSize;
private _$autoFontSize: boolean;
private _$focus: boolean;
private _$copyText: string;
private _$thickness: number;
private _$thicknessColor: number;
private _$stopIndex: number;
Expand Down Expand Up @@ -551,13 +551,6 @@ export class TextField extends InteractiveObject
*/
this._$focus = false;

/**
* @type {string}
* @default ""
* @private
*/
this._$copyText = "";

/**
* @type {number}
* @default 0
Expand Down Expand Up @@ -1223,10 +1216,7 @@ export class TextField extends InteractiveObject
*/
copy (): void
{
if (this.focusIndex === -1 || this.selectIndex === -1) {
return ;
}
this._$copyText = textFieldCopyUseCase(this);
textFieldCopyUseCase(this);
}

/**
Expand All @@ -1239,10 +1229,7 @@ export class TextField extends InteractiveObject
*/
paste (): void
{
if (!this._$copyText || this.focusIndex === -1) {
return ;
}
this.insertText(this._$copyText);
textFieldPasteService(this);
}

/**
Expand Down
47 changes: 47 additions & 0 deletions packages/text/src/TextField/service/TextFieldPasteService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { execute } from "./TextFieldPasteService";
import { TextField } from "../../TextField";
import { describe, expect, it, beforeEach, afterAll } from "vitest";

describe("TextFieldPasteService.js test", () =>
{
beforeEach(() => {
Object.assign(navigator, {
"clipboard": {
"text": "",
readText ()
{
return Promise.resolve(this.text);
},
writeText (data: string)
{
this.text = data;
return Promise.resolve();
}
}
});
});

afterAll(() => {
Object.assign(navigator, { "clipboard": undefined });
});

it("execute test case1", async () =>
{
await navigator
.clipboard
.writeText("あいうえお\nかきくけこ\nさしすせそ");



const textField = new TextField();
textField.multiline = true;
textField.focusIndex = 1;
textField.selectIndex = 99;

textField.text = "xyz";
expect(textField.text).toBe("xyz");

await execute(textField);
expect(textField.text).toBe("あいうえお\nかきくけこ\nさしすせそ");
});
});
20 changes: 20 additions & 0 deletions packages/text/src/TextField/service/TextFieldPasteService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { TextField } from "../../TextField";

/**
* @description コピーしたテキストをペーストします。
* Pastes the copied text.
*
* @param {TextField} text_field
* @return {void}
* @method
* @protected
*/
export const execute = async (text_field: TextField): Promise<void> =>
{
const text = await navigator.clipboard.readText();
if (text === "" || text_field.focusIndex === -1) {
return ;
}

text_field.insertText(text);
};
47 changes: 44 additions & 3 deletions packages/text/src/TextField/usecase/TextFieldArrowDownUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { TextField } from "../../TextField";
import { $textArea } from "../../TextUtil";
import { execute as textFieldGetTextDataUseCase } from "../../TextField/usecase/TextFieldGetTextDataUseCase";
import { execute as textFieldBlinkingClearTimeoutService } from "../../TextField/service/TextFieldBlinkingClearTimeoutService";
import { execute as textFieldBlinkingUseCase } from "../../TextField/usecase/TextFieldBlinkingUseCase";
Expand Down Expand Up @@ -50,11 +49,47 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>

text_field.focusVisible = false;
text_field.focusIndex = textData.textTable.length;

const width = text_field.width;
const scaleX = (text_field.textWidth - width) / width;

let scrollX = 0;
for (let idx = 1; text_field.focusIndex >= idx; ++idx) {

const textObject = textData.textTable[idx];
if (!textObject || textObject.line > line) {
break;
}

if (textObject.line !== line) {
continue;
}

scrollX += textObject.w;
}

text_field.scrollX = (scrollX - width) / scaleX;

textFieldBlinkingClearTimeoutService();
textFieldBlinkingUseCase(text_field);
return ;
}

const height = text_field.height;
const scaleY = (text_field.textHeight - height) / height;

let currentHeight = -text_field.scrollY * scaleY - 2;
let endLine = 0;
for (let idx = 0; idx < textData.heightTable.length; ++idx) {

currentHeight += textData.heightTable[idx];
if (currentHeight > height) {
break;
}

endLine++;
}

let currentWidth = 2;
for (let idx = 1; idx < textData.textTable.length; ++idx) {

Expand Down Expand Up @@ -103,7 +138,10 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>
}
}

$textArea.style.top = `${$textArea.offsetTop + textObject.h}px`;
if (textObject.line >= endLine) {
text_field.scrollY += textData.heightTable[textObject.line] / scaleY;
}

text_field.focusVisible = false;
text_field.focusIndex = textObject.mode === "text" ? idx - 1 : idx;
textFieldBlinkingClearTimeoutService();
Expand All @@ -130,7 +168,10 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>
}
}

$textArea.style.top = `${$textArea.offsetTop + textObject.h}px`;
if (textObject.line >= endLine) {
text_field.scrollY += textData.heightTable[textObject.line] / scaleY;
}

text_field.focusVisible = false;
text_field.focusIndex = idx;
textFieldBlinkingClearTimeoutService();
Expand Down
27 changes: 27 additions & 0 deletions packages/text/src/TextField/usecase/TextFieldArrowLeftUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>

// fixed logic
text_field.focusIndex--;

if (!shift_key) {
text_field.selectIndex = -1;
} else {
Expand All @@ -39,6 +40,32 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>
}
}

const textObject = textData.textTable[text_field.focusIndex];
if (textObject) {
const line = textObject.mode === "text"
? textObject.line
: textObject.line - 1;

const height = text_field.height;
const scaleY = (text_field.textHeight - height) / height;

let currentHeight = -text_field.scrollY * scaleY - 2;
let startLine = 0;
for (let idx = 0; idx < textData.heightTable.length; ++idx) {

currentHeight += textData.heightTable[idx];
if (currentHeight > 0) {
break;
}

startLine++;
}

if (startLine > line) {
text_field.scrollY -= textData.heightTable[textObject.line] / scaleY;
}
}

text_field.focusVisible = false;
textFieldBlinkingClearTimeoutService();
textFieldBlinkingUseCase(text_field);
Expand Down
66 changes: 66 additions & 0 deletions packages/text/src/TextField/usecase/TextFieldArrowRightUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,70 @@ export const execute = (text_field: TextField, shift_key: boolean): void =>
text_field.focusIndex++;
textFieldBlinkingClearTimeoutService();
textFieldBlinkingUseCase(text_field);

const textObject = textData.textTable[text_field.focusIndex];
if (textObject) {
const line = textObject.mode === "text"
? textObject.line
: textObject.line - 1;

const height = text_field.height;
const scaleY = (text_field.textHeight - height) / height;

let currentHeight = -text_field.scrollY * scaleY - 2;
let endLine = 0;
for (let idx = 0; idx < textData.heightTable.length; ++idx) {

currentHeight += textData.heightTable[idx];
if (currentHeight > height) {
break;
}

endLine++;
}

if (line >= endLine) {
text_field.scrollY += textData.heightTable[line] / scaleY;
}

const currentTextObject = textData.textTable[text_field.focusIndex - 1];
const currentLine = currentTextObject.mode === "text"
? currentTextObject.line
: currentTextObject.line - 1;

if (currentTextObject && line > currentLine) {
if (text_field.yScrollShape.hasLocalVariable("job")) {
text_field.yScrollShape.deleteLocalVariable("job");
}
text_field.scrollX = 0;
return ;
}

const width = text_field.width;
const scaleX = (text_field.textWidth - width) / width;

let limitWidth = text_field.scrollX * scaleX - 2 + width;
for (let idx = 1; text_field.focusIndex >= idx; ++idx) {

const textObject = textData.textTable[idx];
if (!textObject || textObject.line > line) {
break;
}

if (textObject.line !== line) {
continue;
}

limitWidth -= textObject.w;
if (limitWidth > 0) {
continue;
}

if (text_field.yScrollShape.hasLocalVariable("job")) {
text_field.yScrollShape.deleteLocalVariable("job");
}
text_field.scrollX += textObject.w / scaleX;
break;
}
}
};
Loading

0 comments on commit bb892e9

Please sign in to comment.