Skip to content

Commit 8647cef

Browse files
committed
Comments
1 parent 48841db commit 8647cef

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

kashida.js

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { JoiningGroup, JoiningType, JOINING_GROUP, JOINING_TYPE } from './arabic_joining.js';
66

7+
// A Kashida insertion point.
78
export class Kashida {
89
constructor(index, priority, max = null) {
910
this.index = index;
@@ -12,6 +13,8 @@ export class Kashida {
1213
}
1314
}
1415

16+
// An array of Kashida insertion points. Makes sure that there are no more than
17+
// one Kashida at the same index.
1518
class Kashidas extends Array {
1619
append(kashida) {
1720
if (this.some(k => k.index === kashida.index)) {
@@ -21,11 +24,14 @@ class Kashidas extends Array {
2124
}
2225
}
2326

27+
// Supported Kashida algorithms.
2428
export const Algorithm = {
2529
SIMPLE: 'simple',
2630
NASKH: 'naskh'
2731
};
2832

33+
// Match any Kashida character that is not followed by a small alef or hamza
34+
// above.
2935
const KASHIDA_RE = /(\u0640)(?!\u0670|\u0654)/;
3036

3137
const ALEF = Object.keys(JOINING_GROUP).filter(c => JOINING_GROUP[c] === JoiningGroup.Alef).map(c => String.fromCharCode(c));
@@ -50,6 +56,9 @@ function isArabicLetter(c) {
5056
return c.match(/\p{L}/u) && c.match(/\p{Script=Arab}/u);
5157
};
5258

59+
// Get the next Arabic letter in a text string skipping combining marks, or None
60+
// if next base character is not an Arabic letter.If step is negative, it will
61+
// get the previous Arabic letter.
5362
function getNextArabicLetter(text, index, step = 1) {
5463
while (index >= 0 && index < text.length) {
5564
const c = text[index];
@@ -65,27 +74,50 @@ function getNextArabicLetter(text, index, step = 1) {
6574
return null;
6675
}
6776

77+
// Get the previous Arabic letter in a text string skipping combining marks, or
78+
// None if previous base character is not an Arabic letter.
6879
function getPreviousArabicLetter(text, index) {
6980
return getNextArabicLetter(text, index, -1);
7081
}
7182

83+
// Check if the character at the given index joins to the left.
7284
export function joinsLeft(word, index) {
85+
// Get the current Letter, skipping combining marks.
7386
const c1 = getNextArabicLetter(word, index);
74-
if (!c1) return false;
75-
if (RIGHT_JOINING.includes(c1[0])) return false;
76-
if (!getNextArabicLetter(word, c1[1] + 1)) return false;
87+
if (!c1)
88+
return false;
89+
90+
// If it is righ joining, then it does not join to the left.
91+
if (RIGHT_JOINING.includes(c1[0]))
92+
return false;
93+
94+
// Get the next Letter, skipping combining marks.
95+
if (!getNextArabicLetter(word, c1[1] + 1))
96+
return false;
97+
7798
return true;
7899
}
79100

101+
// Check if the character at the given index joins to the right.
80102
export function joinsRight(word, index) {
103+
// Get the current Letter, skipping combining marks.
81104
const c1 = getPreviousArabicLetter(word, index);
82-
if (!c1) return false;
105+
if (!c1)
106+
return false;
107+
108+
// Get the previous Letter, skipping combining marks.
83109
const c2 = getPreviousArabicLetter(word, c1[1] - 1);
84-
if (!c2) return false;
85-
if (RIGHT_JOINING.includes(c2[0])) return false;
110+
if (!c2)
111+
return false;
112+
113+
// If it is righ joining, then it does not join to the left.
114+
if (RIGHT_JOINING.includes(c2[0]))
115+
return false;
116+
86117
return true;
87118
}
88119

120+
// Check if the character at the given index is a Lam Alef ligature.
89121
function isLamAlef(word, index) {
90122
const c = word[index];
91123
if (ALEF.includes(c)) {
@@ -97,6 +129,9 @@ function isLamAlef(word, index) {
97129
return false;
98130
}
99131

132+
// Find Kashida insertion points in Arabic text using Microsoft's algorithm as
133+
// described in:
134+
// https://web.archive.org/web/20130308140133/microsoft.com/middleeast/msdn/JustifyingText-CSS.aspx
100135
function findKashidaPointsSimple(word) {
101136
const kashidas = new Kashidas();
102137

@@ -151,6 +186,12 @@ function findKashidaPointsSimple(word) {
151186
return kashidas;
152187
}
153188

189+
// Find Kashida insertion points in a word.
190+
//
191+
// Args:
192+
// word: A text word.
193+
// remove_existing_kashida: Remove existing Kashida characters.
194+
// algorithm: Kashida algorithm to use.
154195
export function findKashidaPoints(word, algorithm = Algorithm.SIMPLE, removeExistingKashida = true) {
155196
if (removeExistingKashida) {
156197
word = word.replace(KASHIDA_RE, '');
@@ -166,6 +207,13 @@ export function findKashidaPoints(word, algorithm = Algorithm.SIMPLE, removeExis
166207
return [word, kashidas];
167208
}
168209

210+
// Insert kashida characters into a word.
211+
//
212+
// Args:
213+
// word: A text word.
214+
// kashidas: Kashida insertion points.
215+
// all_kashidas: Insert all possible Kashidas in a word, default is to
216+
// insert only the Kashida with the highest priority.
169217
export function insertKashidas(word, kashidas, allKashidas = false) {
170218
if (!kashidas.length) return word;
171219

@@ -184,6 +232,14 @@ export function insertKashidas(word, kashidas, allKashidas = false) {
184232
return word;
185233
}
186234

235+
// Find possible Kashida points and insert them in a text string.
236+
//
237+
// Args:
238+
// text: A text string.
239+
// algorithm: Kashida algorithm to use.
240+
// remove_existing_kashida: Remove existing Kashida characters.
241+
// all_kashidas: Insert all possible Kashidas in a word, default is to
242+
// insert only the Kashida with the highest priority.
187243
export function makeKashidaString(text, algorithm = Algorithm.SIMPLE, removeExistingKashida = true, allKashidas = false) {
188244
const words = text.split(' ');
189245
const ret = words.map(word => {

0 commit comments

Comments
 (0)