mo.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2017-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Implements the CHTMLmo wrapper for the MmlMo object
  19. *
  20. * @author dpvc@mathjax.org (Davide Cervone)
  21. */
  22. import {CHTMLWrapper, CHTMLConstructor, StringMap} from '../Wrapper.js';
  23. import {CommonMoMixin, DirectionVH} from '../../common/Wrappers/mo.js';
  24. import {MmlMo} from '../../../core/MmlTree/MmlNodes/mo.js';
  25. import {StyleList} from '../../../util/StyleList.js';
  26. import {DIRECTION} from '../FontData.js';
  27. /*****************************************************************/
  28. /**
  29. * The CHTMLmo wrapper for the MmlMo object
  30. *
  31. * @template N The HTMLElement node class
  32. * @template T The Text node class
  33. * @template D The Document class
  34. */
  35. // @ts-ignore
  36. export class CHTMLmo<N, T, D> extends
  37. CommonMoMixin<CHTMLConstructor<any, any, any>>(CHTMLWrapper) {
  38. /**
  39. * The mo wrapper
  40. */
  41. public static kind = MmlMo.prototype.kind;
  42. /**
  43. * @override
  44. */
  45. public static styles: StyleList = {
  46. 'mjx-stretchy-h': {
  47. display: 'inline-table',
  48. width: '100%'
  49. },
  50. 'mjx-stretchy-h > *': {
  51. display: 'table-cell',
  52. width: 0
  53. },
  54. 'mjx-stretchy-h > * > mjx-c': {
  55. display: 'inline-block',
  56. transform: 'scalex(1.0000001)' // improves blink positioning
  57. },
  58. 'mjx-stretchy-h > * > mjx-c::before': {
  59. display: 'inline-block',
  60. width: 'initial'
  61. },
  62. 'mjx-stretchy-h > mjx-ext': {
  63. '/* IE */ overflow': 'hidden',
  64. '/* others */ overflow': 'clip visible',
  65. width: '100%'
  66. },
  67. 'mjx-stretchy-h > mjx-ext > mjx-c::before': {
  68. transform: 'scalex(500)'
  69. },
  70. 'mjx-stretchy-h > mjx-ext > mjx-c': {
  71. width: 0
  72. },
  73. 'mjx-stretchy-h > mjx-beg > mjx-c': {
  74. 'margin-right': '-.1em'
  75. },
  76. 'mjx-stretchy-h > mjx-end > mjx-c': {
  77. 'margin-left': '-.1em'
  78. },
  79. 'mjx-stretchy-v': {
  80. display: 'inline-block'
  81. },
  82. 'mjx-stretchy-v > *': {
  83. display: 'block'
  84. },
  85. 'mjx-stretchy-v > mjx-beg': {
  86. height: 0
  87. },
  88. 'mjx-stretchy-v > mjx-end > mjx-c': {
  89. display: 'block'
  90. },
  91. 'mjx-stretchy-v > * > mjx-c': {
  92. transform: 'scaley(1.0000001)', // improves Firefox and blink positioning
  93. 'transform-origin': 'left center',
  94. overflow: 'hidden'
  95. },
  96. 'mjx-stretchy-v > mjx-ext': {
  97. display: 'block',
  98. height: '100%',
  99. 'box-sizing': 'border-box',
  100. border: '0px solid transparent',
  101. '/* IE */ overflow': 'hidden',
  102. '/* others */ overflow': 'visible clip',
  103. },
  104. 'mjx-stretchy-v > mjx-ext > mjx-c::before': {
  105. width: 'initial',
  106. 'box-sizing': 'border-box'
  107. },
  108. 'mjx-stretchy-v > mjx-ext > mjx-c': {
  109. transform: 'scaleY(500) translateY(.075em)',
  110. overflow: 'visible'
  111. },
  112. 'mjx-mark': {
  113. display: 'inline-block',
  114. height: '0px'
  115. }
  116. };
  117. /**
  118. * @override
  119. */
  120. public toCHTML(parent: N) {
  121. const attributes = this.node.attributes;
  122. const symmetric = (attributes.get('symmetric') as boolean) && this.stretch.dir !== DIRECTION.Horizontal;
  123. const stretchy = this.stretch.dir !== DIRECTION.None;
  124. if (stretchy && this.size === null) {
  125. this.getStretchedVariant([]);
  126. }
  127. let chtml = this.standardCHTMLnode(parent);
  128. if (stretchy && this.size < 0) {
  129. this.stretchHTML(chtml);
  130. } else {
  131. if (symmetric || attributes.get('largeop')) {
  132. const u = this.em(this.getCenterOffset());
  133. if (u !== '0') {
  134. this.adaptor.setStyle(chtml, 'verticalAlign', u);
  135. }
  136. }
  137. if (this.node.getProperty('mathaccent')) {
  138. this.adaptor.setStyle(chtml, 'width', '0');
  139. this.adaptor.setStyle(chtml, 'margin-left', this.em(this.getAccentOffset()));
  140. }
  141. for (const child of this.childNodes) {
  142. child.toCHTML(chtml);
  143. }
  144. }
  145. }
  146. /**
  147. * Create the HTML for a multi-character stretchy delimiter
  148. *
  149. * @param {N} chtml The parent element in which to put the delimiter
  150. */
  151. protected stretchHTML(chtml: N) {
  152. const c = this.getText().codePointAt(0);
  153. this.font.delimUsage.add(c);
  154. this.childNodes[0].markUsed();
  155. const delim = this.stretch;
  156. const stretch = delim.stretch;
  157. const content: N[] = [];
  158. //
  159. // Set up the beginning, extension, and end pieces
  160. //
  161. if (stretch[0]) {
  162. content.push(this.html('mjx-beg', {}, [this.html('mjx-c')]));
  163. }
  164. content.push(this.html('mjx-ext', {}, [this.html('mjx-c')]));
  165. if (stretch.length === 4) {
  166. //
  167. // Braces have a middle and second extensible piece
  168. //
  169. content.push(
  170. this.html('mjx-mid', {}, [this.html('mjx-c')]),
  171. this.html('mjx-ext', {}, [this.html('mjx-c')])
  172. );
  173. }
  174. if (stretch[2]) {
  175. content.push(this.html('mjx-end', {}, [this.html('mjx-c')]));
  176. }
  177. //
  178. // Set the styles needed
  179. //
  180. const styles: StringMap = {};
  181. const {h, d, w} = this.bbox;
  182. if (delim.dir === DIRECTION.Vertical) {
  183. //
  184. // Vertical needs an extra (empty) element to get vertical position right
  185. // in some browsers (e.g., Safari)
  186. //
  187. content.push(this.html('mjx-mark'));
  188. styles.height = this.em(h + d);
  189. styles.verticalAlign = this.em(-d);
  190. } else {
  191. styles.width = this.em(w);
  192. }
  193. //
  194. // Make the main element and add it to the parent
  195. //
  196. const dir = DirectionVH[delim.dir];
  197. const properties = {class: this.char(delim.c || c), style: styles};
  198. const html = this.html('mjx-stretchy-' + dir, properties, content);
  199. this.adaptor.append(chtml, html);
  200. }
  201. }