Guest User

Untitled

a guest
Apr 20th, 2018
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.15 KB | None | 0 0
  1. import { BodyComponent } from 'mjml-core'
  2. import { flow, identity, join, filter } from 'lodash/fp'
  3.  
  4. import widthParser from 'mjml-core/lib/helpers/widthParser'
  5.  
  6. const makeBackgroundString = flow(filter(identity), join(' '))
  7. export default class McSection extends BodyComponent {
  8. static allowedAttributes = {
  9. 'mc:hideable': 'boolean',
  10. 'mc:repeatable': 'string',
  11. 'mc:variant': 'string',
  12. 'background-color': 'color',
  13. 'background-url': 'string',
  14. 'background-repeat': 'enum(repeat/no-repeat)',
  15. 'background-size': 'string',
  16. border: 'string',
  17. 'border-bottom': 'string',
  18. 'border-left': 'string',
  19. 'border-radius': 'string',
  20. 'border-right': 'string',
  21. 'border-top': 'string',
  22. direction: 'enum(ltr,rtl)',
  23. 'full-width': 'enum(full-width)',
  24. padding: 'unit(px,%){1,4}',
  25. 'padding-top': 'unit(px,%)',
  26. 'padding-bottom': 'unit(px,%)',
  27. 'padding-left': 'unit(px,%)',
  28. 'padding-right': 'unit(px,%)',
  29. 'text-align': 'enum(left,center,right)',
  30. 'text-padding': 'unit(px,%){1,4}',
  31. 'vertical-align': 'enum(bottom,middle,top)',
  32. }
  33.  
  34. static defaultAttributes = {
  35. 'background-repeat': 'repeat',
  36. 'background-size': 'auto',
  37. direction: 'ltr',
  38. padding: '20px 0',
  39. 'text-align': 'center',
  40. 'text-padding': '4px 4px 4px 0',
  41. 'vertical-align': 'top',
  42. }
  43.  
  44. getChildContext() {
  45. const { containerWidth } = this.context
  46.  
  47. const paddingSize =
  48. this.getShorthandAttrValue('padding', 'left') +
  49. this.getShorthandAttrValue('padding', 'right')
  50.  
  51. const { parsedWidth } = widthParser(containerWidth, {
  52. parseFloatToInt: false,
  53. })
  54.  
  55. return {
  56. ...this.context,
  57. containerWidth: `${parsedWidth - paddingSize}px`,
  58. }
  59. }
  60.  
  61. getStyles() {
  62. const { containerWidth } = this.context
  63.  
  64. const fullWidth = this.isFullWidth()
  65.  
  66. const background = this.getAttribute('background-url')
  67. ? { background: this.getBackground() }
  68. : {
  69. background: this.getAttribute('background-color'),
  70. 'background-color': this.getAttribute('background-color'),
  71. }
  72.  
  73. return {
  74. tableFullwidth: {
  75. ...(fullWidth ? background : {}),
  76. width: '100%',
  77. 'border-radius': this.getAttribute('border-radius'),
  78. },
  79. table: {
  80. ...(fullWidth ? {} : background),
  81. width: '100%',
  82. 'border-radius': this.getAttribute('border-radius'),
  83. },
  84. td: {
  85. border: this.getAttribute('border'),
  86. 'border-bottom': this.getAttribute('border-bottom'),
  87. 'border-left': this.getAttribute('border-left'),
  88. 'border-right': this.getAttribute('border-right'),
  89. 'border-top': this.getAttribute('border-top'),
  90. direction: this.getAttribute('direction'),
  91. 'font-size': '0px',
  92. padding: this.getAttribute('padding'),
  93. 'padding-bottom': this.getAttribute('padding-bottom'),
  94. 'padding-left': this.getAttribute('padding-left'),
  95. 'padding-right': this.getAttribute('padding-right'),
  96. 'padding-top': this.getAttribute('padding-top'),
  97. 'text-align': this.getAttribute('text-align'),
  98. 'vertical-align': this.getAttribute('vertical-align'),
  99. },
  100. div: {
  101. ...(fullWidth ? {} : background),
  102. Margin: '0px auto',
  103. 'border-radius': this.getAttribute('border-radius'),
  104. 'max-width': containerWidth,
  105. },
  106. innerDiv: {
  107. 'line-height': '0',
  108. 'font-size': '0',
  109. },
  110. }
  111. }
  112.  
  113. getBackground = () =>
  114. makeBackgroundString([
  115. this.getAttribute('background-color'),
  116. ...(this.hasBackground()
  117. ? [
  118. `url(${this.getAttribute('background-url')})`,
  119. `top center / ${this.getAttribute('background-size')}`,
  120. this.getAttribute('background-repeat'),
  121. ]
  122. : []),
  123. ])
  124.  
  125. hasBackground() {
  126. return this.getAttribute('background-url') != null
  127. }
  128.  
  129. isFullWidth() {
  130. return this.getAttribute('full-width') === 'full-width'
  131. }
  132.  
  133. renderBefore() {
  134. const { containerWidth } = this.context
  135.  
  136. return `
  137. <!--[if mso | IE]>
  138. <table
  139. ${this.htmlAttributes({
  140. align: 'center',
  141. border: '0',
  142. cellpadding: '0',
  143. cellspacing: '0',
  144. class: this.getAttribute('css-class')
  145. ? this.getAttribute('css-class')
  146. .split(' ')
  147. .map(c => `${c}-outlook`)
  148. .join(' ')
  149. : null,
  150. style: { width: `${containerWidth}` },
  151. width: parseInt(containerWidth, 10),
  152. })}
  153. >
  154. <tr>
  155. <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
  156. <![endif]-->
  157. `
  158. }
  159.  
  160. renderAfter() {
  161. // eslint-disable-line class-methods-use-this
  162. return `
  163. <!--[if mso | IE]>
  164. </td>
  165. </tr>
  166. </table>
  167. <![endif]-->
  168. `
  169. }
  170.  
  171. renderWrappedChildren() {
  172. const { children } = this.props
  173.  
  174. return `
  175. <!--[if mso | IE]>
  176. <tr>
  177. <![endif]-->
  178. ${this.renderChildren(children, {
  179. renderer: component =>
  180. component.constructor.isRawElement()
  181. ? component.render()
  182. : `
  183. <!--[if mso | IE]>
  184. <td
  185. ${component.htmlAttributes({
  186. align: component.getAttribute('align'),
  187. class: component.getAttribute('css-class')
  188. ? component
  189. .getAttribute('css-class')
  190. .split(' ')
  191. .map(c => `${c}-outlook`)
  192. .join(' ')
  193. : null,
  194. style: 'tdOutlook',
  195. })}
  196. >
  197. <![endif]-->
  198. ${component.render()}
  199. <!--[if mso | IE]>
  200. </td>
  201. <![endif]-->
  202. `,
  203. })}
  204.  
  205. <!--[if mso | IE]>
  206. </tr>
  207. <![endif]-->
  208. `
  209. }
  210.  
  211. renderWithBackground(content) {
  212. const fullWidth = this.isFullWidth()
  213.  
  214. const { containerWidth } = this.context
  215.  
  216. return `
  217. <!--[if mso | IE]>
  218. <v:rect ${this.htmlAttributes({
  219. style: fullWidth
  220. ? { 'mso-width-percent': '1000' }
  221. : { width: containerWidth },
  222. 'xmlns:v': 'urn:schemas-microsoft-com:vml',
  223. fill: 'true',
  224. stroke: 'false',
  225. })}>
  226. <v:fill ${this.htmlAttributes({
  227. origin: '0.5, 0',
  228. position: '0.5, 0',
  229. src: this.getAttribute('background-url'),
  230. color: this.getAttribute('background-color'),
  231. type: 'tile',
  232. })} />
  233. <v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
  234. <![endif]-->
  235. ${content}
  236. <!--[if mso | IE]>
  237. </v:textbox>
  238. </v:rect>
  239. <![endif]-->
  240. `
  241. }
  242.  
  243. renderSection() {
  244. const hasBackground = this.hasBackground()
  245.  
  246. return `
  247. <div ${this.htmlAttributes({
  248. class: this.isFullWidth() ? null : this.getAttribute('css-class'),
  249. style: 'div',
  250. 'mc:hideable': this.getAttribute('mc:hideable'),
  251. 'mc:repeatable': this.getAttribute('mc:repeatable'),
  252. 'mc:variant': this.getAttribute('mc:variant'),
  253. })}>
  254. ${hasBackground
  255. ? `<div ${this.htmlAttributes({ style: 'innerDiv' })}>`
  256. : ''}
  257. <table
  258. ${this.htmlAttributes({
  259. align: 'center',
  260. background: this.isFullWidth()
  261. ? null
  262. : this.getAttribute('background-url'),
  263. border: '0',
  264. cellpadding: '0',
  265. cellspacing: '0',
  266. role: 'presentation',
  267. style: 'table',
  268. })}
  269. >
  270. <tbody>
  271. <tr>
  272. <td
  273. ${this.htmlAttributes({
  274. style: 'td',
  275. })}
  276. >
  277. <!--[if mso | IE]>
  278. <table role="presentation" border="0" cellpadding="0" cellspacing="0">
  279. <![endif]-->
  280. ${this.renderWrappedChildren()}
  281. <!--[if mso | IE]>
  282. </table>
  283. <![endif]-->
  284. </td>
  285. </tr>
  286. </tbody>
  287. </table>
  288. ${hasBackground ? '</div>' : ''}
  289. </div>
  290. `
  291. }
  292.  
  293. renderFullWidth() {
  294. const content = this.hasBackground()
  295. ? this.renderWithBackground(`
  296. ${this.renderBefore()}
  297. ${this.renderSection()}
  298. ${this.renderAfter()}
  299. `)
  300. : `
  301. ${this.renderBefore()}
  302. ${this.renderSection()}
  303. ${this.renderAfter()}
  304. `
  305.  
  306. return `
  307. <table
  308. ${this.htmlAttributes({
  309. align: 'center',
  310. class: this.getAttribute('css-class'),
  311. background: this.getAttribute('background-url'),
  312. border: '0',
  313. cellpadding: '0',
  314. cellspacing: '0',
  315. role: 'presentation',
  316. style: 'tableFullwidth',
  317. })}
  318. >
  319. <tbody>
  320. <tr>
  321. <td>
  322. ${content}
  323. </td>
  324. </tr>
  325. </tbody>
  326. </table>
  327. `
  328. }
  329.  
  330. renderSimple() {
  331. const section = this.renderSection()
  332.  
  333. return `
  334. ${this.renderBefore()}
  335. ${this.hasBackground() ? this.renderWithBackground(section) : section}
  336. ${this.renderAfter()}
  337. `
  338. }
  339.  
  340. render() {
  341. return this.isFullWidth() ? this.renderFullWidth() : this.renderSimple()
  342. }
  343. }
Add Comment
Please, Sign In to add comment