Skip to content

Commit 098c2c5

Browse files
authored
Merge pull request #20 from dingo-d/feature/mj-image
Implement mj-image element
2 parents 5dbf813 + 0f6359b commit 098c2c5

File tree

2 files changed

+533
-0
lines changed

2 files changed

+533
-0
lines changed
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
<?php
2+
3+
/**
4+
* PHP MJML Renderer library
5+
*
6+
* @package MadeByDenis\PhpMjmlRenderer
7+
* @link https://github.com/dingo-d/php-mjml-renderer
8+
* @license https://opensource.org/licenses/MIT MIT
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace MadeByDenis\PhpMjmlRenderer\Elements\BodyComponents;
14+
15+
use MadeByDenis\PhpMjmlRenderer\Elements\AbstractElement;
16+
17+
/**
18+
* Mjml Image Element
19+
*
20+
* @link https://documentation.mjml.io/#mj-image
21+
*
22+
* @since 1.0.0
23+
*/
24+
class MjImage extends AbstractElement
25+
{
26+
public const string TAG_NAME = 'mj-image';
27+
28+
public const bool ENDING_TAG = false;
29+
30+
/**
31+
* List of allowed attributes on the element
32+
*
33+
* @var array<string, array<string, string>>
34+
*/
35+
protected array $allowedAttributes = [
36+
'align' => [
37+
'unit' => 'string',
38+
'type' => 'alignment',
39+
'description' => 'image alignment',
40+
'default_value' => 'center',
41+
],
42+
'alt' => [
43+
'unit' => 'string',
44+
'type' => 'string',
45+
'description' => 'image description',
46+
'default_value' => '',
47+
],
48+
'border' => [
49+
'unit' => 'string',
50+
'type' => 'string',
51+
'description' => 'css border format',
52+
'default_value' => 'none',
53+
],
54+
'border-radius' => [
55+
'unit' => 'px',
56+
'type' => 'measure',
57+
'description' => 'border radius',
58+
'default_value' => '',
59+
],
60+
'border-top' => [
61+
'unit' => 'string',
62+
'type' => 'string',
63+
'description' => 'css top border format',
64+
'default_value' => 'none',
65+
],
66+
'border-bottom' => [
67+
'unit' => 'string',
68+
'type' => 'string',
69+
'description' => 'css bottom border format',
70+
'default_value' => 'none',
71+
],
72+
'border-left' => [
73+
'unit' => 'string',
74+
'type' => 'string',
75+
'description' => 'css left border format',
76+
'default_value' => 'none',
77+
],
78+
'border-right' => [
79+
'unit' => 'string',
80+
'type' => 'string',
81+
'description' => 'css right border format',
82+
'default_value' => 'none',
83+
],
84+
'container-background-color' => [
85+
'unit' => 'color',
86+
'type' => 'color',
87+
'description' => 'inner element background color',
88+
'default_value' => '',
89+
],
90+
'css-class' => [
91+
'unit' => 'string',
92+
'type' => 'string',
93+
'description' => 'class name added to root HTML element',
94+
'default_value' => '',
95+
],
96+
'fluid-on-mobile' => [
97+
'unit' => 'string',
98+
'type' => 'string',
99+
'description' => 'if true, will be full width on mobile',
100+
'default_value' => '',
101+
],
102+
'height' => [
103+
'unit' => 'px',
104+
'type' => 'measure',
105+
'description' => 'image height',
106+
'default_value' => 'auto',
107+
],
108+
'href' => [
109+
'unit' => 'string',
110+
'type' => 'string',
111+
'description' => 'link to redirect on click',
112+
'default_value' => '',
113+
],
114+
'name' => [
115+
'unit' => 'string',
116+
'type' => 'string',
117+
'description' => 'specify link name attribute',
118+
'default_value' => '',
119+
],
120+
'padding' => [
121+
'unit' => 'px',
122+
'type' => 'measure',
123+
'description' => 'supports up to 4 parameters',
124+
'default_value' => '10px 25px',
125+
],
126+
'padding-top' => [
127+
'unit' => 'px',
128+
'type' => 'measure',
129+
'description' => 'top offset',
130+
'default_value' => '',
131+
],
132+
'padding-bottom' => [
133+
'unit' => 'px',
134+
'type' => 'measure',
135+
'description' => 'bottom offset',
136+
'default_value' => '',
137+
],
138+
'padding-left' => [
139+
'unit' => 'px',
140+
'type' => 'measure',
141+
'description' => 'left offset',
142+
'default_value' => '',
143+
],
144+
'padding-right' => [
145+
'unit' => 'px',
146+
'type' => 'measure',
147+
'description' => 'right offset',
148+
'default_value' => '',
149+
],
150+
'rel' => [
151+
'unit' => 'string',
152+
'type' => 'string',
153+
'description' => 'specify link rel attribute',
154+
'default_value' => '',
155+
],
156+
'sizes' => [
157+
'unit' => 'string',
158+
'type' => 'string',
159+
'description' => 'set width based on query',
160+
'default_value' => '',
161+
],
162+
'src' => [
163+
'unit' => 'string',
164+
'type' => 'string',
165+
'description' => 'image source',
166+
'default_value' => '',
167+
],
168+
'srcset' => [
169+
'unit' => 'string',
170+
'type' => 'string',
171+
'description' => 'different image source based on viewport',
172+
'default_value' => '',
173+
],
174+
'target' => [
175+
'unit' => 'string',
176+
'type' => 'string',
177+
'description' => 'link target on click',
178+
'default_value' => '_blank',
179+
],
180+
'title' => [
181+
'unit' => 'string',
182+
'type' => 'string',
183+
'description' => 'tooltip & accessibility',
184+
'default_value' => '',
185+
],
186+
'usemap' => [
187+
'unit' => 'string',
188+
'type' => 'string',
189+
'description' => 'reference to image map',
190+
'default_value' => '',
191+
],
192+
'width' => [
193+
'unit' => 'px',
194+
'type' => 'measure',
195+
'description' => 'image width',
196+
'default_value' => '',
197+
],
198+
];
199+
200+
protected array $defaultAttributes = [
201+
'align' => 'center',
202+
'border' => 'none',
203+
'height' => 'auto',
204+
'padding' => '10px 25px',
205+
'target' => '_blank',
206+
];
207+
208+
public function render(): string
209+
{
210+
$href = $this->getAttribute('href');
211+
212+
$imgAttributes = $this->getHtmlAttributes([
213+
'alt' => $this->getAttribute('alt'),
214+
'height' => $this->getAttribute('height'),
215+
'src' => $this->getAttribute('src'),
216+
'srcset' => $this->getAttribute('srcset'),
217+
'sizes' => $this->getAttribute('sizes'),
218+
'style' => 'img',
219+
'title' => $this->getAttribute('title'),
220+
'usemap' => $this->getAttribute('usemap'),
221+
'width' => $this->getImageWidth(),
222+
]);
223+
224+
$img = "<img $imgAttributes />";
225+
226+
// Wrap in link if href is provided
227+
if ($href) {
228+
$aAttributes = $this->getHtmlAttributes([
229+
'href' => $href,
230+
'target' => $this->getAttribute('target'),
231+
'rel' => $this->getAttribute('rel'),
232+
'name' => $this->getAttribute('name'),
233+
]);
234+
235+
$img = "<a $aAttributes>$img</a>";
236+
}
237+
238+
$tdAttributes = $this->getHtmlAttributes([
239+
'align' => $this->getAttribute('align'),
240+
'style' => 'td',
241+
]);
242+
243+
return "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" " .
244+
"style=\"border-collapse:collapse;border-spacing:0px;\">" .
245+
"<tbody>" .
246+
"<tr>" .
247+
"<td $tdAttributes>" .
248+
$img .
249+
"</td>" .
250+
"</tr>" .
251+
"</tbody>" .
252+
"</table>";
253+
}
254+
255+
private function getImageWidth(): string
256+
{
257+
$width = $this->getAttribute('width');
258+
259+
if ($width) {
260+
return $width;
261+
}
262+
263+
// Default to container width if not specified
264+
return $this->context['containerWidth'] ?? '';
265+
}
266+
267+
/**
268+
* @return array<string, array<string, string>>
269+
*/
270+
public function getStyles(): array
271+
{
272+
return [
273+
'img' => [
274+
'border' => $this->getAttribute('border'),
275+
'border-top' => $this->getAttribute('border-top'),
276+
'border-bottom' => $this->getAttribute('border-bottom'),
277+
'border-left' => $this->getAttribute('border-left'),
278+
'border-right' => $this->getAttribute('border-right'),
279+
'border-radius' => $this->getAttribute('border-radius'),
280+
'display' => 'block',
281+
'outline' => 'none',
282+
'text-decoration' => 'none',
283+
'height' => $this->getAttribute('height'),
284+
'max-width' => '100%',
285+
'width' => '100%',
286+
],
287+
'td' => [
288+
'width' => $this->getImageWidth(),
289+
],
290+
];
291+
}
292+
}

0 commit comments

Comments
 (0)