3 defined('_JEXEC') or die;
5 if (!defined('_ARTX_FUNCTIONS')) {
7 define('_ARTX_FUNCTIONS', 1);
9 $GLOBALS['artx_settings'] = array(
10 'block' => array('has_header' => true),
11 'menu' => array('show_submenus' => true),
12 'vmenu' => array('show_submenus' => false, 'simple' => false)
15 require_once dirname(__FILE__) . '/library/Artx.php';
18 * Decorates an article or block with the art-post style.
20 * Elements of the $data array:
25 * 'metadata-header-icons'
26 * 'metadata-footer-icons'
29 function artxPost($data)
32 $data = array('content' => $data);
33 $classes = isset($data['classes']) && strlen($data['classes']) ? $data['classes'] : '';
34 artxFragmentBegin("<article class=\"art-post" . $classes . "\">");
35 artxFragmentBegin("<h2 class=\"art-postheader\">");
36 if (isset($data['header-text']) && strlen($data['header-text'])) {
37 if (isset($data['header-link']) && strlen($data['header-link']))
38 artxFragmentContent('<a href="' . $data['header-link'] . '">' . $data['header-text'] . '</a>');
40 artxFragmentContent($data['header-text']);
42 artxFragmentEnd("</h2>");
43 artxFragmentBegin("<div class=\"art-postheadericons art-metadata-icons\">");
44 if (isset($data['metadata-header-icons']) && count($data['metadata-header-icons']))
45 foreach ($data['metadata-header-icons'] as $icon)
46 artxFragment('', $icon, '', ' | ');
47 artxFragmentEnd("</div>");
48 artxFragmentBegin("<div class=\"art-postcontent clearfix\">");
49 if (isset($data['content']) && strlen($data['content']))
50 artxFragmentContent(artxPostprocessPostContent($data['content']));
51 artxFragmentEnd("</div>");
52 artxFragmentBegin("<div class=\"art-postfootericons art-metadata-icons\">");
53 if (isset($data['metadata-footer-icons']) && count($data['metadata-footer-icons']))
54 foreach ($data['metadata-footer-icons'] as $icon)
55 artxFragment('', $icon, '', ' | ');
56 artxFragmentEnd("</div>");
58 return artxFragmentEnd("</article>", '', true);
62 function artxBlock($caption, $content, $classes = '')
64 $hasCaption = ($GLOBALS['artx_settings']['block']['has_header']
65 && null !== $caption && strlen(trim($caption)) > 0);
66 $hasContent = (null !== $content && strlen(trim($content)) > 0);
67 if (!$hasCaption && !$hasContent)
69 artxFragmentBegin("<div class=\"art-block clearfix" . $classes . "\">");
70 artxFragmentBegin("<div class=\"art-blockheader\"><h3 class=\"t\">");
71 artxFragmentContent($caption);
72 artxFragmentEnd("</h3></div>");
73 artxFragmentBegin("<div class=\"art-blockcontent\">");
74 artxFragmentContent(artxPostprocessBlockContent($content));
75 artxFragmentEnd("</div>");
77 return artxFragmentEnd("</div>", '', true);
83 function artxUrlToHref($url)
87 if (isset($p['scheme']) && isset($p['host'])) {
88 $result = $p['scheme'] . '://';
89 if (isset($p['user'])) {
90 $result .= $p['user'];
91 if (isset($p['pass']))
92 $result .= ':' . $p['pass'];
95 $result .= $p['host'];
96 if (isset($p['port']))
97 $result .= ':' . $p['port'];
98 if (!isset($p['path']))
101 if (isset($p['path']))
102 $result .= $p['path'];
103 if (isset($p['query'])) {
104 $result .= '?' . str_replace('&', '&', $p['query']);
106 if (isset($p['fragment']))
107 $result .= '#' . $p['fragment'];
112 * Searches $content for tags and returns information about each found tag.
114 * Created to support button replacing process, e.g. wrapping submit/reset
115 * inputs and buttons with artisteer style.
117 * When all the $name tags are found, they are processed by the $filter specified.
118 * Filter is applied to the attributes. When an attribute contains several values
119 * (e.g. class attribute), only tags that contain all the values from filter
120 * will be selected. E.g. filtering by the button class will select elements
121 * with class="button" and class="button validate".
123 * Parsing does not support nested tags. Looking for span tags in
124 * <span>1<span>2</span>3</span> will return <span>1<span>2</span> and
128 * Select all tags with class='readon':
129 * artxFindTags($html, array('*' => array('class' => 'readon')))
130 * Select inputs with type='submit' and class='button':
131 * artxFindTags($html, array('input' => array('type' => 'submit', 'class' => 'button')))
132 * Select inputs with type='submit' and class='button validate':
133 * artxFindTags($html, array('input' => array('type' => 'submit', 'class' => array('button', 'validate'))))
134 * Select inputs with class != 'art-button'
135 * artxFindTags($html, array('input' => array('class' => '!art-button')))
136 * Select inputs with non-empty class
137 * artxFindTags($html, array('input' => array('class' => '!')))
138 * Select inputs with class != 'art-button' and non-empty class:
139 * artxFindTags($html, array('input' => array('class' => array('!art-button', '!'))))
140 * Select inputs with class = button but != 'art-button'
141 * artxFindTags($html, array('input' => array('class' => array('button', '!art-button'))))
143 * @return array of text fragments and tag information: position, length,
144 * name, attributes, raw_open_tag, body.
146 function artxFindTags($content, $filters)
151 $name = implode('|', array_keys($filters));
152 $name = str_replace('*', '\w+', $name);
153 // search for open tag
155 '~<(' . $name . ')\b(?:\s+[^\s]+\s*=\s*(?:"[^"]+"|\'[^\']+\'|[^\s>]+))*\s*/?' . '>~i', $content,
156 $tagMatches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
158 foreach ($tagMatches as $tagMatch) {
159 $rawMatch = $tagMatch[0][0];
160 $name = $tagMatch[1][0];
161 $normalName = strtolower($name);
162 $tag = array('name' => $name, 'position' => $tagMatch[0][1]);
163 $openTagTail = (strlen($rawMatch) > 1 && '/' == $rawMatch[strlen($rawMatch) - 2])
165 // different instructions for paired and unpaired tags
171 $tag['paired'] = false;
172 $tag['length'] = strlen($tagMatch[0][0]);
174 $tag['close'] = 2 == strlen($openTagTail);
177 $closeTag = '</' . $name . '>';
178 $closeTagLength = strlen($closeTag);
179 $tag['paired'] = true;
180 $end = strpos($content, $closeTag, $tag['position']);
183 $openTagLength = strlen($tagMatch[0][0]);
184 $tag['body'] = substr($content, $tag['position'] + $openTagLength,
185 $end - $openTagLength - $tag['position']);
186 $tag['length'] = $end + $closeTagLength - $tag['position'];
190 $rawAttributes = trim(substr($tagMatch[0][0], strlen($name) + 1,
191 strlen($tagMatch[0][0]) - strlen($name) - 1 - strlen($openTagTail)));
192 $attributes = array();
193 if (preg_match_all('~([^=\s]+)\s*=\s*(?:(")([^"]+)"|(\')([^\']+)\'|([^\s]+))~',
194 $rawAttributes, $attributeMatches, PREG_SET_ORDER))
196 foreach ($attributeMatches as $attrMatch) {
197 $attrName = $attrMatch[1];
198 $attrDelimeter = (isset($attrMatch[2]) && '' !== $attrMatch[2])
200 : ((isset($attrMatch[4]) && '' !== $attrMatch[4])
201 ? $attrMatch[4] : '');
202 $attrValue = (isset($attrMatch[3]) && '' !== $attrMatch[3])
204 : ((isset($attrMatch[5]) && '' !== $attrMatch[5])
205 ? $attrMatch[5] : $attrMatch[6]);
206 if ('class' == $attrName)
207 $attrValue = explode(' ', preg_replace('~\s+~', ' ', $attrValue));
208 $attributes[$attrName] = array('delimeter' => $attrDelimeter,
209 'value' => $attrValue);
212 // apply filter to attributes
214 $filter = isset($filters[$normalName])
215 ? $filters[$normalName]
216 : (isset($filters['*']) ? $filters['*'] : array());
217 foreach ($filter as $key => $value) {
218 $criteria = is_array($value) ? $value : array($value);
219 for ($c = 0; $c < count($criteria) && $passed; $c++) {
220 $crit = $criteria[$c];
222 // attribute should be empty
223 if ('class' == $key) {
224 if (isset($attributes[$key]) && count($attributes[$key]['value']) != 0) {
229 if (isset($attributes[$key]) && strlen($attributes[$key]['value']) != 0) {
234 } else if ('!' == $crit) {
235 // attribute should be not set or empty
236 if ('class' == $key) {
237 if (!isset($attributes[$key]) || count($attributes[$key]['value']) == 0) {
242 if (!isset($attributes[$key]) || strlen($attributes[$key]['value']) == 0) {
247 } else if ('!' == $crit[0]) {
248 // * attribute should not contain value
249 // * if attribute is empty, it does not contain value
250 if ('class' == $key) {
251 if (isset($attributes[$key]) && count($attributes[$key]['value']) != 0
252 && in_array(substr($crit, 1), $attributes[$key]['value']))
258 if (isset($attributes[$key]) && strlen($attributes[$key]['value']) != 0
259 && $crit == $attributes[$key]['value'])
266 // * attribute should contain value
267 // * if attribute is empty, it does not contain value
268 if ('class' == $key) {
269 if (!isset($attributes[$key]) || count($attributes[$key]['value']) == 0) {
273 if (!in_array($crit, $attributes[$key]['value'])) {
278 if (!isset($attributes[$key]) || strlen($attributes[$key]['value']) == 0) {
282 if ($crit != $attributes[$key]['value']) {
294 // finalize tag info constrution
295 $tag['attributes'] = $attributes;
296 $result[$index] = substr($content, $position, $tag['position'] - $position);
297 $position = $tag['position'] + $tag['length'];
299 $result[$index] = $tag;
303 $result[$index] = $position < strlen($content) ? substr($content, $position) : '';
308 * Converts tag info created by artxFindTags back to text tag.
312 function artxTagInfoToString($info)
314 $result = '<' . $info['name'];
315 if (isset($info['attributes']) && 0 != count($info['attributes'])) {
317 foreach ($info['attributes'] as $key => $value)
318 $attributes .= ' ' . $key . '=' . $value['delimeter']
319 . (is_array($value['value']) ? implode(' ', $value['value']) : $value['value'])
320 . $value['delimeter'];
321 $result .= $attributes;
323 if ($info['paired']) {
325 $result .= $info['body'];
326 $result .= '</' . $info['name'] . '>';
328 $result .= ($info['close'] ? ' /' : '') . '>';
333 * Decorates the specified tag with artisteer button style.
335 * @param string $name tag name that should be decorated
336 * @param array $filter select $name tags with attributes matching $filter
337 * @return $content with replaced $name tags
339 function artxReplaceButtons($content, $filter = array('input' => array('class' => 'button')))
342 foreach (artxFindTags($content, $filter) as $tag) {
346 $tag['attributes']['class']['value'][] = 'art-button';
347 $result .= artxTagInfoToString($tag);
353 function artxLinkButton($data = array())
355 return '<a class="' . (isset($data['classes']) && isset($data['classes']['a']) ? $data['classes']['a'] . ' ' : '')
356 . 'art-button" href="' . $data['link'] . '">' . $data['content'] . '</a>';
359 function artxHtmlFixFormAction($content)
361 if (preg_match('~ action="([^"]+)" ~', $content, $matches, PREG_OFFSET_CAPTURE)) {
362 $content = substr($content, 0, $matches[0][1])
363 . ' action="' . artxUrlToHref($matches[1][0]) . '" '
364 . substr($content, $matches[0][1] + strlen($matches[0][0]));
369 function artxTagBuilder($tag, $attributes = array(), $content = '') {
370 $result = '<' . $tag;
371 foreach ($attributes as $name => $value) {
372 if (is_string($value)) {
374 $result .= ' ' . $name . '="' . $value . '"';
375 } else if (is_array($value)) {
376 $values = array_filter($value);
378 $result .= ' ' . $name . '="' . implode(' ', $value) . '"';
381 $result .= '>' . $content . '</' . $tag . '>';
385 $artxFragments = array();
387 function artxFragmentBegin($head = '')
389 global $artxFragments;
390 $artxFragments[] = array('head' => $head, 'content' => '', 'tail' => '');
393 function artxFragmentContent($content = '')
395 global $artxFragments;
396 $artxFragments[count($artxFragments) - 1]['content'] = $content;
399 function artxFragmentEnd($tail = '', $separator = '', $return = false)
401 global $artxFragments;
402 $fragment = array_pop($artxFragments);
403 $fragment['tail'] = $tail;
404 $content = trim($fragment['content']);
405 if (count($artxFragments) == 0) {
407 return (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
408 echo (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
410 $result = (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
411 $fragment =& $artxFragments[count($artxFragments) - 1];
412 $fragment['content'] .= (trim($fragment['content']) == '' ? '' : $separator) . $result;
416 function artxFragment($head = '', $content = '', $tail = '', $separator = '', $return = false)
418 global $artxFragments;
419 if ($head != '' && $content == '' && $tail == '' && $separator == '') {
422 } elseif ($head != '' && $content != '' && $tail == '' && $separator == '') {
423 $separator = $content;
427 artxFragmentBegin($head);
428 artxFragmentContent($content);
429 artxFragmentEnd($tail, $separator, $return);
432 function artxPostprocessBlockContent($content)
434 return artxPostprocessContent($content);
437 function artxPostprocessPostContent($content)
439 return artxPostprocessContent($content);
442 function artxPostprocessContent($content)
444 $config = JFactory::getConfig();
445 $sef = method_exists($config, 'getValue') ? $config->getValue('config.sef') : $sef = $config->get('config.sef');
447 $content = str_replace('url(\'images/', 'url(\'' . JURI::base(true) . '/images/', $content);
448 $content = artxReplaceButtons($content, array('input' => array('class' => array('button', '!art-button')),
449 'button' => array('class' => array('button', '!art-button'))));
453 function artxBalanceTags($text) {
455 $singleTags = array('area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source');
456 $nestedTags = array('blockquote', 'div', 'object', 'q', 'span');
463 while (preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $match)) {
466 $i = strpos($text, $match[0]);
467 $l = strlen($match[0]);
471 if (isset($match[1][0]) && '/' == $match[1][0]) {
472 // processing of the end tag
473 $tag = strtolower(substr($match[1],1));
477 } else if ($stack[$size - 1] == $tag) {
478 $tag = '</' . $tag . '>';
482 for ($j = $size-1; $j >= 0; $j--) {
483 if ($stack[$j] == $tag) {
484 for ($k = $size-1; $k >= $j; $k--) {
485 $queue .= '</' . array_pop($stack) . '>';
494 // processing of the begin tag
495 $tag = strtolower($match[1]);
497 if (substr($match[2], -1) == '/') {
498 if (!in_array($tag, $singleTags))
499 $match[2] = trim(substr($match[2], 0, -1)) . "></$tag";
500 } elseif (in_array($tag, $singleTags)) {
503 if ($size > 0 && !in_array($tag, $nestedTags) && $stack[$size - 1] == $tag) {
504 $queue = '</' . array_pop($stack) . '>';
507 $size = array_push($stack, $tag);
511 $attributes = $match[2];
512 if(!empty($attributes) && $attributes[0] != '>')
513 $attributes = ' ' . $attributes;
515 $tag = '<' . $tag . $attributes . '>';
517 if (!empty($queue)) {
522 $output .= substr($text, 0, $i) . $tag;
523 $text = substr($text, $i + $l);
526 $output .= ($queue . $text);
528 while($t = array_pop($stack))
529 $output .= '</' . $t . '>';