01127: Add a negation parameter to pagelist first/last templates

Summary: Add a negation parameter to pagelist first/last templates
Created: 2009-07-29 07:52
Status: Closed - added for 2.2.14
Category: Feature
Assigned:
Priority: 55
Version: 2.2.x
OS:

Description: Page list templates don't have an equivalent (:template ...:) markup for the expression (:if equal {=$Group} {<$Group}:), ie. all items except for the first in a group.

There does exist an expression for the first item in a group, (:template first {=$Group}:). Obviously its negation should be (:template ! first {=$Group}:), which is useful for example in cases where markup needs to be inserted between each item in a pagelist but not at the ends.

The diff below adds such a negation parameter ('!' or '-') for the (:template first/last:) and for (:template first/last {=$Group}:) directives.

===================================================================
--- scripts/pagelist.php	(revision 2389)
+++ scripts/pagelist.php	(working copy)
@@ -572,16 +572,16 @@
   $ttext = preg_replace('/\\[\\[#[A-Za-z][-.:\\w]*\\]\\]/', '', $ttext);

   ##  extract portions of template
-  $tparts = preg_split('/\\(:(template)\\s+(\\w+)\\s*(.*?):\\)/i', $ttext, -1,
-                       PREG_SPLIT_DELIM_CAPTURE);
+  $tparts = preg_split('/\\(:(template)\\s+([-!]?)\\s*(\\w+)\\s*(.*?):\\)/i',
+                       $ttext, -1, PREG_SPLIT_DELIM_CAPTURE);

   ##  handle (:template defaults:)
   $i = 0;
   while ($i < count($tparts)) {
     if ($tparts[$i] != 'template') { $i++; continue; }
-    if ($tparts[$i+1] != 'defaults' && $tparts[$i+1] != 'default') { $i+=4; continue; }
-    $opt = array_merge(ParseArgs($tparts[$i+2], $PageListArgPattern), $opt);
-    array_splice($tparts, $i, 3);
+    if ($tparts[$i+2] != 'defaults' && $tparts[$i+2] != 'default') { $i+=5; continue; }
+    $opt = array_merge(ParseArgs($tparts[$i+3], $PageListArgPattern), $opt);
+    array_splice($tparts, $i, 4);
   }

   SDVA($opt, array('class' => 'fpltemplate', 'wrap' => 'div'));
@@ -620,10 +620,10 @@
     while ($t < count($tparts)) {
       if ($tparts[$t] != 'template') { $item = $tparts[$t]; $t++; }
       else {
-        list($when, $control, $item) = array_slice($tparts, $t+1, 3); $t+=4;
+        list($neg, $when, $control, $item) = array_slice($tparts, $t+1, 4); $t+=5;
         if (!$control) {
-          if ($when == 'first' && $i != 0) continue;
-          if ($when == 'last' && $i != count($matches) - 1) continue;
+          if ($when == 'first' && ($neg xor ($i != 0))) continue;
+          if ($when == 'last' && ($neg xor ($i != count($matches) - 1))) continue;
         } else {
           if ($when == 'first' || !isset($last[$t])) {
             $Cursor['<'] = $Cursor['&lt;'] = (string)@$matches[$i-1];
@@ -632,7 +632,8 @@
             $curr = str_replace($vk, $vv, $control);
             $curr = preg_replace('/\\{(=|&[lg]t;)(\\$:?\\w+)\\}/e',
                         "PageVar(\$pn, '$2', '$1')", $curr);
-            if ($when == 'first' && $i > 0 && $last[$t] == $curr) continue;
+            if ($when == 'first' && ($neg xor (($i != 0) && ($last[$t] == $curr))))
+              { $last[$t] = $curr; continue; }
             $last[$t] = $curr;
           }
           if ($when == 'last') {
@@ -642,7 +643,7 @@
             $next = str_replace($vk, $vv, $control);
             $next = preg_replace('/\\{(=|&[lg]t;)(\\$:?\\w+)\\}/e',
                         "PageVar(\$pn, '$2', '$1')", $next);
-            if ($next == $last[$t] && $i != count($matches) - 1) continue;
+            if ($neg xor ($next == $last[$t] && $i != count($matches) - 1)) continue;
             $last[$t] = $next;
           }
         }

This looks good and I was about to add it to the core, but then I had a crazy idea. What if we add something like:

 (:template 1:)   == (:template first:)   first page
 (:template >1:)  == (:template ! first:) (suggested above)
 (:template >2:)  == third and next ones

 (:template -1:)  == (:template last:)    last page
 (:template <-1:) == (:template ! last:)  (suggested above)

But also

 (:template %2:)  == every second page (zebra tables, 2, 4, 6, 8, etc.)
 (:template %3 {=$Group}:)  == every third page from the group (3, 6, 9, etc.)

This would be quite a change to the script though. I am not sure it is a good idea. There is one benefit of using "1" instead of "first", for international users. Comments welcome. --Petko August 23, 2009, at 09:58 AM

Using numerals instead of words would make sense from a non-english perspective, but the word arguments shouldn't stop working if the change is made. Also, has someone actually asked for this? I mean, isn't this a bit of a case of creeping featurism, and in any case deserving of its own PITS entry if you feel like going forward with this?

For a second point, is there really a need for '>2' or '%3'? Zebra tables could indeed be useful, but the more complex options sound a bit unlikely to me. Regarding zebra tables, the (to me) obvious way to express them would be (:template odd:) and/or (:template even:). —Eemeli Aro August 25, 2009, at 03:22 AM

I really like this idea. When balancing up simplicity and complexity I tend to go for ideas that are simply to understand, but add power. I find that it is surprising what innovative uses can be made once such features are available. simon August 23, 2009, at 04:32 PM

Testing...

[[#tpl]]
(:template first:)
* {$$PageCount}. FIRST item : {=$:Summary}
(:template ! first:)
* {$$PageCount}. NON FIRST item : {=$:Summary}
[[#tplend]]

(:template first:)

  • {$$PageCount}. FIRST item : {=$:Summary}

(:template ! first:)

  • {$$PageCount}. NON FIRST item : {=$:Summary}

(:pagelist trail=RecentChanges count=5 fmt=#tpl:)
  • 1. FIRST item : make release software tree "no-need-to-touch"
  • 2. NON FIRST item : Configurable <title> format in responsive skin
  • 3. NON FIRST item : no TOC
  • 4. NON FIRST item : Markup Expression number_format
  • 5. NON FIRST item :