3 defined('_JEXEC') or die;
5 if (!defined('_ARTX_FUNCTIONS')) {
7 define('_ARTX_FUNCTIONS', 1);
8 define('_M3_BUTTON_CLASS', 'btn'); // Magic3用のボタンクラス
10 $GLOBALS['artx_settings'] = array(
11 'block' => array('has_header' => true),
12 'menu' => array('show_submenus' => true),
13 'vmenu' => array('show_submenus' => false, 'simple' => false)
16 require_once dirname(__FILE__) . '/library/Artx.php';
19 * Decorates an article or block with the art-post style.
21 * Elements of the $data array:
26 * 'metadata-header-icons'
27 * 'metadata-footer-icons'
30 function artxPost($data)
33 $data = array('content' => $data);
34 $classes = isset($data['classes']) && strlen($data['classes']) ? $data['classes'] : '';
35 artxFragmentBegin("<article class=\"art-post" . $classes . "\">");
36 artxFragmentBegin("<h2 class=\"art-postheader\">");
37 if (isset($data['header-text']) && strlen($data['header-text'])) {
38 if (isset($data['header-link']) && strlen($data['header-link']))
39 artxFragmentContent('<a href="' . $data['header-link'] . '">' . $data['header-text'] . '</a>');
41 artxFragmentContent($data['header-text']);
43 artxFragmentEnd("</h2>");
44 artxFragmentBegin("<div class=\"art-postheadericons art-metadata-icons\">");
45 if (isset($data['metadata-header-icons']) && count($data['metadata-header-icons']))
46 foreach ($data['metadata-header-icons'] as $icon)
47 artxFragment('', $icon, '', ' | ');
48 artxFragmentEnd("</div>");
49 artxFragmentBegin("<div class=\"art-postcontent clearfix\">");
50 if (isset($data['content']) && strlen($data['content']))
51 artxFragmentContent(artxPostprocessPostContent($data['content']));
52 artxFragmentEnd("</div>");
53 artxFragmentBegin("<div class=\"art-postfootericons art-metadata-icons\">");
54 if (isset($data['metadata-footer-icons']) && count($data['metadata-footer-icons']))
55 foreach ($data['metadata-footer-icons'] as $icon)
56 artxFragment('', $icon, '', ' | ');
57 artxFragmentEnd("</div>");
59 return artxFragmentEnd("</article>", '', true);
63 function artxBlock($caption, $content, $classes = '')
65 $hasCaption = ($GLOBALS['artx_settings']['block']['has_header']
66 && null !== $caption && strlen(trim($caption)) > 0);
67 $hasContent = (null !== $content && strlen(trim($content)) > 0);
68 if (!$hasCaption && !$hasContent) return '';
71 artxFragmentBegin("<div class=\"art-block clearfix" . $classes . "\">");
72 artxFragmentBegin("<div class=\"art-blockheader\"><h3 class=\"t\">");
73 artxFragmentContent($caption);
74 artxFragmentEnd("</h3></div>");
75 artxFragmentBegin("<div class=\"art-blockcontent\">");
76 artxFragmentContent(artxPostprocessBlockContent($content));
77 artxFragmentEnd("</div>");*/
79 artxFragmentBegin('<div class="m3widget_box ui-widget">');
80 artxFragmentBegin('<div class="m3widget_box_head ui-state-default ui-priority-primary ui-corner-tl ui-corner-tr">');
81 artxFragmentContent($caption);
82 artxFragmentEnd('</div>');
83 artxFragmentBegin('<div class="m3widget_box_content ui-widget-content ui-corner-bl ui-corner-br">');
84 artxFragmentContent(artxPostprocessBlockContent($content));
85 artxFragmentEnd('</div>');
86 return artxFragmentEnd("</div>", '', true);
91 function artxUrlToHref($url)
95 if (isset($p['scheme']) && isset($p['host'])) {
96 $result = $p['scheme'] . '://';
97 if (isset($p['user'])) {
98 $result .= $p['user'];
99 if (isset($p['pass']))
100 $result .= ':' . $p['pass'];
103 $result .= $p['host'];
104 if (isset($p['port']))
105 $result .= ':' . $p['port'];
106 if (!isset($p['path']))
109 if (isset($p['path']))
110 $result .= $p['path'];
111 if (isset($p['query'])) {
112 $result .= '?' . str_replace('&', '&', $p['query']);
114 if (isset($p['fragment']))
115 $result .= '#' . $p['fragment'];
120 * Searches $content for tags and returns information about each found tag.
122 * Created to support button replacing process, e.g. wrapping submit/reset
123 * inputs and buttons with artisteer style.
125 * When all the $name tags are found, they are processed by the $filter specified.
126 * Filter is applied to the attributes. When an attribute contains several values
127 * (e.g. class attribute), only tags that contain all the values from filter
128 * will be selected. E.g. filtering by the button class will select elements
129 * with class="button" and class="button validate".
131 * Parsing does not support nested tags. Looking for span tags in
132 * <span>1<span>2</span>3</span> will return <span>1<span>2</span> and
136 * Select all tags with class='readon':
137 * artxFindTags($html, array('*' => array('class' => 'readon')))
138 * Select inputs with type='submit' and class='button':
139 * artxFindTags($html, array('input' => array('type' => 'submit', 'class' => 'button')))
140 * Select inputs with type='submit' and class='button validate':
141 * artxFindTags($html, array('input' => array('type' => 'submit', 'class' => array('button', 'validate'))))
142 * Select inputs with class != 'art-button'
143 * artxFindTags($html, array('input' => array('class' => '!art-button')))
144 * Select inputs with non-empty class
145 * artxFindTags($html, array('input' => array('class' => '!')))
146 * Select inputs with class != 'art-button' and non-empty class:
147 * artxFindTags($html, array('input' => array('class' => array('!art-button', '!'))))
148 * Select inputs with class = button but != 'art-button'
149 * artxFindTags($html, array('input' => array('class' => array('button', '!art-button'))))
151 * @return array of text fragments and tag information: position, length,
152 * name, attributes, raw_open_tag, body.
154 function artxFindTags($content, $filters)
159 $name = implode('|', array_keys($filters));
160 $name = str_replace('*', '\w+', $name);
161 // search for open tag
163 '~<(' . $name . ')\b(?:\s+[^\s]+\s*=\s*(?:"[^"]+"|\'[^\']+\'|[^\s>]+))*\s*/?' . '>~i', $content,
164 $tagMatches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
166 foreach ($tagMatches as $tagMatch) {
167 $rawMatch = $tagMatch[0][0];
168 $name = $tagMatch[1][0];
169 $normalName = strtolower($name);
170 $tag = array('name' => $name, 'position' => $tagMatch[0][1]);
171 $openTagTail = (strlen($rawMatch) > 1 && '/' == $rawMatch[strlen($rawMatch) - 2])
173 // different instructions for paired and unpaired tags
179 $tag['paired'] = false;
180 $tag['length'] = strlen($tagMatch[0][0]);
182 $tag['close'] = 2 == strlen($openTagTail);
185 $closeTag = '</' . $name . '>';
186 $closeTagLength = strlen($closeTag);
187 $tag['paired'] = true;
188 $end = strpos($content, $closeTag, $tag['position']);
191 $openTagLength = strlen($tagMatch[0][0]);
192 $tag['body'] = substr($content, $tag['position'] + $openTagLength,
193 $end - $openTagLength - $tag['position']);
194 $tag['length'] = $end + $closeTagLength - $tag['position'];
198 $rawAttributes = trim(substr($tagMatch[0][0], strlen($name) + 1,
199 strlen($tagMatch[0][0]) - strlen($name) - 1 - strlen($openTagTail)));
200 $attributes = array();
201 if (preg_match_all('~([^=\s]+)\s*=\s*(?:(")([^"]+)"|(\')([^\']+)\'|([^\s]+))~',
202 $rawAttributes, $attributeMatches, PREG_SET_ORDER))
204 foreach ($attributeMatches as $attrMatch) {
205 $attrName = $attrMatch[1];
206 $attrDelimeter = (isset($attrMatch[2]) && '' !== $attrMatch[2])
208 : ((isset($attrMatch[4]) && '' !== $attrMatch[4])
209 ? $attrMatch[4] : '');
210 $attrValue = (isset($attrMatch[3]) && '' !== $attrMatch[3])
212 : ((isset($attrMatch[5]) && '' !== $attrMatch[5])
213 ? $attrMatch[5] : $attrMatch[6]);
214 if ('class' == $attrName)
215 $attrValue = explode(' ', preg_replace('~\s+~', ' ', $attrValue));
216 $attributes[$attrName] = array('delimeter' => $attrDelimeter,
217 'value' => $attrValue);
220 // apply filter to attributes
222 $filter = isset($filters[$normalName])
223 ? $filters[$normalName]
224 : (isset($filters['*']) ? $filters['*'] : array());
225 foreach ($filter as $key => $value) {
226 $criteria = is_array($value) ? $value : array($value);
227 for ($c = 0; $c < count($criteria) && $passed; $c++) {
228 $crit = $criteria[$c];
230 // attribute should be empty
231 if ('class' == $key) {
232 if (isset($attributes[$key]) && count($attributes[$key]['value']) != 0) {
237 if (isset($attributes[$key]) && strlen($attributes[$key]['value']) != 0) {
242 } else if ('!' == $crit) {
243 // attribute should be not set or empty
244 if ('class' == $key) {
245 if (!isset($attributes[$key]) || count($attributes[$key]['value']) == 0) {
250 if (!isset($attributes[$key]) || strlen($attributes[$key]['value']) == 0) {
255 } else if ('!' == $crit[0]) {
256 // * attribute should not contain value
257 // * if attribute is empty, it does not contain value
258 if ('class' == $key) {
259 if (isset($attributes[$key]) && count($attributes[$key]['value']) != 0
260 && in_array(substr($crit, 1), $attributes[$key]['value']))
266 if (isset($attributes[$key]) && strlen($attributes[$key]['value']) != 0
267 && $crit == $attributes[$key]['value'])
274 // * attribute should contain value
275 // * if attribute is empty, it does not contain value
276 if ('class' == $key) {
277 if (!isset($attributes[$key]) || count($attributes[$key]['value']) == 0) {
281 if (!in_array($crit, $attributes[$key]['value'])) {
286 if (!isset($attributes[$key]) || strlen($attributes[$key]['value']) == 0) {
290 if ($crit != $attributes[$key]['value']) {
302 // finalize tag info constrution
303 $tag['attributes'] = $attributes;
304 $result[$index] = substr($content, $position, $tag['position'] - $position);
305 $position = $tag['position'] + $tag['length'];
307 $result[$index] = $tag;
311 $result[$index] = $position < strlen($content) ? substr($content, $position) : '';
316 * Converts tag info created by artxFindTags back to text tag.
320 function artxTagInfoToString($info)
322 $result = '<' . $info['name'];
323 if (isset($info['attributes']) && 0 != count($info['attributes'])) {
325 foreach ($info['attributes'] as $key => $value)
326 $attributes .= ' ' . $key . '=' . $value['delimeter']
327 . (is_array($value['value']) ? implode(' ', $value['value']) : $value['value'])
328 . $value['delimeter'];
329 $result .= $attributes;
331 if ($info['paired']) {
333 $result .= $info['body'];
334 $result .= '</' . $info['name'] . '>';
336 $result .= ($info['close'] ? ' /' : '') . '>';
341 * Decorates the specified tag with artisteer button style.
343 * @param string $name tag name that should be decorated
344 * @param array $filter select $name tags with attributes matching $filter
345 * @return $content with replaced $name tags
347 function artxReplaceButtons($content, $filter = array('input' => array('class' => 'button')))
350 foreach (artxFindTags($content, $filter) as $tag) {
354 //$tag['attributes']['class']['value'][] = 'art-button'; // 追加しない
355 $tag['attributes']['class']['value'] = array(_M3_BUTTON_CLASS); // ボタンクラスを変更
356 $result .= artxTagInfoToString($tag);
362 function artxLinkButton($data = array())
364 return '<a class="' . (isset($data['classes']) && isset($data['classes']['a']) ? $data['classes']['a'] . ' ' : '')
365 . 'art-button" href="' . $data['link'] . '">' . $data['content'] . '</a>';
368 function artxHtmlFixFormAction($content)
370 if (preg_match('~ action="([^"]+)" ~', $content, $matches, PREG_OFFSET_CAPTURE)) {
371 $content = substr($content, 0, $matches[0][1])
372 . ' action="' . artxUrlToHref($matches[1][0]) . '" '
373 . substr($content, $matches[0][1] + strlen($matches[0][0]));
378 function artxTagBuilder($tag, $attributes = array(), $content = '') {
379 $result = '<' . $tag;
380 foreach ($attributes as $name => $value) {
381 if (is_string($value)) {
383 $result .= ' ' . $name . '="' . $value . '"';
384 } else if (is_array($value)) {
385 $values = array_filter($value);
387 $result .= ' ' . $name . '="' . implode(' ', $value) . '"';
390 $result .= '>' . $content . '</' . $tag . '>';
394 $artxFragments = array();
396 function artxFragmentBegin($head = '')
398 global $artxFragments;
399 $artxFragments[] = array('head' => $head, 'content' => '', 'tail' => '');
402 function artxFragmentContent($content = '')
404 global $artxFragments;
405 $artxFragments[count($artxFragments) - 1]['content'] = $content;
408 function artxFragmentEnd($tail = '', $separator = '', $return = false)
410 global $artxFragments;
411 $fragment = array_pop($artxFragments);
412 $fragment['tail'] = $tail;
413 $content = trim($fragment['content']);
414 if (count($artxFragments) == 0) {
416 return (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
417 echo (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
419 $result = (trim($content) == '') ? '' : ($fragment['head'] . $content . $fragment['tail']);
420 $fragment =& $artxFragments[count($artxFragments) - 1];
421 $fragment['content'] .= (trim($fragment['content']) == '' ? '' : $separator) . $result;
425 function artxFragment($head = '', $content = '', $tail = '', $separator = '', $return = false)
427 global $artxFragments;
428 if ($head != '' && $content == '' && $tail == '' && $separator == '') {
431 } elseif ($head != '' && $content != '' && $tail == '' && $separator == '') {
432 $separator = $content;
436 artxFragmentBegin($head);
437 artxFragmentContent($content);
438 artxFragmentEnd($tail, $separator, $return);
441 function artxPostprocessBlockContent($content)
443 return artxPostprocessContent($content);
446 function artxPostprocessPostContent($content)
448 return artxPostprocessContent($content);
451 function artxPostprocessContent($content)
453 // $config = JFactory::getConfig();
454 // $sef = method_exists($config, 'getValue') ? $config->getValue('config.sef') : $sef = $config->get('config.sef');
455 // if ($sef) $content = str_replace('url(\'images/', 'url(\'' . JURI::base(true) . '/images/', $content);
456 // $content = artxReplaceButtons($content, array('input' => array('class' => array('button', '!art-button')),
457 // 'button' => array('class' => array('button', '!art-button'))));
461 function artxBalanceTags($text) {
463 $singleTags = array('area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source');
464 $nestedTags = array('blockquote', 'div', 'object', 'q', 'span');
471 while (preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $match)) {
474 $i = strpos($text, $match[0]);
475 $l = strlen($match[0]);
479 if (isset($match[1][0]) && '/' == $match[1][0]) {
480 // processing of the end tag
481 $tag = strtolower(substr($match[1],1));
485 } else if ($stack[$size - 1] == $tag) {
486 $tag = '</' . $tag . '>';
490 for ($j = $size-1; $j >= 0; $j--) {
491 if ($stack[$j] == $tag) {
492 for ($k = $size-1; $k >= $j; $k--) {
493 $queue .= '</' . array_pop($stack) . '>';
502 // processing of the begin tag
503 $tag = strtolower($match[1]);
505 if (substr($match[2], -1) == '/') {
506 if (!in_array($tag, $singleTags))
507 $match[2] = trim(substr($match[2], 0, -1)) . "></$tag";
508 } elseif (in_array($tag, $singleTags)) {
511 if ($size > 0 && !in_array($tag, $nestedTags) && $stack[$size - 1] == $tag) {
512 $queue = '</' . array_pop($stack) . '>';
515 $size = array_push($stack, $tag);
519 $attributes = $match[2];
520 if(!empty($attributes) && $attributes[0] != '>')
521 $attributes = ' ' . $attributes;
523 $tag = '<' . $tag . $attributes . '>';
525 if (!empty($queue)) {
530 $output .= substr($text, 0, $i) . $tag;
531 $text = substr($text, $i + $l);
534 $output .= ($queue . $text);
536 while($t = array_pop($stack))
537 $output .= '</' . $t . '>';