bidiformatter.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utility for formatting text for display in a potentially
  16. * opposite-directionality context without garbling.
  17. * Mostly a port of http://go/formatter.cc.
  18. */
  19. goog.provide('goog.i18n.BidiFormatter');
  20. goog.require('goog.html.SafeHtml');
  21. goog.require('goog.i18n.bidi');
  22. goog.require('goog.i18n.bidi.Dir');
  23. goog.require('goog.i18n.bidi.Format');
  24. /**
  25. * Utility class for formatting text for display in a potentially
  26. * opposite-directionality context without garbling. Provides the following
  27. * functionality:
  28. *
  29. * 1. BiDi Wrapping
  30. * When text in one language is mixed into a document in another, opposite-
  31. * directionality language, e.g. when an English business name is embedded in a
  32. * Hebrew web page, both the inserted string and the text following it may be
  33. * displayed incorrectly unless the inserted string is explicitly separated
  34. * from the surrounding text in a "wrapper" that declares its directionality at
  35. * the start and then resets it back at the end. This wrapping can be done in
  36. * HTML mark-up (e.g. a 'span dir="rtl"' tag) or - only in contexts where
  37. * mark-up can not be used - in Unicode BiDi formatting codes (LRE|RLE and PDF).
  38. * Providing such wrapping services is the basic purpose of the BiDi formatter.
  39. *
  40. * 2. Directionality estimation
  41. * How does one know whether a string about to be inserted into surrounding
  42. * text has the same directionality? Well, in many cases, one knows that this
  43. * must be the case when writing the code doing the insertion, e.g. when a
  44. * localized message is inserted into a localized page. In such cases there is
  45. * no need to involve the BiDi formatter at all. In the remaining cases, e.g.
  46. * when the string is user-entered or comes from a database, the language of
  47. * the string (and thus its directionality) is not known a priori, and must be
  48. * estimated at run-time. The BiDi formatter does this automatically.
  49. *
  50. * 3. Escaping
  51. * When wrapping plain text - i.e. text that is not already HTML or HTML-
  52. * escaped - in HTML mark-up, the text must first be HTML-escaped to prevent XSS
  53. * attacks and other nasty business. This of course is always true, but the
  54. * escaping can not be done after the string has already been wrapped in
  55. * mark-up, so the BiDi formatter also serves as a last chance and includes
  56. * escaping services.
  57. *
  58. * Thus, in a single call, the formatter will escape the input string as
  59. * specified, determine its directionality, and wrap it as necessary. It is
  60. * then up to the caller to insert the return value in the output.
  61. *
  62. * See http://wiki/Main/TemplatesAndBiDi for more information.
  63. *
  64. * @param {goog.i18n.bidi.Dir|number|boolean|null} contextDir The context
  65. * directionality, in one of the following formats:
  66. * 1. A goog.i18n.bidi.Dir constant. NEUTRAL is treated the same as null,
  67. * i.e. unknown, for backward compatibility with legacy calls.
  68. * 2. A number (positive = LTR, negative = RTL, 0 = unknown).
  69. * 3. A boolean (true = RTL, false = LTR).
  70. * 4. A null for unknown directionality.
  71. * @param {boolean=} opt_alwaysSpan Whether {@link #spanWrap} should always
  72. * use a 'span' tag, even when the input directionality is neutral or
  73. * matches the context, so that the DOM structure of the output does not
  74. * depend on the combination of directionalities. Default: false.
  75. * @constructor
  76. * @final
  77. */
  78. goog.i18n.BidiFormatter = function(contextDir, opt_alwaysSpan) {
  79. /**
  80. * The overall directionality of the context in which the formatter is being
  81. * used.
  82. * @type {?goog.i18n.bidi.Dir}
  83. * @private
  84. */
  85. this.contextDir_ = goog.i18n.bidi.toDir(contextDir, true /* opt_noNeutral */);
  86. /**
  87. * Whether {@link #spanWrap} and similar methods should always use the same
  88. * span structure, regardless of the combination of directionalities, for a
  89. * stable DOM structure.
  90. * @type {boolean}
  91. * @private
  92. */
  93. this.alwaysSpan_ = !!opt_alwaysSpan;
  94. };
  95. /**
  96. * @return {?goog.i18n.bidi.Dir} The context directionality.
  97. */
  98. goog.i18n.BidiFormatter.prototype.getContextDir = function() {
  99. return this.contextDir_;
  100. };
  101. /**
  102. * @return {boolean} Whether alwaysSpan is set.
  103. */
  104. goog.i18n.BidiFormatter.prototype.getAlwaysSpan = function() {
  105. return this.alwaysSpan_;
  106. };
  107. /**
  108. * @param {goog.i18n.bidi.Dir|number|boolean|null} contextDir The context
  109. * directionality, in one of the following formats:
  110. * 1. A goog.i18n.bidi.Dir constant. NEUTRAL is treated the same as null,
  111. * i.e. unknown.
  112. * 2. A number (positive = LTR, negative = RTL, 0 = unknown).
  113. * 3. A boolean (true = RTL, false = LTR).
  114. * 4. A null for unknown directionality.
  115. */
  116. goog.i18n.BidiFormatter.prototype.setContextDir = function(contextDir) {
  117. this.contextDir_ = goog.i18n.bidi.toDir(contextDir, true /* opt_noNeutral */);
  118. };
  119. /**
  120. * @param {boolean} alwaysSpan Whether {@link #spanWrap} should always use a
  121. * 'span' tag, even when the input directionality is neutral or matches the
  122. * context, so that the DOM structure of the output does not depend on the
  123. * combination of directionalities.
  124. */
  125. goog.i18n.BidiFormatter.prototype.setAlwaysSpan = function(alwaysSpan) {
  126. this.alwaysSpan_ = alwaysSpan;
  127. };
  128. /**
  129. * Returns the directionality of input argument {@code str}.
  130. * Identical to {@link goog.i18n.bidi.estimateDirection}.
  131. *
  132. * @param {string} str The input text.
  133. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  134. * Default: false.
  135. * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}.
  136. */
  137. goog.i18n.BidiFormatter.prototype.estimateDirection =
  138. goog.i18n.bidi.estimateDirection;
  139. /**
  140. * Returns true if two given directionalities are opposite.
  141. * Note: the implementation is based on the numeric values of the Dir enum.
  142. *
  143. * @param {?goog.i18n.bidi.Dir} dir1 1st directionality.
  144. * @param {?goog.i18n.bidi.Dir} dir2 2nd directionality.
  145. * @return {boolean} Whether the directionalities are opposite.
  146. * @private
  147. */
  148. goog.i18n.BidiFormatter.prototype.areDirectionalitiesOpposite_ = function(
  149. dir1, dir2) {
  150. return Number(dir1) * Number(dir2) < 0;
  151. };
  152. /**
  153. * Returns a unicode BiDi mark matching the context directionality (LRM or
  154. * RLM) if {@code opt_dirReset}, and if either the directionality or the exit
  155. * directionality of {@code str} is opposite to the context directionality.
  156. * Otherwise returns the empty string.
  157. *
  158. * @param {string} str The input text.
  159. * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
  160. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  161. * Default: false.
  162. * @param {boolean=} opt_dirReset Whether to perform the reset. Default: false.
  163. * @return {string} A unicode BiDi mark or the empty string.
  164. * @private
  165. */
  166. goog.i18n.BidiFormatter.prototype.dirResetIfNeeded_ = function(
  167. str, dir, opt_isHtml, opt_dirReset) {
  168. // endsWithRtl and endsWithLtr are called only if needed (short-circuit).
  169. if (opt_dirReset &&
  170. (this.areDirectionalitiesOpposite_(dir, this.contextDir_) ||
  171. (this.contextDir_ == goog.i18n.bidi.Dir.LTR &&
  172. goog.i18n.bidi.endsWithRtl(str, opt_isHtml)) ||
  173. (this.contextDir_ == goog.i18n.bidi.Dir.RTL &&
  174. goog.i18n.bidi.endsWithLtr(str, opt_isHtml)))) {
  175. return this.contextDir_ == goog.i18n.bidi.Dir.LTR ?
  176. goog.i18n.bidi.Format.LRM :
  177. goog.i18n.bidi.Format.RLM;
  178. } else {
  179. return '';
  180. }
  181. };
  182. /**
  183. * Returns "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" if
  184. * it is LTR. In case it's NEUTRAL, returns "rtl" if the context directionality
  185. * is RTL, and "ltr" otherwise.
  186. * Needed for GXP, which can't handle dirAttr.
  187. * Example use case:
  188. * &lt;td expr:dir='bidiFormatter.dirAttrValue(foo)'&gt;
  189. * &lt;gxp:eval expr='foo'&gt;
  190. * &lt;/td&gt;
  191. *
  192. * @param {string} str Text whose directionality is to be estimated.
  193. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  194. * Default: false.
  195. * @return {string} "rtl" or "ltr", according to the logic described above.
  196. */
  197. goog.i18n.BidiFormatter.prototype.dirAttrValue = function(str, opt_isHtml) {
  198. return this.knownDirAttrValue(this.estimateDirection(str, opt_isHtml));
  199. };
  200. /**
  201. * Returns "rtl" if the given directionality is RTL, and "ltr" if it is LTR. In
  202. * case it's NEUTRAL, returns "rtl" if the context directionality is RTL, and
  203. * "ltr" otherwise.
  204. *
  205. * @param {goog.i18n.bidi.Dir} dir A directionality.
  206. * @return {string} "rtl" or "ltr", according to the logic described above.
  207. */
  208. goog.i18n.BidiFormatter.prototype.knownDirAttrValue = function(dir) {
  209. var resolvedDir = dir == goog.i18n.bidi.Dir.NEUTRAL ? this.contextDir_ : dir;
  210. return resolvedDir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
  211. };
  212. /**
  213. * Returns 'dir="ltr"' or 'dir="rtl"', depending on {@code str}'s estimated
  214. * directionality, if it is not the same as the context directionality.
  215. * Otherwise, returns the empty string.
  216. *
  217. * @param {string} str Text whose directionality is to be estimated.
  218. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  219. * Default: false.
  220. * @return {string} 'dir="rtl"' for RTL text in non-RTL context; 'dir="ltr"' for
  221. * LTR text in non-LTR context; else, the empty string.
  222. */
  223. goog.i18n.BidiFormatter.prototype.dirAttr = function(str, opt_isHtml) {
  224. return this.knownDirAttr(this.estimateDirection(str, opt_isHtml));
  225. };
  226. /**
  227. * Returns 'dir="ltr"' or 'dir="rtl"', depending on the given directionality, if
  228. * it is not the same as the context directionality. Otherwise, returns the
  229. * empty string.
  230. *
  231. * @param {goog.i18n.bidi.Dir} dir A directionality.
  232. * @return {string} 'dir="rtl"' for RTL text in non-RTL context; 'dir="ltr"' for
  233. * LTR text in non-LTR context; else, the empty string.
  234. */
  235. goog.i18n.BidiFormatter.prototype.knownDirAttr = function(dir) {
  236. if (dir != this.contextDir_) {
  237. return dir == goog.i18n.bidi.Dir.RTL ?
  238. 'dir="rtl"' :
  239. dir == goog.i18n.bidi.Dir.LTR ? 'dir="ltr"' : '';
  240. }
  241. return '';
  242. };
  243. /**
  244. * Formats a string of unknown directionality for use in HTML output of the
  245. * context directionality, so an opposite-directionality string is neither
  246. * garbled nor garbles what follows it.
  247. * The algorithm: estimates the directionality of input argument {@code html}.
  248. * In case its directionality doesn't match the context directionality, wraps it
  249. * with a 'span' tag and adds a "dir" attribute (either 'dir="rtl"' or
  250. * 'dir="ltr"'). If setAlwaysSpan(true) was used, the input is always wrapped
  251. * with 'span', skipping just the dir attribute when it's not needed.
  252. *
  253. * If {@code opt_dirReset}, and if the overall directionality or the exit
  254. * directionality of {@code str} are opposite to the context directionality, a
  255. * trailing unicode BiDi mark matching the context directionality is appened
  256. * (LRM or RLM).
  257. *
  258. * @param {!goog.html.SafeHtml} html The input HTML.
  259. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  260. * matching the context directionality, when needed, to prevent the possible
  261. * garbling of whatever may follow {@code html}. Default: true.
  262. * @return {!goog.html.SafeHtml} Input text after applying the processing.
  263. */
  264. goog.i18n.BidiFormatter.prototype.spanWrapSafeHtml = function(
  265. html, opt_dirReset) {
  266. return this.spanWrapSafeHtmlWithKnownDir(null, html, opt_dirReset);
  267. };
  268. /**
  269. * Formats a string of given directionality for use in HTML output of the
  270. * context directionality, so an opposite-directionality string is neither
  271. * garbled nor garbles what follows it.
  272. * The algorithm: If {@code dir} doesn't match the context directionality, wraps
  273. * {@code html} with a 'span' tag and adds a "dir" attribute (either 'dir="rtl"'
  274. * or 'dir="ltr"'). If setAlwaysSpan(true) was used, the input is always wrapped
  275. * with 'span', skipping just the dir attribute when it's not needed.
  276. *
  277. * If {@code opt_dirReset}, and if {@code dir} or the exit directionality of
  278. * {@code html} are opposite to the context directionality, a trailing unicode
  279. * BiDi mark matching the context directionality is appened (LRM or RLM).
  280. *
  281. * @param {?goog.i18n.bidi.Dir} dir {@code html}'s overall directionality, or
  282. * null if unknown and needs to be estimated.
  283. * @param {!goog.html.SafeHtml} html The input HTML.
  284. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  285. * matching the context directionality, when needed, to prevent the possible
  286. * garbling of whatever may follow {@code html}. Default: true.
  287. * @return {!goog.html.SafeHtml} Input text after applying the processing.
  288. */
  289. goog.i18n.BidiFormatter.prototype.spanWrapSafeHtmlWithKnownDir = function(
  290. dir, html, opt_dirReset) {
  291. if (dir == null) {
  292. dir = this.estimateDirection(goog.html.SafeHtml.unwrap(html), true);
  293. }
  294. return this.spanWrapWithKnownDir_(dir, html, opt_dirReset);
  295. };
  296. /**
  297. * The internal implementation of spanWrapSafeHtmlWithKnownDir for non-null dir,
  298. * to help the compiler optimize.
  299. *
  300. * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
  301. * @param {!goog.html.SafeHtml} html The input HTML.
  302. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  303. * matching the context directionality, when needed, to prevent the possible
  304. * garbling of whatever may follow {@code str}. Default: true.
  305. * @return {!goog.html.SafeHtml} Input text after applying the above processing.
  306. * @private
  307. */
  308. goog.i18n.BidiFormatter.prototype.spanWrapWithKnownDir_ = function(
  309. dir, html, opt_dirReset) {
  310. opt_dirReset = opt_dirReset || (opt_dirReset == undefined);
  311. var result;
  312. // Whether to add the "dir" attribute.
  313. var dirCondition =
  314. dir != goog.i18n.bidi.Dir.NEUTRAL && dir != this.contextDir_;
  315. if (this.alwaysSpan_ || dirCondition) { // Wrap is needed
  316. var dirAttribute;
  317. if (dirCondition) {
  318. dirAttribute = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
  319. }
  320. result = goog.html.SafeHtml.create('span', {'dir': dirAttribute}, html);
  321. } else {
  322. result = html;
  323. }
  324. var str = goog.html.SafeHtml.unwrap(html);
  325. result = goog.html.SafeHtml.concatWithDir(
  326. goog.i18n.bidi.Dir.NEUTRAL, result,
  327. this.dirResetIfNeeded_(str, dir, true, opt_dirReset));
  328. return result;
  329. };
  330. /**
  331. * Formats a string of unknown directionality for use in plain-text output of
  332. * the context directionality, so an opposite-directionality string is neither
  333. * garbled nor garbles what follows it.
  334. * As opposed to {@link #spanWrap}, this makes use of unicode BiDi formatting
  335. * characters. In HTML, its *only* valid use is inside of elements that do not
  336. * allow mark-up, e.g. an 'option' tag.
  337. * The algorithm: estimates the directionality of input argument {@code str}.
  338. * In case it doesn't match the context directionality, wraps it with Unicode
  339. * BiDi formatting characters: RLE{@code str}PDF for RTL text, and
  340. * LRE{@code str}PDF for LTR text.
  341. *
  342. * If {@code opt_dirReset}, and if the overall directionality or the exit
  343. * directionality of {@code str} are opposite to the context directionality, a
  344. * trailing unicode BiDi mark matching the context directionality is appended
  345. * (LRM or RLM).
  346. *
  347. * Does *not* do HTML-escaping regardless of the value of {@code opt_isHtml}.
  348. * The return value can be HTML-escaped as necessary.
  349. *
  350. * @param {string} str The input text.
  351. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  352. * Default: false.
  353. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  354. * matching the context directionality, when needed, to prevent the possible
  355. * garbling of whatever may follow {@code str}. Default: true.
  356. * @return {string} Input text after applying the above processing.
  357. */
  358. goog.i18n.BidiFormatter.prototype.unicodeWrap = function(
  359. str, opt_isHtml, opt_dirReset) {
  360. return this.unicodeWrapWithKnownDir(null, str, opt_isHtml, opt_dirReset);
  361. };
  362. /**
  363. * Formats a string of given directionality for use in plain-text output of the
  364. * context directionality, so an opposite-directionality string is neither
  365. * garbled nor garbles what follows it.
  366. * As opposed to {@link #spanWrapWithKnownDir}, makes use of unicode BiDi
  367. * formatting characters. In HTML, its *only* valid use is inside of elements
  368. * that do not allow mark-up, e.g. an 'option' tag.
  369. * The algorithm: If {@code dir} doesn't match the context directionality, wraps
  370. * {@code str} with Unicode BiDi formatting characters: RLE{@code str}PDF for
  371. * RTL text, and LRE{@code str}PDF for LTR text.
  372. *
  373. * If {@code opt_dirReset}, and if the overall directionality or the exit
  374. * directionality of {@code str} are opposite to the context directionality, a
  375. * trailing unicode BiDi mark matching the context directionality is appended
  376. * (LRM or RLM).
  377. *
  378. * Does *not* do HTML-escaping regardless of the value of {@code opt_isHtml}.
  379. * The return value can be HTML-escaped as necessary.
  380. *
  381. * @param {?goog.i18n.bidi.Dir} dir {@code str}'s overall directionality, or
  382. * null if unknown and needs to be estimated.
  383. * @param {string} str The input text.
  384. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  385. * Default: false.
  386. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  387. * matching the context directionality, when needed, to prevent the possible
  388. * garbling of whatever may follow {@code str}. Default: true.
  389. * @return {string} Input text after applying the above processing.
  390. */
  391. goog.i18n.BidiFormatter.prototype.unicodeWrapWithKnownDir = function(
  392. dir, str, opt_isHtml, opt_dirReset) {
  393. if (dir == null) {
  394. dir = this.estimateDirection(str, opt_isHtml);
  395. }
  396. return this.unicodeWrapWithKnownDir_(dir, str, opt_isHtml, opt_dirReset);
  397. };
  398. /**
  399. * The internal implementation of unicodeWrapWithKnownDir for non-null dir, to
  400. * help the compiler optimize.
  401. *
  402. * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
  403. * @param {string} str The input text.
  404. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  405. * Default: false.
  406. * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
  407. * matching the context directionality, when needed, to prevent the possible
  408. * garbling of whatever may follow {@code str}. Default: true.
  409. * @return {string} Input text after applying the above processing.
  410. * @private
  411. */
  412. goog.i18n.BidiFormatter.prototype.unicodeWrapWithKnownDir_ = function(
  413. dir, str, opt_isHtml, opt_dirReset) {
  414. opt_dirReset = opt_dirReset || (opt_dirReset == undefined);
  415. var result = [];
  416. if (dir != goog.i18n.bidi.Dir.NEUTRAL && dir != this.contextDir_) {
  417. result.push(
  418. dir == goog.i18n.bidi.Dir.RTL ? goog.i18n.bidi.Format.RLE :
  419. goog.i18n.bidi.Format.LRE);
  420. result.push(str);
  421. result.push(goog.i18n.bidi.Format.PDF);
  422. } else {
  423. result.push(str);
  424. }
  425. result.push(this.dirResetIfNeeded_(str, dir, opt_isHtml, opt_dirReset));
  426. return result.join('');
  427. };
  428. /**
  429. * Returns a Unicode BiDi mark matching the context directionality (LRM or RLM)
  430. * if the directionality or the exit directionality of {@code str} are opposite
  431. * to the context directionality. Otherwise returns the empty string.
  432. *
  433. * @param {string} str The input text.
  434. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  435. * Default: false.
  436. * @return {string} A Unicode bidi mark matching the global directionality or
  437. * the empty string.
  438. */
  439. goog.i18n.BidiFormatter.prototype.markAfter = function(str, opt_isHtml) {
  440. return this.markAfterKnownDir(null, str, opt_isHtml);
  441. };
  442. /**
  443. * Returns a Unicode BiDi mark matching the context directionality (LRM or RLM)
  444. * if the given directionality or the exit directionality of {@code str} are
  445. * opposite to the context directionality. Otherwise returns the empty string.
  446. *
  447. * @param {?goog.i18n.bidi.Dir} dir {@code str}'s overall directionality, or
  448. * null if unknown and needs to be estimated.
  449. * @param {string} str The input text.
  450. * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
  451. * Default: false.
  452. * @return {string} A Unicode bidi mark matching the global directionality or
  453. * the empty string.
  454. */
  455. goog.i18n.BidiFormatter.prototype.markAfterKnownDir = function(
  456. dir, str, opt_isHtml) {
  457. if (dir == null) {
  458. dir = this.estimateDirection(str, opt_isHtml);
  459. }
  460. return this.dirResetIfNeeded_(str, dir, opt_isHtml, true);
  461. };
  462. /**
  463. * Returns the Unicode BiDi mark matching the context directionality (LRM for
  464. * LTR context directionality, RLM for RTL context directionality), or the
  465. * empty string for neutral / unknown context directionality.
  466. *
  467. * @return {string} LRM for LTR context directionality and RLM for RTL context
  468. * directionality.
  469. */
  470. goog.i18n.BidiFormatter.prototype.mark = function() {
  471. switch (this.contextDir_) {
  472. case (goog.i18n.bidi.Dir.LTR):
  473. return goog.i18n.bidi.Format.LRM;
  474. case (goog.i18n.bidi.Dir.RTL):
  475. return goog.i18n.bidi.Format.RLM;
  476. default:
  477. return '';
  478. }
  479. };
  480. /**
  481. * Returns 'right' for RTL context directionality. Otherwise (LTR or neutral /
  482. * unknown context directionality) returns 'left'.
  483. *
  484. * @return {string} 'right' for RTL context directionality and 'left' for other
  485. * context directionality.
  486. */
  487. goog.i18n.BidiFormatter.prototype.startEdge = function() {
  488. return this.contextDir_ == goog.i18n.bidi.Dir.RTL ? goog.i18n.bidi.RIGHT :
  489. goog.i18n.bidi.LEFT;
  490. };
  491. /**
  492. * Returns 'left' for RTL context directionality. Otherwise (LTR or neutral /
  493. * unknown context directionality) returns 'right'.
  494. *
  495. * @return {string} 'left' for RTL context directionality and 'right' for other
  496. * context directionality.
  497. */
  498. goog.i18n.BidiFormatter.prototype.endEdge = function() {
  499. return this.contextDir_ == goog.i18n.bidi.Dir.RTL ? goog.i18n.bidi.LEFT :
  500. goog.i18n.bidi.RIGHT;
  501. };