PageRenderTime 55ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/rah_repeat/rah_repeat.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 670 lines | 421 code | 161 blank | 88 comment | 35 complexity | 104143185afd1804a061cf10cee95ccd MD5 | raw file
  1. <?php
  2. // This is a PLUGIN TEMPLATE for Textpattern CMS.
  3. // Copy this file to a new name like abc_myplugin.php. Edit the code, then
  4. // run this file at the command line to produce a plugin for distribution:
  5. // $ php abc_myplugin.php > abc_myplugin-0.1.txt
  6. // Plugin name is optional. If unset, it will be extracted from the current
  7. // file name. Plugin names should start with a three letter prefix which is
  8. // unique and reserved for each plugin author ("abc" is just an example).
  9. // Uncomment and edit this line to override:
  10. $plugin['name'] = 'rah_repeat';
  11. // Allow raw HTML help, as opposed to Textile.
  12. // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
  13. // 1 = Plugin help is in raw HTML. Not recommended.
  14. # $plugin['allow_html_help'] = 1;
  15. $plugin['version'] = '1.0.1';
  16. $plugin['author'] = 'Jukka Svahn';
  17. $plugin['author_uri'] = 'http://rahforum.biz';
  18. $plugin['description'] = 'Iterations made easy';
  19. // Plugin load order:
  20. // The default value of 5 would fit most plugins, while for instance comment
  21. // spam evaluators or URL redirectors would probably want to run earlier
  22. // (1...4) to prepare the environment for everything else that follows.
  23. // Values 6...9 should be considered for plugins which would work late.
  24. // This order is user-overrideable.
  25. $plugin['order'] = '5';
  26. // Plugin 'type' defines where the plugin is loaded
  27. // 0 = public : only on the public side of the website (default)
  28. // 1 = public+admin : on both the public and admin side
  29. // 2 = library : only when include_plugin() or require_plugin() is called
  30. // 3 = admin : only on the admin side (no AJAX)
  31. // 4 = admin+ajax : only on the admin side (AJAX supported)
  32. // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
  33. $plugin['type'] = '0';
  34. // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
  35. // Use an appropriately OR-ed combination of these flags.
  36. // The four high-order bits 0xf000 are available for this plugin's private use
  37. if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
  38. if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
  39. $plugin['flags'] = '0';
  40. // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
  41. // Syntax:
  42. // ## arbitrary comment
  43. // #@event
  44. // #@language ISO-LANGUAGE-CODE
  45. // abc_string_name => Localized String
  46. /** Uncomment me, if you need a textpack
  47. $plugin['textpack'] = <<<EOT
  48. #@admin
  49. #@language en-gb
  50. abc_sample_string => Sample String
  51. abc_one_more => One more
  52. #@language de-de
  53. abc_sample_string => Beispieltext
  54. abc_one_more => Noch einer
  55. EOT;
  56. **/
  57. // End of textpack
  58. if (!defined('txpinterface'))
  59. @include_once('zem_tpl.php');
  60. # --- BEGIN PLUGIN CODE ---
  61. /**
  62. * Rah_repeat plugin for Textpattern CMS.
  63. *
  64. * @author Jukka Svahn
  65. * @license GNU GPLv2
  66. * @link http://rahforum.biz/plugins/rah_repeat
  67. *
  68. * Copyright (C) 2013 Jukka Svahn http://rahforum.biz
  69. * Licensed under GNU Genral Public License version 2
  70. * http://www.gnu.org/licenses/gpl-2.0.html
  71. */
  72. /**
  73. * Creates a list from the given values.
  74. *
  75. * @param array $atts
  76. * @param string $thing
  77. * @return string
  78. */
  79. function rah_repeat($atts, $thing = null)
  80. {
  81. global $rah_repeat, $variable;
  82. extract(lAtts(array(
  83. 'form' => '',
  84. 'delimiter' => ',',
  85. 'value' => '',
  86. 'limit' => null,
  87. 'offset' => 0,
  88. 'wraptag' => '',
  89. 'break' => '',
  90. 'class' => '',
  91. 'duplicates' => 0,
  92. 'sort' => '',
  93. 'exclude' => null,
  94. 'trim' => 1,
  95. 'range' => '',
  96. 'assign' => null,
  97. ), $atts));
  98. if ($range && strpos($range, ','))
  99. {
  100. $values = call_user_func_array('range', do_list($range));
  101. }
  102. else
  103. {
  104. $values = explode($delimiter, $value);
  105. }
  106. if ($trim)
  107. {
  108. $values = doArray($values, 'trim');
  109. }
  110. if ($duplicates)
  111. {
  112. $values = array_unique($values);
  113. }
  114. if ($exclude !== null)
  115. {
  116. $exclude = explode($delimiter, $exclude);
  117. if ($trim)
  118. {
  119. $exclude = doArray($exclude, 'trim');
  120. }
  121. $values = array_diff($values, $exclude);
  122. }
  123. if ($sort && $sort = doArray(doArray(explode(' ', trim($sort), 2), 'trim'), 'strtoupper'))
  124. {
  125. if (count($sort) == 2 && defined('SORT_'.$sort[0]))
  126. {
  127. sort($values, constant('SORT_'.$sort[0]));
  128. }
  129. if (end($sort) == 'DESC')
  130. {
  131. $values = array_reverse($values);
  132. }
  133. }
  134. $values = array_slice($values, $offset, $limit);
  135. if ($assign !== null)
  136. {
  137. foreach (do_list($assign) as $key => $var)
  138. {
  139. $value = isset($values[$key]) ? $values[$key] : '';
  140. $variable[$var] = $value;
  141. }
  142. }
  143. if (!$values || ($thing === null && $form === ''))
  144. {
  145. return '';
  146. }
  147. $count = count($values);
  148. $i = 0;
  149. $out = array();
  150. foreach ($values as $string)
  151. {
  152. $i++;
  153. $parent = $rah_repeat;
  154. $rah_repeat = array(
  155. 'string' => $string,
  156. 'first' => ($i == 1),
  157. 'last' => ($count == $i),
  158. 'index' => $i - 1,
  159. );
  160. if ($thing === null && $form !== '')
  161. {
  162. $out[] = parse_form($form);
  163. }
  164. else
  165. {
  166. $out[] = parse($thing);
  167. }
  168. $rah_repeat = $parent;
  169. }
  170. unset($rah_repeat);
  171. return doWrap($out, $wraptag, $break, $class);
  172. }
  173. /**
  174. * Returns the current value.
  175. *
  176. * @param array $atts
  177. * @return string
  178. */
  179. function rah_repeat_value($atts)
  180. {
  181. global $rah_repeat;
  182. extract(lAtts(array(
  183. 'escape' => 0,
  184. 'index' => 0,
  185. ), $atts));
  186. if (!isset($rah_repeat['string']))
  187. {
  188. return '';
  189. }
  190. if ($index)
  191. {
  192. return $rah_repeat['index'];
  193. }
  194. if ($escape)
  195. {
  196. return txpspecialchars($rah_repeat['string']);
  197. }
  198. return $rah_repeat['string'];
  199. }
  200. /**
  201. * Checks if the item is the first.
  202. *
  203. * @param array $atts
  204. * @param string $thing
  205. * @return string
  206. */
  207. function rah_repeat_if_first($atts, $thing = '')
  208. {
  209. global $rah_repeat;
  210. return parse(EvalElse($thing, $rah_repeat['first'] == true));
  211. }
  212. /**
  213. * Checks if the item is the last.
  214. *
  215. * @param array $atts
  216. * @param string $thing
  217. * @return string
  218. */
  219. function rah_repeat_if_last($atts, $thing = '')
  220. {
  221. global $rah_repeat;
  222. return parse(EvalElse($thing, $rah_repeat['last'] == true));
  223. }
  224. # --- END PLUGIN CODE ---
  225. if (0) {
  226. ?>
  227. <!--
  228. # --- BEGIN PLUGIN HELP ---
  229. <h1>rah_repeat</h1>
  230. <p><a href="http://rahforum.biz/plugins/rah_repeat" rel="nofollow">Project page</a> | <a href="https://packagist.org/packages/rah/rah_repeat" rel="nofollow">Packagist</a> | <a href="http://twitter.com/gocom" rel="nofollow">Twitter</a> | <a href="https://github.com/gocom/rah_repeat" rel="nofollow">GitHub</a> | <a href="http://forum.textpattern.com/viewtopic.php?id=32384" rel="nofollow">Support forum</a> | <a href="http://rahforum.biz/donate/rah_repeat" rel="nofollow">Donate</a></p>
  231. <p>Rah_repeat is a <a href="http://www.textpattern.com" rel="nofollow">Textpattern <span class="caps">CMS</span></a> plugin used for iterations. The plugin splits a provided value to smaller chunks and iterates overs, just like you would expect from a for each loop in any programming language. With the plugin you can turn a simple comma-separated list of values into advanced <span class="caps">HTML</span> output, or extract parts of a value as <a href="http://textpattern.net/wiki/index.php?title=variable" rel="nofollow">variables</a>.</p>
  232. <h2>Requirements</h2>
  233. <p>Rah_repeat&#8217;s minimum requirements:</p>
  234. <ul>
  235. <li>Textpattern 4.5.0 or newer.</li>
  236. </ul>
  237. <h2>Installing</h2>
  238. <p>Rah_repeat&#8217;s installation follows the standard plugin installation steps.</p>
  239. <ol>
  240. <li>Download the plugin installation code.</li>
  241. <li>Copy and paste the installation code into the <em>Install plugin</em> box of your Textpattern Plugin pane.</li>
  242. <li>Run the automated setup.</li>
  243. <li>After the setup is done, activate the plugin. Done.</li>
  244. </ol>
  245. <h2>Basics</h2>
  246. <pre><code>&lt;txp:rah_repeat range=&quot;min, max, step&quot; value=&quot;value1, value2, ...&quot; assign=&quot;variable1, variable2, ...&quot;&gt;
  247. ...contained statement...
  248. &lt;/txp:rah_repeat&gt;</code></pre>
  249. <p>Rah_repeat&#8217;s main job is primely iterating over values. Its iteration power can used to create lists or extract subsets of data. The plugin can come very handy when you have a <a href="http://textpattern.net/wiki/index.php?title=custom_field" rel="nofollow">custom field</a> that contains comma-separated list of values which you want to present as a <span class="caps">HTML</span> list or extract as individual separate values.</p>
  250. <p>The values you want to iterate over are provided to the tag with the <code>value</code> attribute, each individual subset value separated from each other with the <code>delimiter</code>, defaulting to a comma. The current value that is being iterated over can be returned using the <code>rah_repeat_value</code> tag, wrapped in <code>rah_repeat</code> block. The following would generate a <span class="caps">HTML</span> list from comma-separated list of <code>red, blue, green</code>.</p>
  251. <pre><code>&lt;txp:rah_repeat value=&quot;red, blue, green&quot; wraptag=&quot;ul&quot; break=&quot;li&quot;&gt;
  252. &lt;txp:rah_repeat_value /&gt;
  253. &lt;/txp:rah_repeat&gt;</code></pre>
  254. <p>In addition to iterating over values and creating lists, the tag can also be used to extract values and assign each one to a <a href="http://textpattern.net/wiki/index.php?title=variable" rel="nofollow">variable</a> tag. This can be done using the <code>rah_repeat</code> tag&#8217;s <code>assign</code> attribute. The attribute takes a comma-separated list of variable names that will be created, each containing one of the values.</p>
  255. <pre><code>&lt;txp:rah_repeat value=&quot;red, blue, green&quot; assign=&quot;color1, color2, color3&quot; /&gt;</code></pre>
  256. <p>The above would extra each of the colors as a variable. These variables would be named as <code>color1</code>, <code>color2</code> and <code>color3</code>. Using <code>&lt;txp:variable name=&quot;color1&quot; /&gt;</code> would return <code>red</code>.</p>
  257. <h2>Tags and attributes</h2>
  258. <p>The plugin comes with a total of four tags. The main tag <code>rah_repeat</code>, a single tag <code>rah_repeat_value</code>, and two conditionals <code>rah_repeat_if_first</code> and <code>rah_repeat_if_last</code>.</p>
  259. <h3>rah_repeat</h3>
  260. <pre><code>&lt;txp:rah_repeat value=&quot;value1, value2, ...&quot;&gt;
  261. ...contained statement...
  262. &lt;/txp:rah_repeat&gt;</code></pre>
  263. <p>The <code>&lt;txp:rah_repeat&gt;</code> tag is the plugin&#8217;s main tag. It&#8217;s a container tag used for iterations. Attributes for it are as follows.</p>
  264. <p><strong>value</strong><br />
  265. Sets the values that are passed to the tag. Multiple values are separated with the <code>delimiter</code> which by default is a comma (<code>,</code>). This attribute or either <code>range</code> is required.<br />
  266. Example: <code>value=&quot;dog,cat,human&quot;</code> Default: <code>&quot;&quot;</code></p>
  267. <p><strong>range</strong><br />
  268. Creates a list of values containing a range of elements. Using <code>range</code> overrides <code>value</code> attribute. It works identically to <span class="caps">PHP</span>&#8217;s <a href="http://php.net/manual/en/function.range.php" rel="nofollow">range</a> function and uses same sequence syntax as it. The attribute&#8217;s value consists of three parts: <code>minimum</code>, <code>maximum</code> and <code>step</code>, which are separated by a comma. All but <code>step</code> are required.<br />
  269. Example: <code>range=&quot;1, 10&quot;</code> Default: undefined</p>
  270. <p><strong>delimiter</strong><br />
  271. Sets the delimiter that is used to split the provided <code>value</code> into a list. Default delimiter is comma (<code>,</code>).<br />
  272. Example: <code>delimiter=&quot;|&quot;</code> Default: <code>&quot;,&quot;</code></p>
  273. <p><strong>assign</strong><br />
  274. Assigns values as Textpattern&#8217;s <a href="http://textpattern.net/wiki/index.php?title=variable" rel="nofollow">variables</a>. Takes a comma-separated list of variable names: <code>variable1, variable2, variable3, ...</code>.<br />
  275. Example: <code>assign=&quot;label, value&quot;</code> Default: <code>unset</code></p>
  276. <p><strong>duplicates</strong><br />
  277. Removes duplicate values from the list. If the attribute is set to <code>1</code>, only first occurrence of the value is used and duplicates are stripped off.<br />
  278. Example: <code>duplicates=&quot;1&quot;</code> Default: <code>&quot;0&quot;</code></p>
  279. <p><strong>exclude</strong><br />
  280. Exclude certain values from the list. The attribute takes a comma (or <code>delimiter</code>, if <code>delimiter</code> is changed) separated list of values.<br />
  281. Example: <code>exclude=&quot;foo,bar&quot;</code> Default: undefined</p>
  282. <p><strong>trim</strong><br />
  283. Trims values from extra whitespace. This can be particularly helpful if the provided values are from user-input (e.g. from an article field), or the values just have extra whitespace, and the resulting output has to be clean (i.e. used in <span class="caps">XML</span>, JavaScript or to a <a href="http://textpattern.net/wiki/index.php?title=variable" rel="nofollow">variable</a> comparison). If you want to keep whitespace intact, you can use this attribute. By default the option is on, and values are trimmed.<br />
  284. Example: <code>trim=&quot;0&quot;</code> Default: <code>&quot;1&quot;</code></p>
  285. <p><strong>sort</strong><br />
  286. Sorts the values. If the attribute is used, all values are rearranged to the specified order. Available options are <code>regular</code> (sorts without checking the type), <code>numeric</code> (sorts in a numeric order), <code>string</code> (sorts as strings) and <code>locale_string</code> (sorts according server&#8217;s locale settings). All the values can be followed by the sorting direction, either <code>desc</code> and <code>asc</code>. By default the option isn&#8217;t used (unset), and the values are returned in the order they were supplied.<br />
  287. Example: <code>sort=&quot;regular asc&quot;</code> Default: <code>&quot;&quot;</code></p>
  288. <p><strong>offset</strong><br />
  289. The number of items to skip. Default is <code>0</code> (none).<br />
  290. Example: <code>offset=&quot;5&quot;</code> Default: <code>&quot;0&quot;</code></p>
  291. <p><strong>limit</strong><br />
  292. The number of items are displayed. By default there is no limit, and all items are returned.<br />
  293. Example: <code>limit=&quot;10&quot;</code> Default: undefined</p>
  294. <p><strong>form</strong><br />
  295. Use specified form partial. By default contained statement is used instead of a form.<br />
  296. Example: <code>form=&quot;price_column&quot;</code> Default: <code>&quot;&quot;</code></p>
  297. <p><strong>wraptag</strong><br />
  298. The (X)HTML tag (without brackets) used to wrap the output.<br />
  299. Example: <code>wraptag=&quot;div&quot;</code> Default: <code>&quot;&quot;</code></p>
  300. <p><strong>break</strong><br />
  301. The (X)HTML tag (without brackets) or a string used to separate list items.<br />
  302. Example: <code>&quot;break=&quot;br&quot;</code> Default: <code>&quot;&quot;</code></p>
  303. <p><strong>class</strong><br />
  304. The (X)HTML class applied to the <code>wraptag</code>. Default is unset.<br />
  305. Example: <code>class=&quot;plugin&quot;</code> Default: <code>&quot;&quot;</code></p>
  306. <h3>rah_repeat_value</h3>
  307. <pre><code>&lt;txp:rah_repeat value=&quot;value1, value2, ...&quot;&gt;
  308. &lt;txp:rah_repeat_value /&gt;
  309. &lt;/txp:rah_repeat&gt;</code></pre>
  310. <p>Rah_repeat_value a single tag, used to display a iterated value. The tag should be used inside a <code>&lt;txp:rah_repeat&gt;&lt;/txp:rah_repeat&gt;</code> block.</p>
  311. <p><strong>escape</strong><br />
  312. If set to <code>1</code>, <span class="caps">HTML</span> and Textpattern markup are escaped, and special characters are converted to <span class="caps">HTML</span> entities. By default this option is off.<br />
  313. Example: <code>escape=&quot;1&quot;</code> Default: <code>&quot;0&quot;</code></p>
  314. <p><strong>index</strong><br />
  315. If set to <code>1</code>, the tag returns the iterated value&#8217;s index number. The index starts from 0.<br />
  316. Example: <code>index=&quot;1&quot;</code> Default: <code>&quot;0&quot;</code></p>
  317. <h3>rah_repeat_if_first</h3>
  318. <pre><code>&lt;txp:rah_repeat value=&quot;value1, value2, ...&quot;&gt;
  319. &lt;txp:rah_repeat_if_first&gt;
  320. Fist item.
  321. &lt;/txp:rah_repeat_if_first&gt;
  322. &lt;/txp:rah_repeat&gt;</code></pre>
  323. <p>The <code>&lt;txp:rah_repeat_if_first&gt;</code> tag is a container, and has no attributes. It&#8217;s a conditional tag that checks if the current item is the first one.</p>
  324. <h3>rah_repeat_if_last</h3>
  325. <pre><code>&lt;txp:rah_repeat value=&quot;value1, value2, ...&quot;&gt;
  326. &lt;txp:rah_repeat_if_last&gt;
  327. Last item.
  328. &lt;/txp:rah_repeat_if_last&gt;
  329. &lt;/txp:rah_repeat&gt;</code></pre>
  330. <p>The <code>&lt;txp:rah_repeat_if_last&gt;</code> tag is a container, and has no attributes. It&#8217;s a conditional tag that checks if the current item is the last one.</p>
  331. <h2>Examples</h2>
  332. <h3>Simple usage example</h3>
  333. <p>This example turns simple comma separated list of <code>dog, cat, butterfly</code> into a <span class="caps">HTML</span> list.</p>
  334. <pre><code>&lt;txp:rah_repeat value=&quot;dog, cat, butterfly&quot; wraptag=&quot;ul&quot; break=&quot;li&quot;&gt;
  335. A &lt;txp:rah_repeat_value /&gt;.
  336. &lt;/txp:rah_repeat&gt;</code></pre>
  337. <p>The above returns:</p>
  338. <pre><code>&lt;ul&gt;
  339. &lt;li&gt;A dog.&lt;/li&gt;
  340. &lt;li&gt;A cat.&lt;/li&gt;
  341. &lt;li&gt;A butterfly.&lt;/li&gt;
  342. &lt;/ul&gt;</code></pre>
  343. <h3>Using tags as values</h3>
  344. <p>As of Textpattern version 4.0.7, you can use tags inside tags.</p>
  345. <p>Let&#8217;s say that you have comma separated list of items stored inside article&#8217;s <a href="http://textpattern.net/wiki/index.php?title=custom_field" rel="nofollow">custom field</a>. For example, list of Nameless video service&#8217;s video IDs (<code>ID1, ID2, ID3, ID4</code>), and you want to embed each of those as a playable video.</p>
  346. <p>We pass the custom field hosting the video IDs to rah_repeat tag (with the <code>value</code> attribute), and place the video player code inside the container:</p>
  347. <pre><code>&lt;txp:rah_repeat value='&lt;txp:custom_field name=&quot;MyCustomFieldName&quot; /&gt;'&gt;
  348. &lt;object width=&quot;600&quot; height=&quot;380&quot;&gt;
  349. &lt;param name=&quot;movie&quot; value=&quot;http://example.com/v/&lt;txp:rah_repeat_value /&gt;&quot;&gt;&lt;/param&gt;
  350. &lt;embed src=&quot;http://example.com/v/&lt;txp:rah_repeat_value /&gt;&quot; width=&quot;600&quot; height=&quot;380&quot;&gt;&lt;/embed&gt;
  351. &lt;/object&gt;
  352. &lt;/txp:rah_repeat&gt;</code></pre>
  353. <p>The above code would output 4 embedded players (one for each clip), displaying the videos specified with the custom field.</p>
  354. <h3>Taking advantage of offset and limit attributes</h3>
  355. <p>First display two items, then some text between, two more items, some more text and then the rest of the items.</p>
  356. <pre><code>&lt;txp:rah_repeat value='&lt;txp:custom_field name=&quot;MyCustomFieldName&quot; /&gt;' limit=&quot;2&quot;&gt;
  357. &lt;txp:rah_repeat_value /&gt;
  358. &lt;/txp:rah_repeat&gt;
  359. &lt;p&gt;Some text here.&lt;/p&gt;
  360. &lt;txp:rah_repeat value='&lt;txp:custom_field name=&quot;MyCustomFieldName&quot; /&gt;' offset=&quot;2&quot; limit=&quot;4&quot;&gt;
  361. &lt;txp:rah_repeat_value /&gt;
  362. &lt;/txp:rah_repeat&gt;
  363. &lt;p&gt;Some another cool phrase here.&lt;/p&gt;
  364. &lt;txp:rah_repeat value='&lt;txp:custom_field name=&quot;MyCustomFieldName&quot; /&gt;' offset=&quot;4&quot;&gt;
  365. &lt;txp:rah_repeat_value /&gt;
  366. &lt;/txp:rah_repeat&gt;</code></pre>
  367. <h3>Repeat inside repeat</h3>
  368. <pre><code>&lt;txp:rah_repeat value=&quot;group1|item1|item2, group2|item1|item2&quot;&gt;
  369. &lt;ul&gt;
  370. &lt;txp:rah_repeat value='&lt;txp:rah_repeat_value /&gt;' delimiter=&quot;|&quot;&gt;
  371. &lt;li&gt;&lt;txp:rah_repeat_value /&gt;&lt;/li&gt;
  372. &lt;/txp:rah_repeat&gt;
  373. &lt;/ul&gt;
  374. &lt;/txp:rah_repeat&gt;</code></pre>
  375. <p>Returns two <span class="caps">HTML</span> lists:</p>
  376. <pre><code>&lt;ul&gt;
  377. &lt;li&gt;group1&lt;/li&gt;
  378. &lt;li&gt;item1&lt;/li&gt;
  379. &lt;li&gt;item2&lt;/li&gt;
  380. &lt;/ul&gt;
  381. &lt;ul&gt;
  382. &lt;li&gt;group2&lt;/li&gt;
  383. &lt;li&gt;item1&lt;/li&gt;
  384. &lt;li&gt;item2&lt;/li&gt;
  385. &lt;/ul&gt;</code></pre>
  386. <h3>Basic usage of the if_first and the if_last tags</h3>
  387. <p>With the conditional tags <code>&lt;txp:rah_repeat_if_first /&gt;</code> and <code>&lt;txp:rah_repeat_if_last&gt;</code> we can test which value is the first and which is the last.</p>
  388. <pre><code>&lt;txp:rah_repeat value=&quot;item1, item2, item3, item4, item5&quot; wraptag=&quot;ul&quot; break=&quot;li&quot;&gt;
  389. &lt;txp:rah_repeat_if_first&gt;First: &lt;/txp:rah_repeat_if_first&gt;
  390. &lt;txp:rah_repeat_if_last&gt;Last: &lt;/txp:rah_repeat_if_last&gt;
  391. &lt;txp:rah_repeat_value /&gt;
  392. &lt;/txp:rah_repeat&gt;</code></pre>
  393. <p>Returns:</p>
  394. <pre><code>&lt;ul&gt;
  395. &lt;li&gt;First: item1&lt;/li&gt;
  396. &lt;li&gt;item2&lt;/li&gt;
  397. &lt;li&gt;item3&lt;/li&gt;
  398. &lt;li&gt;item4&lt;/li&gt;
  399. &lt;li&gt;Last: item5&lt;/li&gt;
  400. &lt;/ul&gt;</code></pre>
  401. <h3>Remove duplicate values</h3>
  402. <pre><code>&lt;txp:rah_repeat duplicates=&quot;1&quot; value=&quot;foo, bar, bar, foo, bar, bar, foo, foobar&quot;&gt;
  403. &lt;txp:rah_repeat_value /&gt;
  404. &lt;/txp:rah_repeat&gt;</code></pre>
  405. <p>Returns: <code>foo, bar, foobar</code></p>
  406. <h3>Arrange the values from lowest to highest</h3>
  407. <pre><code>&lt;txp:rah_repeat value=&quot;b, a, c&quot; sort=&quot;regular asc&quot;&gt;
  408. &lt;txp:rah_repeat_value /&gt;
  409. &lt;/txp:rah_repeat&gt;</code></pre>
  410. <p>Returns: <code>a, b, c</code></p>
  411. <h3>Excluding values</h3>
  412. <pre><code>&lt;txp:rah_repeat value=&quot;foo, bar, foobar&quot; exclude=&quot;foo, bar&quot;&gt;
  413. &lt;txp:rah_repeat_value /&gt;
  414. &lt;/txp:rah_repeat&gt;</code></pre>
  415. <p>Returns: <code>foobar</code></p>
  416. <h3>Using range attribute</h3>
  417. <p>With the <code>range</code> it&#8217;s possible to create a range of elements with out specifying each. For example generating list of alphabet (A-z) can be done with range.</p>
  418. <pre><code>&lt;txp:rah_repeat range=&quot;a, z, 1&quot;&gt;
  419. &lt;txp:rah_repeat_value /&gt;
  420. &lt;/txp:rah_repeat&gt;</code></pre>
  421. <p>Or listing number from 0 to 10.</p>
  422. <pre><code>&lt;txp:rah_repeat range=&quot;0, 10, 1&quot;&gt;
  423. &lt;txp:rah_repeat_value /&gt;
  424. &lt;/txp:rah_repeat&gt;</code></pre>
  425. <p>Or values <code>0</code>, <code>2</code>, <code>4</code>, and <code>6</code>.</p>
  426. <pre><code>&lt;txp:rah_repeat range=&quot;0, 6, 2&quot;&gt;
  427. &lt;txp:rah_repeat_value /&gt;
  428. &lt;/txp:rah_repeat&gt;</code></pre>
  429. <h3>Assign variables with assign attribute</h3>
  430. <p>The <code>assign</code> attribute allows exporting split values as <a href="http://textpattern.net/wiki/index.php?title=variable" rel="nofollow">variables</a>.</p>
  431. <pre><code>&lt;txp:rah_repeat value=&quot;JavaScript, jQuery, 1.8.0&quot; assign=&quot;language, framework, version&quot; /&gt;
  432. &lt;txp:variable name=&quot;language&quot; /&gt;
  433. &lt;txp:variable name=&quot;framework&quot; /&gt;
  434. &lt;txp:if_variable name=&quot;version&quot; value=&quot;1.8.0&quot;&gt;
  435. Version is 1.8.0.
  436. &lt;/txp:if_variable&gt;</code></pre>
  437. <h2>Changelog</h2>
  438. <h3>Version 1.0.1 &#8211; 2013/05/07</h3>
  439. <ul>
  440. <li>Composer package now uses <a href="https://packagist.org/packages/textpattern/lock" rel="nofollow">textpattern/lock</a> and <a href="https://packagist.org/packages/textpattern/installer" rel="nofollow">textpattern/installer</a>. The package installs to Textpattern without any extra configuration.</li>
  441. </ul>
  442. <h3>Version 1.0.0 &#8211; 2013/04/23</h3>
  443. <ul>
  444. <li>Fixed: Return a empty string instead of <span class="caps">NULL</span> byte on halt.</li>
  445. <li>Added: <code>form</code> attribute.</li>
  446. <li>Added: <code>index</code> attribute to the <code>rah_repeat_value</code> tag.</li>
  447. <li>Now requires Textpattern 4.5.0 or newer.</li>
  448. </ul>
  449. <h3>Version 0.8.1 &#8211; 2012/08/25</h3>
  450. <ul>
  451. <li>Fixed: <code>range</code> attribute. It ignored any options and always created an list of 1-10.</li>
  452. </ul>
  453. <h3>Version 0.8 &#8211; 2012/08/24</h3>
  454. <ul>
  455. <li>Fixed: made the <code>sort</code> attribute&#8217;s direction optional.</li>
  456. <li>Added: <code>exclude</code> can now take and exclude empty strings (<code>&quot;&quot;</code>) and zeros (<code>0</code>).</li>
  457. <li>Added: <code>range</code> attribute. Allows generating automated lists (<code>range=&quot;min, max, step&quot;</code>).</li>
  458. <li>Added: <code>assign</code> attribute. Allows extracting values as variables.</li>
  459. <li>Added: <code>escape</code> attribute to <code>&lt;txp:rah_repeat_value /&gt;</code>.</li>
  460. <li>Added: Support for natural ordering (<code>sort=&quot;natural&quot;</code>).</li>
  461. <li>Changed: Now <code>trim</code> is enabled by default. Previously values weren&#8217;t trimmed from white-space by default.</li>
  462. <li>Changed: Renamed <code>locale</code> sorting option to <code>LOCALE_STRING</code>.</li>
  463. <li>Changed: Order can be reversed with out re-sorting by using <code>sort=&quot;desc&quot;</code>.</li>
  464. <li>Now requires <span class="caps">PHP</span> 5.2 (or newer).</li>
  465. </ul>
  466. <h3>Version 0.7 &#8211; 2011/12/02</h3>
  467. <ul>
  468. <li>Added: <code>trim</code> attribute. When set to <code>1</code>, provided values are trimmed from surrounding whitespace.</li>
  469. <li>Fixed: locale sorting option. Previously it sorted values as a string, not by locale options.</li>
  470. <li>Changed: limit&#8217;s default to <span class="caps">NULL</span>. Leave limit unset if you only want offset without limit, or use a high value.</li>
  471. <li>Improved: Better offset and limit functionality. Now slices the list of values before staring to build the markup.</li>
  472. </ul>
  473. <h3>Version 0.6 &#8211; 2010/05/09</h3>
  474. <ul>
  475. <li>Added: <code>exclude</code> attribute.</li>
  476. <li>Fixed: <code>&lt;txp:rah_repeat_if_last&gt;</code> tag. Issue was caused by v0.5 update.</li>
  477. </ul>
  478. <h3>Version 0.5 &#8211; 2010/05/08</h3>
  479. <ul>
  480. <li>Changed offset&#8217;s default value from <code>unset</code> to <code>0</code>.</li>
  481. <li>Added: <code>sort</code> attribute.</li>
  482. <li>Added: <code>duplicates</code> attribute.</li>
  483. </ul>
  484. <h3>Version 0.4 &#8211; 2009/11/30</h3>
  485. <ul>
  486. <li>Fixed: now returns old parent global, if two tags are used inside each other, instead of defining it empty.</li>
  487. <li>Added: <code>&lt;txp:rah_repeat_if_first&gt;</code>.</li>
  488. <li>Added: <code>&lt;txp:rah_repeat_if_last&gt;</code>.</li>
  489. </ul>
  490. <h3>Version 0.3 &#8211; 2009/11/28</h3>
  491. <ul>
  492. <li>Added: <code>wraptag</code> attribute.</li>
  493. <li>Added: <code>break</code> attribute.</li>
  494. <li>Added: <code>class</code> attribute.</li>
  495. </ul>
  496. <h3>Version 0.2 &#8211; 2009/11/23</h3>
  497. <ul>
  498. <li>Added: <code>limit</code> attribute.</li>
  499. <li>Added: <code>offset</code> attribute.</li>
  500. </ul>
  501. <h3>Version 0.1 &#8211; 2009/11/20</h3>
  502. <ul>
  503. <li>Initial release.</li>
  504. </ul>
  505. # --- END PLUGIN HELP ---
  506. -->
  507. <?php
  508. }
  509. ?>