@syncfusion/ej2-documenteditor
Version:
Feature-rich document editor control with built-in support for context menu, options pane and dialogs.
879 lines (878 loc) • 44.9 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import { isNullOrUndefined, isUndefined } from '@syncfusion/ej2-base';
import { WCharacterFormat } from '../index';
import { defaultFont } from '../../index';
import { HelperMethods } from '../editor/editor-helper';
import { CharacterRangeType, FontScriptType } from '../../index';
/**
* @private
*/
var TextHelper = /** @class */ (function () {
function TextHelper(documentHelper) {
this.paragraphMarkInfo = {};
this.documentHelper = documentHelper;
if (!isNullOrUndefined(documentHelper)) {
this.context = documentHelper.containerContext;
}
}
Object.defineProperty(TextHelper.prototype, "paragraphMark", {
get: function () {
return '¶';
},
enumerable: true,
configurable: true
});
Object.defineProperty(TextHelper.prototype, "lineBreakMark", {
get: function () {
return '↲';
},
enumerable: true,
configurable: true
});
TextHelper.prototype.getEnSpaceCharacter = function () {
return String.fromCharCode(8194);
};
TextHelper.prototype.repeatChar = function (char, count) {
var text = '';
for (var i = 0; i < count; i++) {
text += char;
}
return text;
};
TextHelper.prototype.getParagraphMarkWidth = function (characterFormat) {
return this.getParagraphMarkSize(characterFormat).Width;
};
TextHelper.prototype.getParagraphMarkSize = function (characterFormat) {
var format = this.getFormatText(characterFormat);
if (this.paragraphMarkInfo["" + format]) {
return this.paragraphMarkInfo["" + format];
}
// Gets the text element's width;
var width = this.getWidth(this.paragraphMark, characterFormat);
// Calculate the text element's height and baseline offset.
var textHelper = this.getHeight(characterFormat);
var textSizeInfo = {
'Width': width, 'Height': textHelper.Height, 'BaselineOffset': textHelper.BaselineOffset
};
if (characterFormat.hidden) {
return textSizeInfo;
}
return this.paragraphMarkInfo["" + format] = textSizeInfo;
};
TextHelper.prototype.getTextSize = function (elementBox, characterFormat) {
// Gets the text element's width;
var textTrimEndWidth = 0;
var isRTL = characterFormat.bidi || this.isRTLText(elementBox.text);
var text = this.setText(elementBox.text, isRTL, characterFormat.bdo);
if (text === '\r') {
text = String.fromCharCode(182);
}
textTrimEndWidth = this.getWidth(text, characterFormat, elementBox.scriptType);
elementBox.width = textTrimEndWidth;
// Calculate the text element's height and baseline offset.
var textHelper = this.getHeight(characterFormat, elementBox.scriptType);
if (!(this.documentHelper.compatibilityMode === 'Word2003' && elementBox.isColumnBreak)) {
elementBox.height = textHelper.Height;
}
elementBox.baselineOffset = textHelper.BaselineOffset;
if (elementBox.text[elementBox.text.length - 1] === ' ') {
textTrimEndWidth = this.getWidth(HelperMethods.trimEnd(elementBox.text), characterFormat, elementBox.scriptType);
}
elementBox.trimEndWidth = textTrimEndWidth;
return textTrimEndWidth;
};
TextHelper.prototype.getHeight = function (characterFormat, scriptType) {
var fontToRender = this.getFontNameToRender(scriptType, characterFormat);
// Get character format property as below predefined structure to make it easy to check and retrieve
// Predefined static structure `[FontName];[FontSize];bold;italic` to maintain as key in the collection
var key = this.getFormatText(characterFormat, fontToRender);
if (!isNullOrUndefined(this.documentHelper.heightInfoCollection["" + key])) {
if (characterFormat.hidden) {
var heightInfo = __assign({}, this.documentHelper.heightInfoCollection["" + key]);
if (heightInfo.Height) {
heightInfo.Height = 0;
}
return heightInfo;
}
return this.documentHelper.heightInfoCollection["" + key];
}
var sizeInfo = this.documentHelper.owner.textMeasureHelper.getHeightInternal(characterFormat, fontToRender);
this.documentHelper.heightInfoCollection["" + key] = __assign({}, sizeInfo);
if (characterFormat.hidden) {
sizeInfo.Height = 0;
}
return sizeInfo;
};
TextHelper.prototype.getFormatText = function (characterFormat, fontToRender) {
var formatText = '';
if (!isNullOrUndefined(fontToRender)) {
formatText = fontToRender.toLocaleLowerCase();
}
else {
formatText = characterFormat.fontFamily.toLocaleLowerCase();
}
var isBidi = characterFormat.bidi || characterFormat.complexScript;
var font = isBidi ? characterFormat.fontSizeBidi : characterFormat.fontSize;
var bold = isBidi ? characterFormat.boldBidi : characterFormat.bold;
var italic = isBidi ? characterFormat.italicBidi : characterFormat.italic;
formatText += ';' + font;
if (bold) {
formatText += ';' + 'bold';
}
if (italic) {
formatText += ';' + 'italic';
}
return formatText;
};
TextHelper.prototype.measureTextExcludingSpaceAtEnd = function (text, characterFormat, scriptType) {
return this.getWidth(HelperMethods.trimEnd(text), characterFormat, scriptType);
};
TextHelper.prototype.getWidth = function (text, characterFormat, scriptType) {
if (characterFormat.hidden) {
return 0;
}
if (text.match('\v')) {
text.replace('\v', this.lineBreakMark);
}
var bold = '';
var italic = '';
var fontFamily = '';
var isBidi = characterFormat.bidi || characterFormat.complexScript;
var fontSize = isBidi ? characterFormat.fontSizeBidi : characterFormat.fontSize;
bold = isBidi ? (characterFormat.boldBidi ? 'bold' : '') : (characterFormat.bold ? 'bold' : '');
italic = isBidi ? (characterFormat.italicBidi ? 'italic' : '') : (characterFormat.italic ? 'italic' : '');
fontFamily = this.getFontNameToRender(scriptType, characterFormat);
fontSize = fontSize === 0 ? 0.5 : fontSize / (characterFormat.baselineAlignment === 'Normal' ? 1 : 1.5);
this.context.font = bold + ' ' + italic + ' ' + fontSize + 'pt' + ' ' + '"' + fontFamily + '"';
this.context.letterSpacing = characterFormat.characterSpacing + 'pt';
var scaleFactor = (characterFormat.scaling / 100);
if (characterFormat.allCaps) {
text = text.toUpperCase();
}
//ES-853789:For combine character we need to add the base character to get the width of the text.
if (text === '\u0336') {
text += 'A';
}
return Math.abs(this.context.measureText(text).width * scaleFactor);
};
TextHelper.prototype.setText = function (textToRender, isBidi, bdo, isRender) {
if (isNullOrUndefined(isRender)) {
isRender = false;
}
if (textToRender.length === 0) {
return '';
}
var isRtlText = isBidi;
if ((!isRtlText && (bdo === 'RTL')) || (isRtlText && (bdo === 'LTR'))) {
textToRender = HelperMethods.reverseString(textToRender);
}
else if (isRender && isRtlText && HelperMethods.endsWith(textToRender)) {
var spaceCount = textToRender.length - HelperMethods.trimEnd(textToRender).length;
textToRender = HelperMethods.addSpace(spaceCount) + HelperMethods.trimEnd(textToRender);
}
return textToRender;
};
TextHelper.prototype.measureText = function (text, characterFormat, scriptType) {
// Gets the text element's width;
var width = this.getWidth(text, characterFormat, scriptType);
// Calculate the text element's height and baseline offset.
var textHelper = this.getHeight(characterFormat, scriptType);
return {
'Width': width, 'Height': textHelper.Height, 'BaselineOffset': textHelper.BaselineOffset
};
};
TextHelper.prototype.updateTextSize = function (elementBox, paragraph) {
if (elementBox.characterFormat.hidden && paragraph.height === 0) {
return;
}
var format = new WCharacterFormat(undefined);
var listCharacterFormat = elementBox.listLevel.characterFormat;
var breakCharacterFormat = paragraph.characterFormat;
format.fontSize = listCharacterFormat.hasValue('fontSize') ? listCharacterFormat.fontSize : breakCharacterFormat.fontSize;
format.fontFamily = listCharacterFormat.hasValue('fontFamily') ? listCharacterFormat.fontFamily : breakCharacterFormat.fontFamily;
var bold = '';
var italic = '';
var baselineAlignment = listCharacterFormat.baselineAlignment === 'Normal' ?
breakCharacterFormat.baselineAlignment : listCharacterFormat.baselineAlignment;
bold = listCharacterFormat.hasValue('bold') ? listCharacterFormat.bold ? 'bold' : '' : breakCharacterFormat.bold ? 'bold' : '';
italic = listCharacterFormat.hasValue('italic') ? listCharacterFormat.italic ? 'italic' : ''
: breakCharacterFormat.italic ? 'italic' : '';
format.baselineAlignment = baselineAlignment;
if (bold) {
format.bold = true;
}
if (italic) {
format.italic = true;
}
var isRTL = format.bidi || this.isRTLText(elementBox.text);
var text = this.setText(elementBox.text, isRTL, format.bdo);
elementBox.width = this.getWidth(text, format);
// Calculate the text element's height and baseline offset.
var textHelper = this.getHeight(format);
elementBox.height = textHelper.Height;
elementBox.baselineOffset = textHelper.BaselineOffset;
format.destroy();
};
TextHelper.prototype.containsSpecialCharAlone = function (text) {
/* eslint-disable */
var specialChars = '*|.\:[]{}-`\;()@&$#%!~?,' + ' ' + "'";
for (var i = 0; i < text.length; i++) {
if (specialChars.indexOf(text.charAt(i)) === -1) {
return false;
}
}
return true;
};
TextHelper.prototype.containsNumberAlone = function (text) {
/* eslint-disable */
var number = '0123456789';
if (text === '') {
return false;
}
for (var i = 0; i < text.length; i++) {
if (number.indexOf(text.charAt(i)) === -1) {
return false;
}
}
return true;
};
TextHelper.prototype.containsCombinationText = function (element) {
/* eslint-disable */
if (element.text.match(/^[0-9]+$/) && element.paragraph.bidi) {
return true;
}
else {
return false;
}
};
TextHelper.prototype.inverseCharacter = function (ch) {
switch (ch) {
//Specify the '('
case '(':
//Specify the ')'
return ')';
//Specify the ')'
case ')':
//Specify the '('
return '(';
//Specify the '<'
case '<':
//Specify the '>'
return '>';
//Specify the '>'
case '>':
//Specify the '<'
return '<';
//Specify the '{'
case '{':
//Specify the '}'
return '}';
//Specify the '}'
case '}':
//Specify the '{'
return '{';
//Specify the '['
case '[':
//Specify the ']'
return ']';
//Specify the ']'
case ']':
//Specify the '['
return '[';
default:
return ch;
}
};
TextHelper.prototype.containsSpecialChar = function (text) {
var specialChars = '*|.\:[]{}-`\;()@&$#%!~?' + ' ';
for (var i = 0; i < text.length; i++) {
if (specialChars.indexOf(text.charAt(i)) !== -1) {
return true;
}
}
return false;
};
/**
* @private
* @param {string} text - Specifies the text
* @returns {boolean} - Returns true if given text it right to left.
*/
TextHelper.prototype.isRTLText = function (text) {
var isRTL = false;
if (!isNullOrUndefined(text)) {
for (var i = 0; i < text.length; i++) {
var temp = text[i];
if ((temp >= String.fromCharCode(1424) && temp <= String.fromCharCode(1535)) ////Script-Hebr, Hebrew characters https://en.wikipedia.org/wiki/Hebrew_alphabet#Unicode_and_HTML (https://en.wikipedia.org/wiki/Hebrew_(Unicode_block))
|| (temp >= String.fromCharCode(64285) && temp <= String.fromCharCode(64335)) //Script-Hebr, Hebrew Alphabetic Presentation Forms characters https://en.wikipedia.org/wiki/Alphabetic_Presentation_Forms
|| (temp >= String.fromCharCode(1536) && temp <= String.fromCharCode(1791)) //Arabic - Urdu characters
|| (temp >= String.fromCharCode(1872) && temp <= String.fromCharCode(1919)) //Arabic - Urdu characters
|| (temp >= String.fromCharCode(2208) && temp <= String.fromCharCode(2303)) //Arabic characters
|| (temp >= String.fromCharCode(64336) && temp <= String.fromCharCode(65023)) //Arabic - Urdu characters
|| (temp >= String.fromCharCode(65136) && temp <= String.fromCharCode(65279)) //Arabic - Urdu characters
|| (temp >= String.fromCharCode(43392) && temp <= String.fromCharCode(43487)) //Javanese characters
|| (temp >= String.fromCharCode(1792) && temp <= String.fromCharCode(1871)) //Syriac characters
|| (temp >= String.fromCharCode(1920) && temp <= String.fromCharCode(1983)) //Thaana characters
|| (temp >= String.fromCharCode(2112) && temp <= String.fromCharCode(2143)) //Mandiac characters
|| (temp >= String.fromCharCode(1984) && temp <= String.fromCharCode(2047)) //N'Ko characters
|| (temp >= String.fromCharCode(2048) && temp <= String.fromCharCode(2111)) //Samaritan characters
//Tifinag characters
|| (temp >= String.fromCharCode(11568) && temp <= String.fromCharCode(11647))) {
isRTL = true;
break;
}
}
}
return isRTL;
};
/**
* @private
* @param {string} text - Specifies the text
* @param {FontScriptType} scriptType - Specifies the script type
* @returns {boolean} - Returns true if given text is unicode text.
*/
TextHelper.prototype.isUnicodeText = function (text, scriptType) {
var isUnicode = false;
if (!isNullOrUndefined(text)) {
for (var i = 0; i < text.length; i++) {
var temp = text[i];
if (((temp >= '\u3000' && temp <= '\u30ff') // Japanese characters
|| (temp >= '\uff00' && temp <= '\uffef') // Full-width roman characters and half-width katakana
|| (temp >= '\u4e00' && temp <= '\u9faf') //CJK unifed ideographs - Common and uncommon kanji
|| (temp >= '\u3400' && temp <= '\u4dbf') //CJK unified ideographs Extension A - Rare kanji
|| (temp >= '\uac00' && temp <= '\uffef') //Korean Hangul characters
|| (temp >= '\u0d80' && temp <= '\u0dff')) && scriptType !== 0) //Sinhala characters
{
isUnicode = true;
break;
}
}
}
return isUnicode;
};
/**
* @private
* @param {string} text - Specifies the text
* @returns {RtlInfo} - Returns the text info.
*/
TextHelper.prototype.getRtlLanguage = function (text) {
if (isNullOrUndefined(text) || text === '') {
return { isRtl: false, id: 0 };
}
if (text >= String.fromCharCode(1424) && text <= String.fromCharCode(1535)) {
return { isRtl: true, id: 1 };
//Arabic - Urdu characters
}
else if ((text >= String.fromCharCode(1536) && text <= String.fromCharCode(1791))
|| (text >= String.fromCharCode(1872) && text <= String.fromCharCode(1919))
|| (text >= String.fromCharCode(2208) && text <= String.fromCharCode(2303))
|| (text >= String.fromCharCode(64336) && text <= String.fromCharCode(65023))
|| (text >= String.fromCharCode(65136) && text <= String.fromCharCode(65279))) {
return { isRtl: true, id: 2 };
}
else if (text >= String.fromCharCode(43392) && text <= String.fromCharCode(43487)) {
return { isRtl: true, id: 3 };
}
else if (text >= String.fromCharCode(1792) && text <= String.fromCharCode(1871)) {
return { isRtl: true, id: 4 };
}
else if (text >= String.fromCharCode(1920) && text <= String.fromCharCode(1983)) {
return { isRtl: true, id: 5 };
}
else if (text >= String.fromCharCode(2112) && text <= String.fromCharCode(2143)) {
return { isRtl: true, id: 6 };
}
else if (text >= String.fromCharCode(1984) && text <= String.fromCharCode(2047)) {
return { isRtl: true, id: 7 };
}
else if (text >= String.fromCharCode(2048) && text <= String.fromCharCode(2111)) {
return { isRtl: true, id: 8 };
}
else if (text >= String.fromCharCode(11568) && text <= String.fromCharCode(11647)) {
return { isRtl: true, id: 9 };
}
return { isRtl: false, id: 0 };
};
/**
* @private
*/
TextHelper.prototype.splitTextByConsecutiveLtrAndRtl = function (text, isTextBidi, isRTLLang, characterRangeTypes, isPrevLTRText, hasRTLCharacter) {
var charTypeIndex = characterRangeTypes.length;
var splittedText = [];
if (isNullOrUndefined(text) || text === '') {
return splittedText;
}
var lastLtrIndex = -1;
var ltrText = '';
var rtlText = '';
var wordSplitChars = '';
var numberText = '';
for (var i = 0; i < text.length; i++) {
var currentCharacterType = 0;
var separateEachWordSplitChars = false;
if ((!isNullOrUndefined(isPrevLTRText.value) ? !isPrevLTRText.value : isTextBidi) && this.isNumber(text[i])) {
numberText += text[i];
currentCharacterType = 4;
}
else if (this.isWordSplitChar(text[i])) {
currentCharacterType = 2;
if (separateEachWordSplitChars = (isTextBidi || (text.charCodeAt(i) == 32 && wordSplitChars == ''))) {
wordSplitChars += text[i];
}
else {
wordSplitChars += text[i];
}
}
else if (this.isRTLText(text[i]) && !this.isNumber(text[i])) {
isPrevLTRText.value = false;
hasRTLCharacter.value = true;
rtlText += text[i];
currentCharacterType = 1;
}
else {
isPrevLTRText.value = true;
ltrText += text[i];
}
if (numberText != '' && currentCharacterType != 4) {
splittedText.push(numberText);
characterRangeTypes.push(CharacterRangeType.Number);
numberText = '';
}
if (rtlText != '' && currentCharacterType != 1) {
splittedText.push(rtlText);
characterRangeTypes.push(CharacterRangeType.RightToLeft);
rtlText = '';
}
if (ltrText != '' && currentCharacterType != 0) {
splittedText.push(ltrText);
lastLtrIndex = splittedText.length - 1;
characterRangeTypes.push(CharacterRangeType.LeftToRight);
ltrText = '';
}
if (wordSplitChars != '' && (currentCharacterType != 2 || separateEachWordSplitChars)) {
splittedText.push(wordSplitChars);
characterRangeTypes.push(CharacterRangeType.WordSplit);
wordSplitChars = '';
}
}
if (numberText != '') {
splittedText.push(numberText);
characterRangeTypes.push(CharacterRangeType.Number);
}
else if (rtlText != '') {
splittedText.push(rtlText);
characterRangeTypes.push(CharacterRangeType.RightToLeft);
}
else if (ltrText != '') {
splittedText.push(ltrText);
lastLtrIndex = splittedText.length - 1;
characterRangeTypes.push(CharacterRangeType.LeftToRight);
}
else if (wordSplitChars != '') {
splittedText.push(wordSplitChars);
characterRangeTypes.push(CharacterRangeType.WordSplit);
}
if (hasRTLCharacter.value || (!isNullOrUndefined(isPrevLTRText.value) && !isPrevLTRText.value)) {
for (var i = 1; i < splittedText.length; i++) {
//Combines the consecutive LTR, RTL, and Number (Number get combined only if it's splitted by non reversing characters (.,:))
//along with single in-between word split character.
var charType = characterRangeTypes[i + charTypeIndex];
if (charType == CharacterRangeType.WordSplit && splittedText[i].length == 1
&& i + charTypeIndex + 1 < characterRangeTypes.length
&& characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.WordSplit
&& (characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.Number
//Else handled to combine consecutive number when text bidi is false and middle word split character is not white space.
|| TextHelper.isNumberNonReversingCharacter(splittedText[i], isTextBidi))
&& characterRangeTypes[i + charTypeIndex - 1] == characterRangeTypes[i + charTypeIndex + 1]) {
splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + splittedText[i + 1];
splittedText.splice(i, 1);
splittedText.splice(i, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
i--;
}
}
}
else if (lastLtrIndex != -1) {
if (isTextBidi) {
for (var i = 1; i < lastLtrIndex; i++) {
//Combines the first and last LTR along with all in-between splited text's.
var charType = characterRangeTypes[i + charTypeIndex];
if (charType == CharacterRangeType.WordSplit && i < lastLtrIndex
&& characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.LeftToRight) {
ltrText = '';
for (var j = i + 1; j <= lastLtrIndex; j++) {
ltrText += splittedText[j];
splittedText.splice(j, 1);
characterRangeTypes.splice(j + charTypeIndex, 1);
j--;
lastLtrIndex--;
}
splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + ltrText;
splittedText.splice(i, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
i--;
lastLtrIndex--;
}
}
}
else {
//Return the input text if text bidi is false.
splittedText.length = 0;
splittedText.push(text);
}
}
else if (!isTextBidi) {
//Return the input text if text bidi is false.
splittedText.length = 0;
splittedText.push(text);
}
if (isTextBidi) {
for (var i = 1; i < splittedText.length; i++) {
//Combines the consecutive LTR, RTL, and Number (Number get combined only if it's splitted by non reversing characters (.,:)
//or if it's lang attribute is represent a RTL language)
//along with single in-between number non reversing word split character.
var charType = characterRangeTypes[i + charTypeIndex];
if (charType == CharacterRangeType.WordSplit && splittedText[i].length == 1
&& i + charTypeIndex + 1 < characterRangeTypes.length
&& characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.WordSplit
&& (characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.Number
|| TextHelper.isNumberNonReversingCharacter(splittedText[i], isTextBidi) || !isRTLLang)
&& characterRangeTypes[i + charTypeIndex - 1] == characterRangeTypes[i + charTypeIndex + 1]) {
splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + splittedText[i + 1];
splittedText.splice(i, 1);
splittedText.splice(i, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
i--;
}
//Combines the Number along with single non-word split characters (% $ #).
else if (charType == CharacterRangeType.WordSplit
&& characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.Number
&& this.isNonWordSplitCharacter(splittedText[i]) && !isRTLLang) {
splittedText[i - 1] = splittedText[i - 1] + splittedText[i];
splittedText.splice(i, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
i--;
}
//Combines the consecutive LTR and Number
else if (charType == CharacterRangeType.LeftToRight
&& (characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.Number
|| characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.LeftToRight)) {
splittedText[i - 1] = splittedText[i - 1] + splittedText[i];
characterRangeTypes[i + charTypeIndex - 1] = CharacterRangeType.LeftToRight;
splittedText.splice(i, 1);
characterRangeTypes.splice(i + charTypeIndex, 1);
i--;
}
}
}
return splittedText;
};
/**
* @private
*/
TextHelper.prototype.isRightToLeftLanguage = function (lang) {
return (lang == 14337 || lang == 15361 || lang == 5121 || lang == 3073 || lang == 2049 ||
lang == 11265 || lang == 13313 || lang == 12289 || lang == 4097 || lang == 8193 ||
lang == 16385 || lang == 1025 || lang == 10241 || lang == 7169 || lang == 9217 || lang == 10655);
};
TextHelper.prototype.isNumber = function (ch) {
if (!isNaN(parseInt(ch, 10))) {
//This logic works for universal digits 0 to 9.
return true;
}
else if (ch >= String.fromCharCode(1632) && ch <= String.fromCharCode(1641)) {
//This logic works for ARABIC-INDIC DIGIT
return true;
}
else if (ch >= String.fromCharCode(1776) && ch <= String.fromCharCode(1785)) {
//This logic works for EXTENDED ARABIC-INDIC DIGIT
return true;
}
else {
//TODO: Extend this for language specific
return false;
}
};
/**
* @private
*/
TextHelper.prototype.isWordSplitChar = function (character) {
for (var i = 0; i < TextHelper.wordSplitCharacters.length; i++) {
if (TextHelper.wordSplitCharacters[i] === character) {
return true;
}
}
return false;
};
/**
* @private
*/
TextHelper.isNumberNonReversingCharacter = function (character, isTextBidi) {
for (var i = 0; i < TextHelper.numberNonReversingCharacters.length; i++) {
var ch = TextHelper.numberNonReversingCharacters[i];
if (character[0] == ch && (ch.charCodeAt(0) == 47 ? !isTextBidi : true)) {
return true;
}
}
return false;
};
/**
* @private
*/
TextHelper.prototype.isNonWordSplitCharacter = function (character) {
var isNonWordSplitChar = false;
for (var i = 0; i < character.length; i++) {
var charCode = character.charCodeAt(i);
//Consider a (% $ #) as non-word split characters
if (charCode == 35 || charCode == 36 || charCode == 37) {
isNonWordSplitChar = true;
}
else {
isNonWordSplitChar = false;
break;
}
}
return isNonWordSplitChar;
};
TextHelper.prototype.getFontNameToRender = function (scriptType, charFormat) {
if (!isNullOrUndefined(scriptType)) {
if (charFormat.bidi || charFormat.complexScript) {
return this.getFontNameBidiToRender(scriptType, charFormat);
}
else {
if ((this.isEastAsiaScript(scriptType) || (charFormat.fontHintType === 'EastAsia' && scriptType === FontScriptType.SpecialCharacter)) && !isNullOrUndefined(charFormat.fontFamilyFarEast))
return this.getFontNameEAToRender(scriptType, charFormat);
else
return this.getFontNameAsciiToRender(scriptType, charFormat);
}
}
else {
return charFormat.fontFamily;
}
};
/// <summary>
/// Check whether specified script is EastAsia script or not.
/// </summary>
/// <param name="scriptType">Represent a FontScriptType to check.</param>
/// <returns></returns>
TextHelper.prototype.isEastAsiaScript = function (scriptType) {
return scriptType == FontScriptType.Japanese || scriptType == FontScriptType.Korean
|| scriptType == FontScriptType.Chinese;
};
/// <summary>
/// Get the font name East Asia to render
/// </summary>
/// <param name="scriptType">Represent a CharacterRangeType.</param>
/// <returns>Returns a eastAsia font name to draw the text.</returns>
TextHelper.prototype.getFontNameEAToRender = function (scriptType, charFormat) {
var fontName = charFormat.fontFamilyFarEast;
if (isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
return this.getFontNameFromTheme(charFormat, fontName, scriptType, "EastAsia");
else
return fontName;
};
TextHelper.prototype.getFontNameAsciiToRender = function (scriptType, charFormat) {
var fontName = charFormat.fontFamilyAscii;
if (HelperMethods.isThemeFont(fontName))
return this.getFontNameFromTheme(charFormat, fontName, scriptType, "Default");
else
return charFormat.fontFamily;
};
TextHelper.prototype.getFontNameBidiToRender = function (scriptType, charFormat) {
//If CharacterFormat.Bidi is true, then font is determined in the order: FontNameBidi, Script-Arab, font scheme(latin, ea, cs), default font (Times New Roman)
//CharacterRangeType of a text and FontHintType (IdctHint) has no impact in this behavior.
//Note: Behavior is traced using Word version 1808 (build 10730.20304)
//Determines the font nmae to used for RTL characters based on its script from direct or font scheme (Document theme file)
var fontName = charFormat.fontFamilyBidi;
if (!isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
return this.getFontNameFromTheme(charFormat, fontName, scriptType, "CS");
else
return fontName;
};
TextHelper.prototype.getFontNameFromTheme = function (charFormat, fontName, scriptType, hintType) {
var fontScheme;
if (this.documentHelper.hasThemes && !isNullOrUndefined(this.documentHelper.themes) && !isUndefined(this.documentHelper.themes.fontScheme))
fontScheme = this.documentHelper.themes.fontScheme;
if (fontName == "majorAscii" || fontName == "majorBidi" || fontName == "majorEastAsia" || fontName == "majorHAnsi") {
var majorFontScheme = void 0;
if (fontScheme != null && fontScheme.majorFontScheme != null) {
majorFontScheme = fontScheme.majorFontScheme;
}
fontName = this.updateFontNameFromTheme(charFormat, majorFontScheme, scriptType, fontName, hintType);
}
else if (fontName == "minorAscii" || fontName == "minorBidi" || fontName == "minorEastAsia" || fontName == "minorHAnsi") {
var minorFontScheme = void 0;
if (fontScheme != null && fontScheme.majorFontScheme != null) {
minorFontScheme = fontScheme.minorFontScheme;
}
fontName = this.updateFontNameFromTheme(charFormat, minorFontScheme, scriptType, fontName, hintType);
}
if (isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
//Gets the default font (Times New Roman)
fontName = defaultFont;
return fontName;
};
/// <summary>
/// Update a font name from theme, based on FontHintType.
/// </summary>
/// <param name="majorMinorFontScheme"></param>
/// <param name="scriptType"></param>
/// <param name="fontName"></param>
/// <param name="hintType"></param>
TextHelper.prototype.updateFontNameFromTheme = function (charFormat, majorMinorFontScheme, scriptType, fontName, hintType) {
//Script-Arab, font scheme(latin, ea, cs), default font (Times New Roman)
var fontNameFromTheme = "";
//Gets font from font scheme(latin, ea, cs) of document theme.
if (majorMinorFontScheme != null && majorMinorFontScheme.fontSchemeList != null
&& majorMinorFontScheme.fontSchemeList.length > 0) {
majorMinorFontScheme.fontSchemeList.forEach(function (fontSchemeStruct) {
if (fontSchemeStruct.name == "cs" && (fontName == "majorBidi" || fontName == "minorBidi"))
fontNameFromTheme = fontSchemeStruct.typeface;
else if (fontSchemeStruct.name == "ea" && (fontName == "majorEastAsia" || fontName == "minorEastAsia"))
fontNameFromTheme = fontSchemeStruct.typeface;
else if (fontSchemeStruct.name == "latin" && (fontName == "majorAscii" || fontName == "majorHAnsi"
|| fontName == "minorAscii" || fontName == "minorHAnsi"))
fontNameFromTheme = fontSchemeStruct.typeface;
});
}
if (majorMinorFontScheme != null && majorMinorFontScheme.fontTypeface != null) {
if (hintType == "CS") {
// //If it's an complex script and "themeFontLang" element has a "bidi" attribute, then we need to locate the font name
// //from the "theme.xml" for the language specified by the bidi attribute
// if (charFormat.complexScript && Document != null && Document.Settings.ThemeFontLanguages != null &&
// Document.Settings.ThemeFontLanguages.HasValue(WCharacterFormat.LidBiKey))
// {
// fontName = this.getFontNameWithFontScript(majorMinorFontScheme, Document.Settings.ThemeFontLanguages.LocaleIdBidi, hintType);
// if (fontName != null)
// fontNameFromTheme = fontName;
// }
//If the font name is mentioned as Ascii or HAnsi, then we need to get the font name from Latin.
if (!charFormat.complexScript && (!charFormat.bidi && (fontName === "majorAscii" || fontName === "majorHAnsi" || fontName === "minorAscii" || fontName === "minorHAnsi"))
|| (charFormat.bidi && (fontName === "majorHAnsi" || fontName === "minorHAnsi"))) {
fontName = fontNameFromTheme;
}
//To-Do: Have to implement the font name retrieval behavior, when a bidi attribute is not available in theme.
else if (majorMinorFontScheme.fontTypeface.containsKey('Arab')) {
//map(object => object.id).indexOf('c');
//Gets the Arab-script (language) based font from font scheme (theme)
fontNameFromTheme = majorMinorFontScheme.fontTypeface.get('Arab');
}
}
else if (hintType == "EastAsia") {
if (!isNullOrUndefined(this.documentHelper.themeFontLanguage)) {
fontName = this.getFontNameWithFontScript(majorMinorFontScheme, this.documentHelper.themeFontLanguage.localeIdFarEast, hintType);
if (!isNullOrUndefined(fontName)) {
fontNameFromTheme = fontName;
}
//When font information is not available at the file level, Microsoft Word uses the following fonts as the default font for the respective language.
// else if (isNullOrUndefined(fontNameFromTheme))
// {
// LocaleIDs lang = (LocaleIDs)Document.Settings.ThemeFontLanguages.LocaleIdFarEast;
// if (lang == LocaleIDs.zh_CN)
// fontNameFromTheme = "SimSun";
// else if (lang == LocaleIDs.ko_KR)
// fontNameFromTheme = "Batang";
// else if (lang == LocaleIDs.ja_JP)
// fontNameFromTheme = "MS Mincho";
// }
}
}
else if (isNullOrUndefined(fontNameFromTheme) && !isNullOrUndefined(this.documentHelper.themeFontLanguage) && (fontName === "minorBidi" || fontName === "majorBidi")) {
return fontName = this.getFontNameWithFontScript(majorMinorFontScheme, this.documentHelper.themeFontLanguage.localeIdBidi, hintType);
}
}
if (isNullOrUndefined(fontNameFromTheme))
//Gets the default font (Times New Roman)
fontNameFromTheme = defaultFont;
fontName = fontNameFromTheme;
return fontName;
};
// /// <summary>
// /// Gets the font name from a theme part for the specified font script.
// /// </summary>
TextHelper.prototype.getFontNameWithFontScript = function (majorMinorFontScheme, localeID, hintType) {
var fontName = null;
//To-Do: Should extend this behavior deponds on the localeID.
var lang = localeID.toString();
var fontTypeFaces = majorMinorFontScheme.fontTypeface;
//Gujarati
//If lang script is "gu-IN" or "gu", we should retrive the "Gujr" font from a theme part.
if ((lang == 'gu_IN' || localeID == 1095) && fontTypeFaces.containsKey("Gujr"))
fontName = fontTypeFaces.get("Arab");
//Hindi
//If lang script is "hi-IN" or "hi", we should retrive the "Deva" font from a theme part.
//Marathi
//If lang script is "mr-IN" or "mr", we should retrive the "Deva" font from a theme part.
else if ((lang == 'hi_IN' || lang == 'mr_IN' || localeID == 1081 || localeID == 1102)
&& fontTypeFaces.containsKey("Deva"))
fontName = fontTypeFaces.get("Arab");
//Korean
//If lang script is "ko-KR" or "ko", we should retrive the "Hang" font from a theme part.
else if ((lang == 'ko_KR' || localeID == 1042) && fontTypeFaces.containsKey("Hang"))
fontName = fontTypeFaces.get("Arab");
//Chinese - Simplified
//If lang script is "zh-CN", "zh-SG" or "zh", we should retrive the "Hans" font from a theme part.
else if ((lang == 'zh_CN' || lang == 'zh_SG' || localeID == 2052) && fontTypeFaces.containsKey("Hans"))
fontName = fontTypeFaces.get("Hans");
//Chinese - Traditional
//If lang script is "zh-TW", "zh-HK", or "zh-MO", we should retrive the "Hant" font from a theme part.
else if ((lang == 'zh_TW' || lang == 'zh_HK' || lang == 'zh_MO')
&& fontTypeFaces.containsKey("Hant"))
fontName = fontTypeFaces.get("Arab");
//Japanese
//If lang script is "ja-JP" or "ja", we should retrive the "Jpan" font from a theme part.
else if ((lang == 'ja_JP' || localeID == 1041) && fontTypeFaces.containsKey("Jpan"))
fontName = fontTypeFaces.get("Arab");
//Tamil
//If lang script is "ta-IN" or "ta", we should retrive the "Taml" font from a theme part.
else if ((lang == 'ta_IN' || localeID == 1097) && fontTypeFaces.containsKey("Taml"))
fontName = fontTypeFaces.get("Arab");
//Telugu
//If lang script is "te-IN" or "te", we should retrive the "Telu" font from a theme part.
else if ((lang == 'te_IN' || localeID == 1098) && fontTypeFaces.containsKey("Telu"))
fontName = fontTypeFaces.get("Arab");
//Hebrew
//If lang script is "he-IL" or "he", we should retrive the "Hebr" font from a theme part.
else if ((lang == 'he_IL' || lang == 'yi_Hebr' || localeID == 1037) && fontTypeFaces.containsKey("Hebr"))
fontName = fontTypeFaces.get("Arab");
//Thai
//If lang script is "th_TH" or "th", we should retrive the "Thai" font from a theme part.
else if ((lang == 'th_TH' || localeID == 1054) && fontTypeFaces.containsKey("Thai"))
fontName = fontTypeFaces.get("Thai");
//Arabic
else if (hintType == "CS" && fontTypeFaces.containsKey("Arab"))
fontName = fontTypeFaces.get("Arab");
return fontName;
};
TextHelper.prototype.destroy = function () {
this.documentHelper = undefined;
this.context = undefined;
this.paragraphMarkInfo = {};
this.paragraphMarkInfo = undefined;
};
TextHelper.wordSplitCharacters = [String.fromCharCode(32), String.fromCharCode(33), String.fromCharCode(34),
String.fromCharCode(35), String.fromCharCode(36), String.fromCharCode(37), String.fromCharCode(38), String.fromCharCode(39),
String.fromCharCode(40), String.fromCharCode(41), String.fromCharCode(42), String.fromCharCode(43), String.fromCharCode(44),
String.fromCharCode(45), String.fromCharCode(46), String.fromCharCode(47), String.fromCharCode(58), String.fromCharCode(59),
String.fromCharCode(60), String.fromCharCode(61), String.fromCharCode(62), String.fromCharCode(63), String.fromCharCode(64),
String.fromCharCode(91), String.fromCharCode(92), String.fromCharCode(93), String.fromCharCode(94), String.fromCharCode(95),
String.fromCharCode(96), String.fromCharCode(123), String.fromCharCode(124), String.fromCharCode(125), String.fromCharCode(126),
String.fromCharCode(1548), String.fromCharCode(1563), String.fromCharCode(8211), String.fromCharCode(8212),
String.fromCharCode(8216), String.fromCharCode(8217), String.fromCharCode(8221), String.fromCharCode(12288),
String.fromCharCode(8207)];
TextHelper.numberNonReversingCharacters = [String.fromCharCode(44), String.fromCharCode(46), String.fromCharCode(47),
String.fromCharCode(58), String.fromCharCode(1548)];
return TextHelper;
}());
export { TextHelper };