spiegel-keyman/web/source/text/deadkeys.ts
2019-02-19 15:19:26 +07:00

160 lines
No EOL
3.9 KiB
TypeScript

namespace com.keyman.text {
// Defines the base Deadkey-tracking object.
export class Deadkey {
p: number; // Position of deadkey
d: number; // Numerical id of the deadkey
o: number; // Ordinal value of the deadkey (resolves same-place conflicts)
matched: number;
static ordinalSeed: number = 0;
constructor(pos: number, id: number) {
this.p = pos;
this.d = id;
this.o = Deadkey.ordinalSeed++;
}
match(p: number, d: number): boolean {
var result:boolean = (this.p == p && this.d == d);
return result;
}
set(): void {
this.matched = 1;
}
reset(): void {
this.matched = 0;
}
before(other: Deadkey): boolean {
return this.o < other.o;
}
clone(): Deadkey {
let dk = new Deadkey(this.p, this.d);
dk.o = this.o;
return dk;
}
/**
* Sorts the deadkeys in reverse order.
*/
static sortFunc = function(a: Deadkey, b: Deadkey) {
// We want descending order, so we want 'later' deadkeys first.
if(a.p != b.p) {
return b.p - a.p;
} else {
return b.o - a.o;
}
};
}
// Object-orients deadkey management.
export class DeadkeyTracker {
dks: Deadkey[] = [];
toSortedArray(): Deadkey[] {
this.dks = this.dks.sort(Deadkey.sortFunc);
return [].concat(this.dks);
}
clone(): DeadkeyTracker {
let dkt = new DeadkeyTracker();
let dks = this.toSortedArray();
// Make sure to clone the deadkeys themselves - the Deadkey object is mutable.
dkt.dks = [];
dks.forEach(function(value: Deadkey) {
dkt.dks.push(value.clone());
});
return dkt;
}
/**
* Function isMatch
* Scope Public
* @param {number} caretPos current cursor position
* @param {number} n expected offset of deadkey from cursor
* @param {number} d deadkey
* @return {boolean} True if deadkey found selected context matches val
* Description Match deadkey at current cursor position
*/
isMatch(caretPos: number, n: number, d: number): boolean {
if(this.dks.length == 0) {
return false; // I3318
}
var sp=caretPos;
n = sp - n;
for(var i = 0; i < this.dks.length; i++) {
// Don't re-match an already-matched deadkey. It's possible to have two identical
// entries, and they should be kept separately.
if(this.dks[i].match(n, d) && !this.dks[i].matched) {
this.dks[i].set();
// Assumption: since we match the first possible entry in the array, we
// match the entry with the lower ordinal - the 'first' deadkey in the position.
return true; // I3318
}
}
this.resetMatched(); // I3318
return false;
}
add(dk: Deadkey) {
this.dks = this.dks.concat(dk);
}
remove(dk: Deadkey) {
var index = this.dks.indexOf(dk);
this.dks.splice(index, 1);
}
clear() {
this.dks = [];
}
resetMatched() {
for(let dk of this.dks) {
dk.reset();
}
}
deleteMatched(): void {
for(var Li = 0; Li < this.dks.length; Li++) {
if(this.dks[Li].matched) {
this.dks.splice(Li--, 1); // Don't forget to decrement!
}
}
}
/**
* Function adjustPositions (formerly _DeadkeyAdjustPos)
* Scope Private
* @param {number} Lstart start position in context
* @param {number} Ldelta characters to adjust by
* Description Adjust saved positions of deadkeys in context
*/
adjustPositions(Lstart: number, Ldelta: number): void {
if(Ldelta == 0) {
return;
}
for(let dk of this.dks) {
if(dk.p > Lstart) {
dk.p += Ldelta;
}
}
}
count(): number {
return this.dks.length;
}
}
}