hangul-unicode-composer 1.6.0
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 +101 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/keyboard/key/KeyStatus.d.ts +6 -0
- package/dist/keyboard/key/KeyStatus.js +6 -0
- package/dist/keyboard/keyMeta/KeyInfo.d.ts +5 -0
- package/dist/keyboard/keyMeta/KeyInfo.js +5 -0
- package/dist/keyboard/keyMeta/KeyType.d.ts +14 -0
- package/dist/keyboard/keyMeta/KeyType.js +14 -0
- package/dist/text/HangleTextEvent.d.ts +24 -0
- package/dist/text/HangleTextEvent.js +29 -0
- package/dist/text/HangleUnicodeComposer.d.ts +133 -0
- package/dist/text/HangleUnicodeComposer.js +629 -0
- package/dist/text/HangulTextEvent.d.ts +24 -0
- package/dist/text/HangulTextEvent.js +29 -0
- package/dist/text/HangulUnicodeComposer.d.ts +133 -0
- package/dist/text/HangulUnicodeComposer.js +629 -0
- package/package.json +35 -0
- package/src/index.ts +5 -0
- package/src/keyboard/key/KeyStatus.ts +6 -0
- package/src/keyboard/keyMeta/KeyInfo.ts +5 -0
- package/src/keyboard/keyMeta/KeyType.ts +16 -0
- package/src/text/HangulTextEvent.ts +34 -0
- package/src/text/HangulUnicodeComposer.ts +641 -0
- package/src/text/__tests__/HangulUnicodeComposer.test.ts +162 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
import { HangleTextEvent } from "./HangleTextEvent.js";
|
|
2
|
+
class ArchivePack {
|
|
3
|
+
key = "";
|
|
4
|
+
compositionString = "";
|
|
5
|
+
extra = "";
|
|
6
|
+
_instant = [];
|
|
7
|
+
get instant() {
|
|
8
|
+
return this._instant;
|
|
9
|
+
}
|
|
10
|
+
set instant(value) {
|
|
11
|
+
this._instant = [...value];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* HangleUnicodeComposer
|
|
16
|
+
* Ports the AS3 한글 조합 라이브러리 to TypeScript.
|
|
17
|
+
* Composes Korean Jamo characters into Unicode Hangul syllables.
|
|
18
|
+
*/
|
|
19
|
+
export class HangleUnicodeComposer extends EventTarget {
|
|
20
|
+
/**
|
|
21
|
+
* Initial consonant (초성) Unicode values
|
|
22
|
+
*/
|
|
23
|
+
static INITIAL = [
|
|
24
|
+
0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142, 0x3143, 0x3145,
|
|
25
|
+
0x3146, 0x3147, 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Medial vowel (중성) Unicode values
|
|
29
|
+
*/
|
|
30
|
+
static MEDIAL = [
|
|
31
|
+
0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157, 0x3158,
|
|
32
|
+
0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160, 0x3161, 0x3162,
|
|
33
|
+
0x3163
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Final consonant (종성) Unicode values. Index 0 is empty (no final consonant).
|
|
37
|
+
*/
|
|
38
|
+
static FINAL = [
|
|
39
|
+
"", 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3139, 0x313a,
|
|
40
|
+
0x313b, 0x313c, 0x313d, 0x313e, 0x313f, 0x3140, 0x3141, 0x3142, 0x3144, 0x3145,
|
|
41
|
+
0x3146, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e
|
|
42
|
+
];
|
|
43
|
+
static used = false;
|
|
44
|
+
/**
|
|
45
|
+
* Helper to make one letter by composing 3 syllables.
|
|
46
|
+
*/
|
|
47
|
+
static getString3Syllables(init, mid, fin) {
|
|
48
|
+
const uni = new HangleUnicodeComposer();
|
|
49
|
+
return uni.combine3Syllables(init, mid, fin);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns true if the character is a Hangeul Jaeum (consonant) in the range 3131 ~ 314E.
|
|
53
|
+
*/
|
|
54
|
+
static isHangleJaeum(char) {
|
|
55
|
+
const uni = new HangleUnicodeComposer();
|
|
56
|
+
return uni.compatibleJaeum(char);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns true if the character is a Hangeul Jamo in the range 3130 ~ 318F.
|
|
60
|
+
*/
|
|
61
|
+
static isHangleJamo(char) {
|
|
62
|
+
const uni = new HangleUnicodeComposer();
|
|
63
|
+
return uni.compatibleHangleJamo(char);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns true if the character is a Hangeul Moeum (vowel) in the range 314F ~ 3163.
|
|
67
|
+
*/
|
|
68
|
+
static isHangleMoeum(char) {
|
|
69
|
+
const uni = new HangleUnicodeComposer();
|
|
70
|
+
return uni.compatibleMoeum(char);
|
|
71
|
+
}
|
|
72
|
+
compositionString = "";
|
|
73
|
+
extra = "";
|
|
74
|
+
restrict = 3000;
|
|
75
|
+
instant = [];
|
|
76
|
+
archives = [];
|
|
77
|
+
// Callbacks for easy JS integration
|
|
78
|
+
onUpdate;
|
|
79
|
+
onLimited;
|
|
80
|
+
onError;
|
|
81
|
+
constructor() {
|
|
82
|
+
super();
|
|
83
|
+
if (HangleUnicodeComposer.used)
|
|
84
|
+
return;
|
|
85
|
+
HangleUnicodeComposer.used = true;
|
|
86
|
+
const re = "* hangle unicode composer for TS lib : ver- " + this.ver() + "\n" +
|
|
87
|
+
"* homepage-blog.hansune.com : maker-han hyon soo\n";
|
|
88
|
+
console.log(re);
|
|
89
|
+
}
|
|
90
|
+
ver() {
|
|
91
|
+
return "1.6";
|
|
92
|
+
}
|
|
93
|
+
get instantChars() {
|
|
94
|
+
return this.instant;
|
|
95
|
+
}
|
|
96
|
+
set instantChars(value) {
|
|
97
|
+
this.instant = [...value];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Input Jaeum or Moeum to compose.
|
|
101
|
+
*/
|
|
102
|
+
addJamo(char) {
|
|
103
|
+
if (!this.compatibleHangleJamo(char))
|
|
104
|
+
return;
|
|
105
|
+
this.instant.push(char);
|
|
106
|
+
this.instantUpdate();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Save current composed strings by key.
|
|
110
|
+
*/
|
|
111
|
+
archive(key, txt = null) {
|
|
112
|
+
let match = false;
|
|
113
|
+
for (const ap of this.archives) {
|
|
114
|
+
if (ap.key === key) {
|
|
115
|
+
if (txt !== null) {
|
|
116
|
+
ap.compositionString = txt;
|
|
117
|
+
ap.instant = [];
|
|
118
|
+
ap.extra = "";
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
ap.compositionString = this.compositionString;
|
|
122
|
+
ap.instant = this.instant;
|
|
123
|
+
ap.extra = this.extra;
|
|
124
|
+
}
|
|
125
|
+
match = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!match) {
|
|
129
|
+
const newA = new ArchivePack();
|
|
130
|
+
if (txt !== null) {
|
|
131
|
+
newA.compositionString = txt;
|
|
132
|
+
newA.instant = [];
|
|
133
|
+
newA.extra = "";
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
newA.compositionString = this.compositionString;
|
|
137
|
+
newA.instant = [...this.instant];
|
|
138
|
+
newA.extra = this.extra;
|
|
139
|
+
}
|
|
140
|
+
newA.key = key;
|
|
141
|
+
this.archives.push(newA);
|
|
142
|
+
}
|
|
143
|
+
return this.archives.length;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Restore composed state from the saved key.
|
|
147
|
+
*/
|
|
148
|
+
restore(key) {
|
|
149
|
+
let match = false;
|
|
150
|
+
for (const ap of this.archives) {
|
|
151
|
+
if (ap.key === key) {
|
|
152
|
+
this.compositionString = ap.compositionString;
|
|
153
|
+
this.instant = [...ap.instant];
|
|
154
|
+
this.extra = ap.extra;
|
|
155
|
+
match = true;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!match) {
|
|
160
|
+
return "";
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
return this.compositionString + this.extra;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Logic engine to process the composition of characters in instant array.
|
|
168
|
+
*/
|
|
169
|
+
instantUpdate() {
|
|
170
|
+
switch (this.instant.length) {
|
|
171
|
+
case 0:
|
|
172
|
+
this.extra = "";
|
|
173
|
+
break;
|
|
174
|
+
case 1:
|
|
175
|
+
if (this.compatibleMoeum(this.instant[0])) {
|
|
176
|
+
this.compositionString += this.instant[0];
|
|
177
|
+
this.instant = [];
|
|
178
|
+
this.extra = "";
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.extra = this.instant[0];
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case 2:
|
|
185
|
+
if (this.compatibleMoeum(this.instant[1])) {
|
|
186
|
+
if (this.isMedialJamo(this.instant[1])) {
|
|
187
|
+
this.extra = this.combine(this.instant[0], this.instant[1]);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
this.compositionString += this.instant[0];
|
|
191
|
+
this.extra = this.instant[1];
|
|
192
|
+
this.instant.shift();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
this.compositionString += this.instant[0];
|
|
197
|
+
this.extra = this.instant[1];
|
|
198
|
+
this.instant.shift();
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case 3:
|
|
202
|
+
if (this.compatibleMoeum(this.instant[2])) {
|
|
203
|
+
if (this.combine(this.instant[1], this.instant[2]) !== "") {
|
|
204
|
+
this.instant[1] = this.combine(this.instant[1], this.instant[2]);
|
|
205
|
+
this.instant.pop();
|
|
206
|
+
this.extra = this.combine3Syllables(this.instant[0], this.instant[1], "");
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
this.compositionString += this.combine(this.instant[0], this.instant[1]);
|
|
210
|
+
this.compositionString += this.instant[2];
|
|
211
|
+
this.extra = "";
|
|
212
|
+
this.instant = [];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
if (this.isFinalJamo(this.instant[2])) {
|
|
217
|
+
if (this.isCombinableFinalJamo(this.instant[2]) || this.isInitialJamo(this.instant[2])) {
|
|
218
|
+
this.extra = this.combine3Syllables(this.instant[0], this.instant[1], this.instant[2]);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.instant[2]);
|
|
222
|
+
this.extra = "";
|
|
223
|
+
this.instant = [];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
this.compositionString += this.combine(this.instant[0], this.instant[1]);
|
|
228
|
+
this.extra = this.instant[2];
|
|
229
|
+
this.instant.shift();
|
|
230
|
+
this.instant.shift();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case 4:
|
|
235
|
+
if (this.compatibleMoeum(this.instant[3])) {
|
|
236
|
+
if (this.compatibleMoeum(this.instant[2])) {
|
|
237
|
+
this.compositionString += this.combine(this.instant[0], this.combine(this.instant[1], this.instant[2]));
|
|
238
|
+
this.extra = this.instant[3];
|
|
239
|
+
this.instant.shift();
|
|
240
|
+
this.instant.shift();
|
|
241
|
+
this.instant.shift();
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
if (this.isMedialJamo(this.instant[3])) {
|
|
245
|
+
this.compositionString += this.combine(this.instant[0], this.instant[1]);
|
|
246
|
+
this.extra = this.combine(this.instant[2], this.instant[3]);
|
|
247
|
+
this.instant.shift();
|
|
248
|
+
this.instant.shift();
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.instant[2]);
|
|
252
|
+
this.extra = this.instant[3];
|
|
253
|
+
this.instant.shift();
|
|
254
|
+
this.instant.shift();
|
|
255
|
+
this.instant.shift();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
if (this.compatibleMoeum(this.instant[2])) {
|
|
261
|
+
if (this.isCombinableFinalJamo(this.instant[3]) || this.isInitialJamo(this.instant[3])) {
|
|
262
|
+
this.extra = this.combine3Syllables(this.instant[0], this.combine(this.instant[1], this.instant[2]), this.instant[3]);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.combine(this.instant[1], this.instant[2]), this.instant[3]);
|
|
266
|
+
this.extra = "";
|
|
267
|
+
this.instant = [];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
if (this.combine(this.instant[2], this.instant[3]) !== "") {
|
|
272
|
+
if (this.isInitialJamo(this.instant[3])) {
|
|
273
|
+
this.extra = this.combine3Syllables(this.instant[0], this.instant[1], this.combine(this.instant[2], this.instant[3]));
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.combine(this.instant[2], this.instant[3]));
|
|
277
|
+
this.extra = "";
|
|
278
|
+
this.instant = [];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.instant[2]);
|
|
283
|
+
this.extra = this.instant[3];
|
|
284
|
+
this.instant.shift();
|
|
285
|
+
this.instant.shift();
|
|
286
|
+
this.instant.shift();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
case 5:
|
|
292
|
+
if (this.compatibleMoeum(this.instant[4])) {
|
|
293
|
+
if (this.combine(this.instant[1], this.instant[2]) !== "") {
|
|
294
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.combine(this.instant[1], this.instant[2]), "");
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.instant[2]);
|
|
298
|
+
}
|
|
299
|
+
this.extra = this.combine(this.instant[3], this.instant[4]);
|
|
300
|
+
this.instant.shift();
|
|
301
|
+
this.instant.shift();
|
|
302
|
+
this.instant.shift();
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
if (this.compatibleJaeum(this.instant[4])) {
|
|
306
|
+
if (this.isInitialJamo(this.instant[4])) {
|
|
307
|
+
this.compositionString += this.extra;
|
|
308
|
+
this.extra = this.instant[4];
|
|
309
|
+
this.instant.shift();
|
|
310
|
+
this.instant.shift();
|
|
311
|
+
this.instant.shift();
|
|
312
|
+
this.instant.shift();
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
this.compositionString += this.extra;
|
|
316
|
+
this.compositionString += this.instant[3];
|
|
317
|
+
this.extra = "";
|
|
318
|
+
this.instant.shift();
|
|
319
|
+
this.instant.shift();
|
|
320
|
+
this.instant.shift();
|
|
321
|
+
this.instant.shift();
|
|
322
|
+
this.instant.shift();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.instant[1], this.combine(this.instant[2], this.instant[3]));
|
|
327
|
+
this.compositionString += this.instant[4];
|
|
328
|
+
this.extra = "";
|
|
329
|
+
this.instant = [];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
case 6:
|
|
334
|
+
if (this.combine(this.instant[4], this.instant[5]) !== "") {
|
|
335
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.combine(this.instant[1], this.instant[2]), this.instant[3]);
|
|
336
|
+
this.extra = this.combine(this.instant[4], this.instant[5]);
|
|
337
|
+
this.instant.shift();
|
|
338
|
+
this.instant.shift();
|
|
339
|
+
this.instant.shift();
|
|
340
|
+
this.instant.shift();
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
this.compositionString += this.combine3Syllables(this.instant[0], this.combine(this.instant[1], this.instant[2]), this.combine(this.instant[3], this.instant[4]));
|
|
344
|
+
this.extra = this.instant[5];
|
|
345
|
+
this.instant.shift();
|
|
346
|
+
this.instant.shift();
|
|
347
|
+
this.instant.shift();
|
|
348
|
+
this.instant.shift();
|
|
349
|
+
this.instant.shift();
|
|
350
|
+
}
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
if (this.compositionString.length + this.extra.length > this.restrict) {
|
|
354
|
+
this.backSpace();
|
|
355
|
+
this.dispatchComposerEvent(HangleTextEvent.LIMITED, this.compositionString + this.extra);
|
|
356
|
+
}
|
|
357
|
+
// console.log("<instant : " + this.instant.join(",") + ">");
|
|
358
|
+
this.dispatchComposerEvent(HangleTextEvent.UPDATE, this.compositionString + this.extra);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Helper to dispatch events and invoke corresponding callbacks.
|
|
362
|
+
*/
|
|
363
|
+
dispatchComposerEvent(type, text) {
|
|
364
|
+
const event = new HangleTextEvent(type, text);
|
|
365
|
+
this.dispatchEvent(event);
|
|
366
|
+
if (type === HangleTextEvent.UPDATE && this.onUpdate) {
|
|
367
|
+
this.onUpdate(text);
|
|
368
|
+
}
|
|
369
|
+
else if (type === HangleTextEvent.LIMITED && this.onLimited) {
|
|
370
|
+
this.onLimited(text);
|
|
371
|
+
}
|
|
372
|
+
else if (type === HangleTextEvent.ERROR && this.onError) {
|
|
373
|
+
this.onError(text);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Insert character that is not available to compose (e.g. English, numbers, symbols).
|
|
378
|
+
*/
|
|
379
|
+
addSpecialChar(char, at = -1) {
|
|
380
|
+
if (this.compositionString.length + this.extra.length + 1 > this.restrict) {
|
|
381
|
+
this.dispatchComposerEvent(HangleTextEvent.LIMITED, this.compositionString + this.extra);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
this.compositionString += this.extra;
|
|
385
|
+
if (at === -1)
|
|
386
|
+
at = this.compositionString.length;
|
|
387
|
+
const strA = this.compositionString.slice(0, at);
|
|
388
|
+
const strB = this.compositionString.slice(at);
|
|
389
|
+
this.compositionString = strA + char + strB;
|
|
390
|
+
this.extra = "";
|
|
391
|
+
this.instant = [];
|
|
392
|
+
this.dispatchComposerEvent(HangleTextEvent.UPDATE, this.compositionString);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Add Jamo by Unicode character code.
|
|
396
|
+
*/
|
|
397
|
+
addJamoUnicode(code) {
|
|
398
|
+
this.addJamo(String.fromCharCode(code));
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Delete character by backspace.
|
|
402
|
+
*/
|
|
403
|
+
backSpace(at = -1) {
|
|
404
|
+
if (this.instant.length > 0) {
|
|
405
|
+
this.instant.pop();
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
this.compositionString += this.extra;
|
|
409
|
+
if (at === -1)
|
|
410
|
+
at = this.compositionString.length;
|
|
411
|
+
this.compositionString =
|
|
412
|
+
this.compositionString.slice(0, at - 1) + this.compositionString.slice(at);
|
|
413
|
+
this.extra = "";
|
|
414
|
+
this.instant = [];
|
|
415
|
+
}
|
|
416
|
+
this.instantUpdate();
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Composes two Jamos and returns array with composed character or split ones.
|
|
420
|
+
*/
|
|
421
|
+
compare2Jamo(charA, charB) {
|
|
422
|
+
const re = [];
|
|
423
|
+
if (this.combine(charA, charB) !== "") {
|
|
424
|
+
re.push(this.combine(charA, charB));
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
re.push(charA);
|
|
428
|
+
re.push(charB);
|
|
429
|
+
}
|
|
430
|
+
return re;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Composes three Jamos.
|
|
434
|
+
*/
|
|
435
|
+
compare3Syllables(init, mid, fin) {
|
|
436
|
+
let re = [];
|
|
437
|
+
if (this.isInitialJamo(init) && this.isMedialJamo(mid) && this.isFinalJamo(fin)) {
|
|
438
|
+
re.push(this.combine3Syllables(init, mid, fin));
|
|
439
|
+
}
|
|
440
|
+
else if (this.isInitialJamo(init) && this.isMedialJamo(mid) && !this.isFinalJamo(fin)) {
|
|
441
|
+
re.push(this.combine3Syllables(init, mid, ""));
|
|
442
|
+
re.push(fin);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
re = [init, mid, fin];
|
|
446
|
+
}
|
|
447
|
+
return re;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Checks if string is a valid Hangul syllable or Jamo.
|
|
451
|
+
*/
|
|
452
|
+
compatibleHangleJamo(char) {
|
|
453
|
+
if (char.length !== 1) {
|
|
454
|
+
throw new Error("1개의 글자가 필요합니다. only one character is available.");
|
|
455
|
+
}
|
|
456
|
+
const code = char.charCodeAt(0);
|
|
457
|
+
return code >= 0x3131 && code <= 0x3163;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Checks if character is a Jaeum.
|
|
461
|
+
*/
|
|
462
|
+
compatibleJaeum(char) {
|
|
463
|
+
const code = char.charCodeAt(0);
|
|
464
|
+
return code > 0x3130 && code < 0x314f;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Checks if character is a Moeum.
|
|
468
|
+
*/
|
|
469
|
+
compatibleMoeum(char) {
|
|
470
|
+
const code = char.charCodeAt(0);
|
|
471
|
+
return code > 0x314e && code < 0x3164;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Deletes characters at target index.
|
|
475
|
+
*/
|
|
476
|
+
del(at = -1) {
|
|
477
|
+
this.compositionString += this.extra;
|
|
478
|
+
const str = this.compositionString;
|
|
479
|
+
if (at === -1)
|
|
480
|
+
at = this.compositionString.length;
|
|
481
|
+
this.compositionString = str.slice(0, at) + str.slice(at + 2);
|
|
482
|
+
this.extra = "";
|
|
483
|
+
this.instant = [];
|
|
484
|
+
this.dispatchComposerEvent(HangleTextEvent.UPDATE, this.compositionString);
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Resets composer state.
|
|
488
|
+
*/
|
|
489
|
+
reset() {
|
|
490
|
+
this.compositionString = "";
|
|
491
|
+
this.extra = "";
|
|
492
|
+
this.instant = [];
|
|
493
|
+
this.archives = [];
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Checks if character is in FINAL.
|
|
497
|
+
*/
|
|
498
|
+
isFinalJamo(char) {
|
|
499
|
+
const code = char.charCodeAt(0);
|
|
500
|
+
return HangleUnicodeComposer.FINAL.indexOf(code) >= 0;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Checks if character is in INITIAL.
|
|
504
|
+
*/
|
|
505
|
+
isInitialJamo(char) {
|
|
506
|
+
const code = char.charCodeAt(0);
|
|
507
|
+
return HangleUnicodeComposer.INITIAL.indexOf(code) >= 0;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Checks if character is in MEDIAL.
|
|
511
|
+
*/
|
|
512
|
+
isMedialJamo(char) {
|
|
513
|
+
const code = char.charCodeAt(0);
|
|
514
|
+
return HangleUnicodeComposer.MEDIAL.indexOf(code) >= 0;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Adds space.
|
|
518
|
+
*/
|
|
519
|
+
space(at = -1) {
|
|
520
|
+
if (this.compositionString.length + this.extra.length + 1 > this.restrict) {
|
|
521
|
+
this.dispatchComposerEvent(HangleTextEvent.LIMITED, this.compositionString + this.extra);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
this.compositionString += this.extra;
|
|
525
|
+
if (at === -1)
|
|
526
|
+
at = this.compositionString.length;
|
|
527
|
+
const strA = this.compositionString.slice(0, at);
|
|
528
|
+
const strB = this.compositionString.slice(at);
|
|
529
|
+
this.compositionString = strA + " " + strB;
|
|
530
|
+
this.extra = "";
|
|
531
|
+
this.instant = [];
|
|
532
|
+
this.dispatchComposerEvent(HangleTextEvent.UPDATE, this.compositionString);
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Combines initial, medial, and final into a single Hangul syllable.
|
|
536
|
+
*/
|
|
537
|
+
combine3Syllables(init, mid, fin) {
|
|
538
|
+
const initCode = HangleUnicodeComposer.INITIAL.indexOf(init.charCodeAt(0));
|
|
539
|
+
const midCode = HangleUnicodeComposer.MEDIAL.indexOf(mid.charCodeAt(0));
|
|
540
|
+
const finCode = fin === "" ? 0 : HangleUnicodeComposer.FINAL.indexOf(fin.charCodeAt(0));
|
|
541
|
+
return String.fromCharCode((initCode * 588 + midCode * 28 + finCode) + 44032);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Combine two characters (Jaeum + Jaeum, Moeum + Moeum, or Initial + Medial)
|
|
545
|
+
*/
|
|
546
|
+
combine(charA, charB) {
|
|
547
|
+
let re = "";
|
|
548
|
+
let compCode = 0;
|
|
549
|
+
const charCodeA = charA.charCodeAt(0);
|
|
550
|
+
const charCodeB = charB.charCodeAt(0);
|
|
551
|
+
if (this.compatibleJaeum(charA) && this.compatibleJaeum(charB)) {
|
|
552
|
+
switch (charCodeA) {
|
|
553
|
+
case 0x3131: // ㄱ
|
|
554
|
+
if (charCodeB === 0x3145)
|
|
555
|
+
compCode = 0x3133; // ㄳ
|
|
556
|
+
break;
|
|
557
|
+
case 0x3134: // ㄴ
|
|
558
|
+
if (charCodeB === 0x3148)
|
|
559
|
+
compCode = 0x3135; // ㄵ
|
|
560
|
+
if (charCodeB === 0x314e)
|
|
561
|
+
compCode = 0x3136; // ㄶ
|
|
562
|
+
break;
|
|
563
|
+
case 0x3139: // ㄹ
|
|
564
|
+
if (charCodeB === 0x3131)
|
|
565
|
+
compCode = 0x313a; // ㄺ
|
|
566
|
+
if (charCodeB === 0x3141)
|
|
567
|
+
compCode = 0x313b; // ㄻ
|
|
568
|
+
if (charCodeB === 0x3142)
|
|
569
|
+
compCode = 0x313c; // ㄼ
|
|
570
|
+
if (charCodeB === 0x3145)
|
|
571
|
+
compCode = 0x313d; // ㄽ
|
|
572
|
+
if (charCodeB === 0x314c)
|
|
573
|
+
compCode = 0x313e; // ㄾ
|
|
574
|
+
if (charCodeB === 0x314d)
|
|
575
|
+
compCode = 0x313f; // ㄿ
|
|
576
|
+
if (charCodeB === 0x314e)
|
|
577
|
+
compCode = 0x3140; // ㅀ
|
|
578
|
+
break;
|
|
579
|
+
case 0x3142: // ㅂ
|
|
580
|
+
if (charCodeB === 0x3145)
|
|
581
|
+
compCode = 0x3144; // ㅄ
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
else if (this.compatibleMoeum(charA) && this.compatibleMoeum(charB)) {
|
|
586
|
+
switch (charCodeA) {
|
|
587
|
+
case 0x3157: // ㅗ
|
|
588
|
+
if (charCodeB === 0x314f)
|
|
589
|
+
compCode = 0x3158; // ㅘ
|
|
590
|
+
if (charCodeB === 0x3150)
|
|
591
|
+
compCode = 0x3159; // ㅙ
|
|
592
|
+
if (charCodeB === 0x3163)
|
|
593
|
+
compCode = 0x315a; // ㅚ
|
|
594
|
+
break;
|
|
595
|
+
case 0x315c: // ㅜ
|
|
596
|
+
if (charCodeB === 0x3153)
|
|
597
|
+
compCode = 0x315d; // ㅝ
|
|
598
|
+
if (charCodeB === 0x3154)
|
|
599
|
+
compCode = 0x315e; // ㅞ
|
|
600
|
+
if (charCodeB === 0x3163)
|
|
601
|
+
compCode = 0x315f; // ㅟ
|
|
602
|
+
break;
|
|
603
|
+
case 0x3161: // ㅡ
|
|
604
|
+
if (charCodeB === 0x3163)
|
|
605
|
+
compCode = 0x3162; // ㅢ
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else if (this.isInitialJamo(charA) && this.isMedialJamo(charB)) {
|
|
610
|
+
re = this.combine3Syllables(charA, charB, "");
|
|
611
|
+
}
|
|
612
|
+
if (compCode !== 0) {
|
|
613
|
+
return String.fromCharCode(compCode);
|
|
614
|
+
}
|
|
615
|
+
return re;
|
|
616
|
+
}
|
|
617
|
+
isCombinableFinalJamo(char) {
|
|
618
|
+
let re = false;
|
|
619
|
+
switch (char.charCodeAt(0)) {
|
|
620
|
+
case 0x3131: // ㄱ
|
|
621
|
+
case 0x3134: // ㄴ
|
|
622
|
+
case 0x3139: // ㄹ
|
|
623
|
+
case 0x3142: // ㅂ
|
|
624
|
+
re = true;
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
return re;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event class used in HangulUnicodeComposer.
|
|
3
|
+
* Replicates the AS3 HangulTextEvent behaviour.
|
|
4
|
+
*/
|
|
5
|
+
export declare class HangulTextEvent extends Event {
|
|
6
|
+
/**
|
|
7
|
+
* Dispatched when the composed string changes.
|
|
8
|
+
*/
|
|
9
|
+
static readonly UPDATE = "update";
|
|
10
|
+
/**
|
|
11
|
+
* Dispatched when the composed string length reaches the restricted limit.
|
|
12
|
+
*/
|
|
13
|
+
static readonly LIMITED = "limited";
|
|
14
|
+
/**
|
|
15
|
+
* Dispatched when composition errors occur.
|
|
16
|
+
*/
|
|
17
|
+
static readonly ERROR = "error";
|
|
18
|
+
/**
|
|
19
|
+
* Composed string data at the time of the event.
|
|
20
|
+
*/
|
|
21
|
+
string: string;
|
|
22
|
+
constructor(type: string, stringData: string, bubbles?: boolean, cancelable?: boolean);
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event class used in HangulUnicodeComposer.
|
|
3
|
+
* Replicates the AS3 HangulTextEvent behaviour.
|
|
4
|
+
*/
|
|
5
|
+
export class HangulTextEvent extends Event {
|
|
6
|
+
/**
|
|
7
|
+
* Dispatched when the composed string changes.
|
|
8
|
+
*/
|
|
9
|
+
static UPDATE = "update";
|
|
10
|
+
/**
|
|
11
|
+
* Dispatched when the composed string length reaches the restricted limit.
|
|
12
|
+
*/
|
|
13
|
+
static LIMITED = "limited";
|
|
14
|
+
/**
|
|
15
|
+
* Dispatched when composition errors occur.
|
|
16
|
+
*/
|
|
17
|
+
static ERROR = "error";
|
|
18
|
+
/**
|
|
19
|
+
* Composed string data at the time of the event.
|
|
20
|
+
*/
|
|
21
|
+
string;
|
|
22
|
+
constructor(type, stringData, bubbles = false, cancelable = false) {
|
|
23
|
+
super(type, { bubbles, cancelable });
|
|
24
|
+
this.string = stringData;
|
|
25
|
+
}
|
|
26
|
+
toString() {
|
|
27
|
+
return `${this.type} ${this.string}`;
|
|
28
|
+
}
|
|
29
|
+
}
|