forked from ibm-js/delite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Bidi.js
170 lines (157 loc) · 4.94 KB
/
Bidi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/**
* When has("bidi") is true, delite/Widget will mix in the properties in this module.
* It enables support for the `textdir` property to control text direction independently from the GUI direction.
* @module delite/Bidi
*/
define([
"./features"
], function (has) {
// UCC - constants that will be used by bidi support.
var LRE = "\u202A",
RLE = "\u202B",
PDF = "\u202C";
return /** @lends module:delite/Bidi */ {
declaredClass: "delite/Bidi",
/**
* Bi-directional support, the main variable which is responsible for the direction of the text.
* The text direction can be different than the GUI direction by using this parameter in creation
* of a widget.
*
* Allowed values:
*
* 1. "ltr"
* 2. "rtl"
* 3. "auto" - contextual the direction of a text defined by first strong letter.
*
* By default is as the page direction.
*/
textDir: "",
/**
* Return the direction setting for the page itself, or if `has("inherited-dir")` is defined and the widget is
* attached to the page, then return the dir setting inherited from any ancestor node.
* @returns {string} "ltr" or "rtl"
* @protected
*/
getInheritedDir: function () {
return this._inheritedDir || this.ownerDocument.body.dir || this.ownerDocument.documentElement.dir || "ltr";
},
connectedCallback: function () {
if (has("inherited-dir")) {
// Now that the widget is attached to the DOM, need to retrigger computation of effectiveDir.
this._inheritedDir = window.getComputedStyle(this, null).direction;
this.notifyCurrentValue("dir");
this.deliver();
}
},
/**
* Returns the right direction of text.
*
* If textDir is ltr or rtl, returns the value.
* If it's auto, calls to another function that's responsible
* for checking the value, and defining the direction.
*
* @param {string} text
* @returns {string} ltr or rtl
* @protected
*/
getTextDir: function (text) {
var textDir = this.textDir;
return textDir === "auto" ? this._checkContextual(text) :
(/^(rtl|ltr)$/i).test(textDir) ? textDir : this.effectiveDir;
},
/**
* Finds the first strong (directional) character, return ltr if isLatin or rtl if isBidiChar.
*
* @param {string} text
* @returns {string} ltr or rtl
* @private
*/
_checkContextual: function (text) {
// look for strong (directional) characters
var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
// if found return the direction that defined by the character, else return widgets dir as default.
return fdc ? (fdc[0] <= "z" ? "ltr" : "rtl") : this.effectiveDir;
},
/**
* Set element.dir according to this.textDir.
*
* @param {HTMLElement} element - The text element to be set. Should have dir property.
* @protected
*/
applyTextDir: function (element) {
if (this.textDir) {
var textDir = this.textDir;
if (textDir === "auto") {
// convert "auto" to either "ltr" or "rtl"
var tagName = element.tagName.toLowerCase();
var text = (tagName === "input" || tagName === "textarea") ? element.value : element.textContent;
textDir = this._checkContextual(text);
}
element.dir = textDir;
}
else {
element.dir = this.effectiveDir;
}
},
/**
* Enforce base direction of the given text according to this.textDir.
*
* @param {string} text
* @returns {string}
* @protected
*/
applyTextDirection: function (text) {
if (this.textDir) {
return this.wrapWithUcc(this.removeUcc(text));
} else {
return this.removeUcc(text);
}
},
/**
* Returns specified text with UCC added to enforce widget's textDir setting.
*
* @param {string} text
* @returns {string}
* @protected
*/
wrapWithUcc: function (text) {
return (this.getTextDir(text) === "ltr" ? LRE : RLE) + text + PDF;
},
/**
* Removes UCC from specified text.
*
* @param {string} text
* @returns {string}
* @protected
*/
removeUcc: function (text) {
return text && text.replace(/[\u200E\u200F\u202A-\u202C]/g, "");
},
/**
* Wraps by UCC (Unicode control characters) option's text according to this.textDir.
*
* This function saves the original text value for later restoration if needed,
* for example if the textDir will change etc.
*
* @param {HTMLOptionElement} node - The node we wrapping the text for.
* @protected
*/
enforceTextDirWithUcc: function (node) {
node.originalText = node.text;
node.innerHTML = this.applyTextDirection(node.innerHTML);
},
/**
* Restores the text of origObj, if needed, after enforceTextDirWithUcc, for example
* after `myWidget.textDir = "ltr"`. The function then removes the originalText from origObj!
*
* @param {HTMLOptionElement} origObj - The node to restore.
* @protected
*/
restoreOriginalText: function (origObj) {
if (origObj.originalText) {
origObj.text = origObj.originalText;
delete origObj.originalText;
}
}
};
});