Completed
Push — master ( 3912aa...50e85d )
by Josh
17:47
created

TemplateGenerator::getContentTemplate()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 1
ccs 0
cts 0
cp 0
nc 1
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2016 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Plugins\MediaEmbed\Configurator;
9
10
use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
11
12
abstract class TemplateGenerator
13
{
14
	/**
15
	* @var array Attributes used to generate current template
16
	*/
17
	protected $attributes;
18
19
	/**
20
	* @var array Default attributes
21
	*/
22
	protected $defaultAttributes = [
23
		'height'         => 360,
24
		'padding-height' => 0,
25
		'style'          => [],
26
		'width'          => 640
27
	];
28
29
	/**
30
	* Build the template representing the embedded content
31
	*
32
	* @return string
33
	*/
34
	abstract protected function getContentTemplate();
35
36
	/**
37
	* Build a template based on a list of attributes
38
	*
39
	* @param  array  $attributes
40
	* @return string
41
	*/
42 12
	public function getTemplate(array $attributes)
43
	{
44 12
		$this->attributes = $attributes + $this->defaultAttributes;
45
46 12
		$prepend = $append = '';
47 12
		if ($this->needsWrapper())
48 12
		{
49 7
			$this->attributes['style']['width']    = '100%';
50 7
			$this->attributes['style']['height']   = '100%';
51 7
			$this->attributes['style']['position'] = 'absolute';
52 7
			$this->attributes['style']['left'] = '0';
53
54 7
			$outerStyle = 'display:inline-block;width:100%;max-width:' . $this->attributes['width'] . 'px';
55 7
			$innerStyle = 'overflow:hidden;position:relative;' . $this->getResponsivePadding();
56
57 7
			$prepend .= '<div>' . $this->generateAttributes(['style' => $outerStyle]);
58 7
			$prepend .= '<div>' . $this->generateAttributes(['style' => $innerStyle]);
59 7
			$append  .= '</div></div>';
60 7
		}
61
		else
62
		{
63 5
			$this->attributes['style']['width']  = '100%';
64 5
			$this->attributes['style']['height'] = $this->attributes['height'] . 'px';
65
66 5
			if (isset($this->attributes['max-width']))
67 5
			{
68 1
				$this->attributes['style']['max-width'] = $this->attributes['max-width'] . 'px';
69 1
			}
70 4
			elseif ($this->attributes['width'] !== '100%')
71
			{
72 3
				$this->attributes['style']['max-width'] = $this->attributes['width'] . 'px';
73 3
			}
74
		}
75
76 12
		return $prepend . $this->getContentTemplate() . $append;
77
	}
78
79
	/**
80
	* Format an attribute value to be used in an XPath expression
81
	*
82
	* @param  string $expr Original value
83
	* @return string       Formatted value
84
	*/
85 7
	protected function expr($expr)
86
	{
87 7
		$expr = trim($expr, '{}');
88
89 7
		return (preg_match('(^[@$]?[-\\w]+$)D', $expr)) ? $expr : "($expr)";
90
	}
91
92
	/**
93
	* Generate and return the padding declaration used in the responsive wrapper
94
	*
95
	* @return string
96
	*/
97 7
	protected function getResponsivePadding()
98
	{
99 7
		$height        = $this->expr($this->attributes['height']);
100 7
		$paddingHeight = $this->expr($this->attributes['padding-height']);
101 7
		$width         = $this->expr($this->attributes['width']);
102
103
		// Create the padding declaration for the fixed ratio
104 7
		$css = 'padding-bottom:<xsl:value-of select="100*(' . $height . '+' . $paddingHeight . ')div' . $width . '"/>%';
105
		
106
		// Add the padding declaration for the computed ratio if applicable
107 7
		if (!empty($this->attributes['padding-height']))
108 7
		{
109
			// NOTE: there needs to be whitespace around tokens in calc()
110 2
			$css .= ';padding-bottom:calc(<xsl:value-of select="100*' . $height . ' div' . $width . '"/>% + ' . $paddingHeight . 'px)';
111 2
		}
112
113
		// If the width is dynamic, use a conditional to protect against divisions by zero
114 7
		if (strpos($width, '@') !== false)
115 7
		{
116 1
			$css = '<xsl:if test="@width&gt;0">' . $css . '</xsl:if>';
117 1
		}
118
119 7
		return $css;
120
	}
121
122
	/**
123
	* Generate xsl:attributes elements from an array
124
	*
125
	* @param  array  $attributes Array of [name => value] where value can be XSL code
126
	* @return string             XSL source
127
	*/
128 10
	protected function generateAttributes(array $attributes)
129
	{
130 10
		if (isset($attributes['style']) && is_array($attributes['style']))
131 10
		{
132 10
			$attributes['style'] = $this->generateStyle($attributes['style']);
133 10
		}
134
135 10
		ksort($attributes);
136 10
		$xsl = '';
137 10
		foreach ($attributes as $attrName => $attrValue)
138
		{
139 10
			$innerXML = (strpos($attrValue, '<xsl:') !== false) ? $attrValue : AVTHelper::toXSL($attrValue);
140
141 10
			$xsl .= '<xsl:attribute name="' . htmlspecialchars($attrName, ENT_QUOTES, 'UTF-8') . '">' . $innerXML . '</xsl:attribute>';
142 10
		}
143
144 10
		return $xsl;
145
	}
146
147
	/**
148
	* Generate a CSS declaration based on an array of CSS properties
149
	*
150
	* @param  array  $properties Property name => property value
151
	* @return string
152
	*/
153 10
	protected function generateStyle(array $properties)
154
	{
155 10
		ksort($properties);
156
157 10
		$style = '';
158 10
		foreach ($properties as $name => $value)
159
		{
160 10
			$style .= $name . ':' . $value . ';';
161 10
		}
162
163 10
		return trim($style, ';');
164
	}
165
166
	/**
167
	* Merge two array of attributes
168
	*
169
	* @param  array $defaultAttributes
170
	* @param  array $newAttributes
171
	* @return array
172
	*/
173 8
	protected function mergeAttributes(array $defaultAttributes, array $newAttributes)
174
	{
175 8
		$attributes = array_merge($defaultAttributes, $newAttributes);
176 8
		if (isset($defaultAttributes['style'], $newAttributes['style']))
177 8
		{
178
			// Re-add the default attributes that were lost (but not replaced) in the merge
179 8
			$attributes['style'] += $defaultAttributes['style'];
180 8
		}
181
182 8
		return $attributes;
183
	}
184
185
	/**
186
	* Test whether current template needs a wrapper to be responsive
187
	*
188
	* @return bool
189
	*/
190 10
	protected function needsWrapper()
191
	{
192 10
		if ($this->attributes['width'] === '100%')
193 10
		{
194 2
			return false;
195
		}
196
197 8
		if (isset($this->attributes['onload']) && strpos($this->attributes['onload'], '.height') !== false)
198 8
		{
199 1
			return false;
200
		}
201
202 7
		return true;
203
	}
204
}