Add address list pagination, 'Compose To' button, more labels for checkboxes, hook...
authorpdontthink <pdontthink@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Thu, 22 May 2008 01:19:00 +0000 (01:19 +0000)
committerpdontthink <pdontthink@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Thu, 22 May 2008 01:19:00 +0000 (01:19 +0000)
git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@13160 7612ce4b-ef26-0410-bec9-ea0150e637f0

ChangeLog
functions/addressbook.php
functions/template/abook_util.php
include/load_prefs.php
include/options/display.php
src/addressbook.php
templates/default/addressbook_list.tpl
templates/default/addressbook_paginator.tpl [new file with mode: 0644]
templates/default/css/default.css

index 9246d80..a9e9f43 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -248,6 +248,11 @@ Version 1.5.2 - SVN
     default_pref file next to hardcoding them into the DB class, thanks
     Thierry Godefroy.
   - Reimplement printer friendly to make use of CSS.
+  - Enhanced address book page: added address list pagination, added
+    'Compose to' button, put labels around address entries tied to
+    checkboxes, added hook and template plugin output sections for
+    plugins that can filter address book listings and modify the abook
+    navigation bar.  Complements RisuMail team (risumail.jp).
 
 Version 1.5.1 (branched on 2006-02-12)
 --------------------------------------
index 36edcb0..a802c03 100644 (file)
@@ -363,9 +363,8 @@ function show_abook_sort_button($abook_sort_order, $alt_tag,
         $which = 8;
     }
 
-    $uri = $form_url .'?abook_sort_order=' . $which;
-    foreach ($uri_extra as $key => $value)
-       $uri = set_url_var($uri, $key, $value, FALSE);
+    $uri_extra['abook_sort_order'] = $which;
+    $uri = set_uri_vars($form_url, $uri_extra, FALSE);
 
     /* Now that we have everything figured out, show the actual button. */
     return create_hyperlink($uri,
index 53bfb40..55d55c1 100644 (file)
 
 
 /**
- * Display a column header with sort buttons
- *
- * @param string $field   Which field to display
- * @param int    $backend The abook backend to be shown when
- *                        sort link is clicked
- *
- * @author Steve Brown
- * @since 1.5.2
- */
-function addAbookSort ($field, $backend) {
+  * Display a column header with sort buttons
+  *
+  * @param string $field             Which field to display
+  * @param array  $current_page_args All known query string arguments
+  *                                  for the current page request; structured
+  *                                  as an associative array of key/value pairs
+  *
+  * @author Steve Brown
+  * @since 1.5.2
+  */
+function addAbookSort ($field, $current_page_args) {
     global $abook_sort_order, $nbsp;
 
     switch ($field) {
@@ -60,7 +61,252 @@ function addAbookSort ($field, $backend) {
     }
 
     // show_abook_sort_button() creates a hyperlink (using hyperlink.tpl) that encompases an image, using a getImage() call
-    return $str . ($has_sort ? $nbsp . show_abook_sort_button($abook_sort_order, $alt, $down, $up, array('new_bnum' => $backend)) : '');
+    return $str . ($has_sort ? $nbsp . show_abook_sort_button($abook_sort_order, $alt, $down, $up, $current_page_args) : '');
+}
+
+
+/**
+  * Creates an address book paginator
+  *
+  * @param boolean $abook_page_selector     Whether or not to show the page selector
+  * @param int     $abook_page_selector_max The maximum number of page links to show
+  *                                         on screen
+  * @param int     $page_number             What page is being viewed - 0 if not used
+  * @param int     $page_size               Maximum number of addresses to be shown
+  *                                         per page
+  * @param int     $total_addresses         The total count of addresses in the backend
+  * @param boolean $show_all                Whether or not all addresses are being shown
+  * @param array  $current_page_args        All known query string arguments
+  *                                         for the current page request; structured
+  *                                         as an associative array of key/value pairs
+  * @param boolean $compact                 Whether or not to build a smaller, 
+  *                                         "compact" paginator
+  *
+  * @return string The paginator, ready for output
+  *
+  */
+function get_abook_paginator($abook_page_selector, $abook_page_selector_max,
+                             $page_number, $page_size, $total_addresses,
+                             $show_all, $current_page_args, $compact) {
+
+    // if showing all, just show pagination link
+    //
+    if ($show_all)
+    {
+        unset($current_page_args['show_all']);
+        return '[' . make_abook_paginator_link(1, _("Paginate"), $current_page_args) . ']';
+    }
+
+
+    // if we don't have enough information to build the paginator, return nothing
+    //
+    if (empty($page_number) || empty($page_size) || empty($total_addresses))
+        return '';
+
+
+    // calculate some values we need below
+    //
+    $show_elipses_before = FALSE;
+    $show_elipses_after = FALSE;
+    global $nbsp;
+    $sep = '|';
+    $paginator_string = '[';
+    $total_pages = ceil($total_addresses / $page_size);
+    if ($page_number > $total_pages) $page_number = $total_pages;
+    $spacing = ($compact ? $nbsp : $nbsp . $nbsp);
+
+
+    // only enough addresses for one page anyway?  no pagination needed
+    //
+    if ($total_pages < 2) return '';
+
+
+    // build "Show All" link
+    //
+    $show_all_string = '['
+                     . make_abook_paginator_link(1, _("Show All"), 
+                                                 array_merge($current_page_args, array('show_all' => 1)))
+                     . ']';
+
+
+    // build next/previous links for compact paginator
+    //
+    if ($compact)
+    {
+        if ($page_number > 1)
+            $paginator_string .= make_abook_paginator_link(1,
+                                                           _("<<"),
+                                                           $current_page_args)
+                               . ']['
+                               . make_abook_paginator_link($page_number - 1,
+                                                           _("<"),
+                                                           $current_page_args)
+                               . '][';
+        else
+            $paginator_string .= _("<<") . '][' . _("<") . '][';
+        if ($page_number < $total_pages)
+            $paginator_string .= make_abook_paginator_link($page_number + 1,
+                                                           _(">"),
+                                                           $current_page_args)
+                               . ']['
+                               . make_abook_paginator_link($total_pages,
+                                                           _(">>"),
+                                                           $current_page_args)
+                               . ']';
+        else
+            $paginator_string .= _(">") . '][' . _(">>") . ']';
+    }
+
+
+    // build next/previous links for regular paginator
+    //
+    else
+    {
+        if ($page_number > 1)
+            $paginator_string .= make_abook_paginator_link($page_number - 1,
+                                                           _("Previous"),
+                                                           $current_page_args);
+        else
+            $paginator_string .= _("Previous");
+        $paginator_string .= $nbsp . $sep . $nbsp;
+        if ($page_number < $total_pages)
+            $paginator_string .= make_abook_paginator_link($page_number + 1,
+                                                           _("Next"),
+                                                           $current_page_args);
+        else
+            $paginator_string .= _("Next");
+        $paginator_string .= ']';
+    }
+
+
+    // paginator is turned off - just show previous/next links
+    //
+    if (!$abook_page_selector)
+    {
+        return $paginator_string . $spacing . $show_all_string;
+    }
+
+
+    $paginator_string .= $spacing;
+
+
+    if ($total_pages <= $abook_page_selector_max)
+    {
+        $start_page = 1;
+        $end_page = $total_pages;
+    }
+    else
+    {
+        $pages_to_show = ($abook_page_selector_max % 2 ? $abook_page_selector_max : $abook_page_selector_max - 1);
+        $end_page = $page_number + floor($pages_to_show / 2);
+        $start_page = $page_number - floor($pages_to_show / 2);
+        if (!($abook_page_selector_max % 2)) $start_page--;
+
+        if ($start_page < 1)
+        {
+            $end_page += 1 - $start_page;
+            $start_page = 1;
+        }
+        else if ($end_page > $total_pages)
+        {
+            $start_page -= $end_page - $total_pages;
+            $end_page = $total_pages;
+        }
+
+
+        // do we need to insert elipses?
+        //
+        if (1 < $start_page)
+        {
+            $start_page++;
+            $show_elipses_before = TRUE;
+        }
+        if ($total_pages > $end_page)
+        {
+            $end_page--;
+            $show_elipses_after = TRUE;
+        }
+    }
+
+
+    // now build the actual (compact) paginator
+    //
+    if ($compact)
+    {
+        $aValues = array();
+        for ($i = 1; $i <= $total_pages; $i++)
+            $aValues[$i] = $i . '/' . $total_pages;
+        $page_uri = sqm_baseuri() . 'src/addressbook.php';
+        $temp_page_number = $current_page_args['page_number'];
+        unset($current_page_args['page_number']);
+        $page_uri = set_uri_vars($page_uri, array_diff($current_page_args, array('page_number' => 0)), FALSE);
+        $current_page_args['page_number'] = $temp_page_number;
+        $paginator_string .= addSelect('page_number', $aValues,
+                                       $page_number, TRUE,
+                                       (checkForJavascript()
+                                        ? array('onchange' => 'SubmitOnSelect(this, \''
+                                                                                  . $page_uri
+                                                                                  . '&page_number='
+                                                                                  . '\')')
+                                        : array()));
+
+        // need a submit button when select widget cannot submit itself
+        //
+        if (!checkForJavascript())
+        {
+            $paginator_string .= addSubmit(_("Go"), 'paginator_submit');
+        }
+    }
+
+
+    // now build the actual (regular) paginator
+    //
+    else
+    {
+        $paginator_string .= '[' . $nbsp;
+        if ($show_elipses_before)
+            $paginator_string .= make_abook_paginator_link(1, 1, $current_page_args)
+                            . $nbsp . '...' . $nbsp;
+        for ($x = $start_page; $x <= $end_page; $x++)
+        {
+            if ($x == $page_number)
+                $paginator_string .= $x . $nbsp;
+            else
+                $paginator_string .= make_abook_paginator_link($x, $x, $current_page_args) . $nbsp;
+        }
+        if ($show_elipses_after)
+            $paginator_string .= '...' . $nbsp
+                              . make_abook_paginator_link($total_pages, $total_pages, $current_page_args)
+                              . $nbsp;
+        $paginator_string .= ']';
+    }
+    $paginator_string .= $spacing . $show_all_string;
+
+
+    return $paginator_string;
+
+}
+
+
+/**
+  * Build a page (pagination) link for use with the address book list page
+  *
+  * @param int    $page_number       The page number for the link
+  * @param string $text              The link text
+  * @param array  $current_page_args All known query string arguments
+  *                                  for the current page request; structured
+  *                                  as an associative array of key/value pairs
+  *
+  */
+function make_abook_paginator_link($page_number, $text, $current_page_args) {
+
+    $uri = sqm_baseuri() . 'src/addressbook.php';
+
+    $current_page_args['page_number'] = $page_number;
+    $uri = set_uri_vars($uri, $current_page_args, FALSE);
+
+    return create_hyperlink($uri, $text);
+
 }
 
 
index c3d5f56..65fc273 100644 (file)
@@ -278,6 +278,12 @@ $page_selector = getPref($data_dir, $username, 'page_selector', SMPREF_ON);
 $compact_paginator = getPref($data_dir, $username, 'compact_paginator', SMPREF_OFF);
 $page_selector_max = getPref($data_dir, $username, 'page_selector_max', 10);
 
+/* Abook page selector options */
+$abook_show_num = getPref($data_dir, $username, 'abook_show_num', 15 );
+$abook_page_selector = getPref($data_dir, $username, 'abook_page_selector', SMPREF_ON);
+$abook_compact_paginator = getPref($data_dir, $username, 'abook_compact_paginator', SMPREF_OFF);
+$abook_page_selector_max = getPref($data_dir, $username, 'abook_page_selector_max', 5);
+
 /* SqClock now in the core */
 $date_format = getPref($data_dir, $username, 'date_format', 3);
 $hour_format = getPref($data_dir, $username, 'hour_format', SMPREF_TIME_12HR);
index 4ba3945..ef7d266 100644 (file)
@@ -15,6 +15,7 @@
 define('SMOPT_GRP_GENERAL', 0);
 define('SMOPT_GRP_MAILBOX', 1);
 define('SMOPT_GRP_MESSAGE', 2);
+define('SMOPT_GRP_ABOOK', 3);
 
 global $use_iframe;
 if (! isset($use_iframe)) $use_iframe=false;
@@ -400,6 +401,44 @@ FIXME!
         'refresh' => SMOPT_REFRESH_ALL
     );
 
+
+
+    /*** Load the Address Book Options into the array ***/
+    $optgrps[SMOPT_GRP_ABOOK] = _("Address Book Display Options");
+    $optvals[SMOPT_GRP_ABOOK] = array();
+
+    $optvals[SMOPT_GRP_ABOOK][] = array(
+        'name'    => 'abook_show_num',
+        'caption' => _("Number of Addresses per Page"),
+        'type'    => SMOPT_TYPE_INTEGER,
+        'refresh' => SMOPT_REFRESH_NONE,
+        'size'    => SMOPT_SIZE_TINY
+    );
+
+    $optvals[SMOPT_GRP_ABOOK][] = array(
+        'name'    => 'abook_page_selector',
+        'caption' => _("Enable Page Selector"),
+        'type'    => SMOPT_TYPE_BOOLEAN,
+        'refresh' => SMOPT_REFRESH_NONE
+    );
+
+    $optvals[SMOPT_GRP_ABOOK][] = array(
+        'name'    => 'abook_compact_paginator',
+        'caption' => _("Use Compact Page Selector"),
+        'type'    => SMOPT_TYPE_BOOLEAN,
+        'refresh' => SMOPT_REFRESH_NONE
+    );
+
+    $optvals[SMOPT_GRP_ABOOK][] = array(
+        'name'    => 'abook_page_selector_max',
+        'caption' => _("Maximum Number of Pages to Show"),
+        'type'    => SMOPT_TYPE_INTEGER,
+        'refresh' => SMOPT_REFRESH_NONE,
+        'size'    => SMOPT_SIZE_TINY
+    );
+
+
+
     /* Assemble all this together and return it as our result. */
     $result = array(
         'grps' => $optgrps,
index 6daf3fd..214a6f8 100644 (file)
@@ -39,6 +39,12 @@ sqgetGlobalVar('sel',           $sel,           SQ_POST);
 sqgetGlobalVar('oldnick',       $oldnick,       SQ_POST);
 sqgetGlobalVar('backend',       $backend,       SQ_POST);
 sqgetGlobalVar('doedit',        $doedit,        SQ_POST);
+$page_size = $abook_show_num;
+if (!sqGetGlobalVar('page_number', $page_number, SQ_FORM))
+    if (!sqGetGlobalVar('current_page_number', $page_number, SQ_FORM))
+        $page_number = 1;
+if (!sqGetGlobalVar('show_all', $show_all, SQ_FORM))
+    $show_all = 0;
 
 /* Get sorting order */
 $abook_sort_order = get_abook_sort();
@@ -51,7 +57,7 @@ displayPageHeader($color);
 */
 $abook = addressbook_init(true, false);
 
-// FIXME: do we have to stop use of address book, when localbackend is not present.
+// FIXME: do we really have to stop use of address book when localbackend is not present?
 if($abook->localbackend == 0) {
     plain_error_message(_("No personal address book is defined. Contact administrator."));
     exit();
@@ -268,6 +274,7 @@ if(sqgetGlobalVar('REQUEST_METHOD', $req_method, SQ_SERVER) && $req_method == 'P
 
     // Some times we end output before forms are printed
     if($abortform) {
+//FIXME: use footer.tpl; remove HTML from core
         echo "</body></html>\n";
         exit();
     }
@@ -294,38 +301,120 @@ while (list($k, $backend) = each ($abook->backends)) {
     $a['BackendWritable'] = $backend->writeable;
     $a['Addresses'] = array();
 
-    $alist = $abook->list_addr($backend->bnum);
+    // don't do address lookup if we are not viewing that backend
+    //
+    if ($backend->bnum == $current_backend) {
+        $alist = $abook->list_addr($backend->bnum);
 
-    /* check return (array with data or boolean false) */
-    if (is_array($alist)) {
-        usort($alist,'alistcmp');
-
-        $a['Addresses'] = formatAddressList($alist);
+        /* check return (array with data or boolean false) */
+        if (is_array($alist)) {
+            usort($alist,'alistcmp');
+    
+            $a['Addresses'] = formatAddressList($alist);
   
-        $addresses[$backend->bnum] = $a;
+            $addresses[$backend->bnum] = $a;
+        } else {
+            // list_addr() returns boolean
+            plain_error_message(nl2br(htmlspecialchars($abook->error)));
+        }
     } else {
-        // list_addr() returns boolean
-        plain_error_message(nl2br(htmlspecialchars($abook->error)));
+        $addresses[$backend->bnum] = $a;
+    }
+}
+
+
+$current_page_args = array(
+                           'abook_sort_order' => $abook_sort_order,
+                           'new_bnum'         => $current_backend,
+                           'page_number'      => $page_number,
+                          );
+
+
+// note that plugins can add to $current_page_args as well as
+// filter the address list
+//
+$temp = array(&$addresses, &$current_backend, &$page_number, &$current_page_args);
+do_hook('abook_list_filter', $temp);
+
+
+// NOTE to address book backend authors and plugin authors: if a backend does
+//      pagination (which might be more efficient), it needs to place a key
+//      in every address listing it returns called "paginated", whose value
+//      should evaluate to boolean TRUE.  However, if a plugin will also be
+//      used on the hook above to filter the addresses (perhaps by group), then
+//      the backend should be made compatible with the filtering plugin and
+//      should do the actual filtering too.  Otherwise, the backend will paginate
+//      before filtering has taken place, the output of which is clearly wrong.
+//      It is proposed that filtering be based on a GET/POST variable called
+//      "abook_groups_X" where X is the current backend number.  The value of
+//      this varaible would be an array of possible filter names, which the
+//      plugin and the backend would both know about.  The plugin would only
+//      filter based on that value if the backend didn't already do it.  The
+//      backend can insert a "grouped" key into all address listings, whose
+//      value evaluates to boolean TRUE, telling the plugin not to do any
+//      filtering itself.  For an example of this implementation, see the
+//      Address Book Grouping and Pagination plugin.
+
+
+// if no pagination was done by a plugin or the abook
+// backend (which is indicated by the presence of a
+// "paginated" key within all of the address entries
+// in the list of addresses for the backend currently
+// being viewed), then we provide default pagination
+//
+$total_addresses = 0;
+if (!$show_all
+ && is_array($addresses[$current_backend]['Addresses'])
+ && empty($addresses[$current_backend]['Addresses'][0]['paginated'])) {
+
+    // at this point, we assume the current list is
+    // the *full* list
+    //
+    $total_addresses = sizeof($addresses[$current_backend]['Addresses']);
+
+    // iterate through all the entries, building list of addresses
+    // to keep based on current page
+    //
+    $new_address_list = array();
+    $total_pages = ceil($total_addresses / $page_size);
+    if ($page_number > $total_pages) $page_number = $total_pages;
+    $page_count = 1;
+    $page_item_count = 0;
+    foreach ($addresses[$current_backend]['Addresses'] as $addr) {
+        $page_item_count++;
+        if ($page_item_count > $page_size) {
+            $page_count++;
+            $page_item_count = 1;
+        }
+        if ($page_count == $page_number)
+            $new_address_list[] = $addr;
     }
+    $addresses[$current_backend]['Addresses'] = $new_address_list;
+
 }
 
 
 if ($showaddrlist) {
-//FIXME: Remove HTML from here!
-    echo addForm($form_url, 'post', 'address_book_form');
     
-    $oTemplate->assign('compose_new_win', $compose_new_win);
-    $oTemplate->assign('compose_height', $compose_height);
-    $oTemplate->assign('compose_width', $compose_width);
+    $oTemplate->assign('show_all', $show_all);
+    $oTemplate->assign('page_number', $page_number);
+    $oTemplate->assign('page_size', $page_size);
+    $oTemplate->assign('total_addresses', $total_addresses);
+    $oTemplate->assign('abook_compact_paginator', $abook_compact_paginator);
+    $oTemplate->assign('abook_page_selector', $abook_page_selector);
+    $oTemplate->assign('current_page_args', $current_page_args);
+    $oTemplate->assign('abook_page_selector_max', $abook_page_selector_max);
     $oTemplate->assign('addresses', $addresses);
     $oTemplate->assign('current_backend', $current_backend);
     $oTemplate->assign('backends', $list_backends);
     $oTemplate->assign('abook_has_extra_field', $abook->add_extra_field);
+    $oTemplate->assign('compose_new_win', $compose_new_win);
+    $oTemplate->assign('compose_height', $compose_height);
+    $oTemplate->assign('compose_width', $compose_width);
+    $oTemplate->assign('form_action', $form_url);
         
     $oTemplate->display('addressbook_list.tpl');
     
-//FIXME: Remove HTML from here!
-    echo "</form>\n";
 }
 
 /* Display the "new address" form */
index 1da30ad..121d753 100644 (file)
@@ -1,50 +1,58 @@
 <?php
+
 /**
- * addressbook_list.tpl
- *
- * Template for the basic address book list
- * 
- * The following variables are available in this template:
- *      $compose_new_win - whether or not the user prefs are set to compose
- *                         messages in a popup window
- *      $compose_width   - width of popup compose window if needed
- *      $compose_height  - height of popup compose window if needed
- *      $current_backend - integer containing backend currently displayed.
- *      $abook_select    - string containing HTML to display the address book
- *                         selection drop down
- *      $abook_has_extra_field - boolean TRUE if the address book contains an
- *                         additional field.  FALSE otherwise.
- *      $backends        - array containing all available backends for selection.
- *                         This will be empty if only 1 backend is available! 
- *      $addresses - array of backends in the address book.  Each element
- *                   is an array containing the following fields:
- *          ['BackendID']       - integer unique identifier for each source of 
- *                                addresses in the book.  this should also be
- *                                the same as the array key for this value
- *          ['BackendSource']   - description of each source of addresses
- *          ['BackendWritable'] - boolean TRUE if the address book can be
- *                                modified.  FALSE otherwise.
- *          ['Addresses']       - array containing address from this source.
- *                                Each array element contains the following:
- *                       ['FirstName']   - The entry's first name
- *                       ['LastName']    - The entry's last name (surname)
- *                       ['FullName']    - The entry's full name (first + last)
- *                       ['NickName']    - The entry's nickname
- *                       ['Email']       - duh
- *                       ['FullAddress'] - Email with full name or nick name
- *                                         optionally prepended.
- *                       ['Info']        - Additional info about this contact
- *                       ['Extra']       - Additional field, if provided.  NULL if
- *                                         this field is not provided by the book.
- *                       ['JSEmail']     - email address scrubbed for use with
- *                                         javascript functions.
- *
- * @copyright &copy; 1999-2006 The SquirrelMail Project Team
- * @license http://opensource.org/licenses/gpl-license.php GNU Public License
- * @version $Id$
- * @package squirrelmail
- * @subpackage templates
- */
+  * addressbook_list.tpl
+  *
+  * Template for the basic address book list
+  * 
+  * The following variables are available in this template:
+  *
+  * string  $form_action       The action for the main form tag
+  * array   $current_page_args All known query string arguments for the
+  *                            current page request, for use when constructing
+  *                            links pointing back to same page (possibly
+  *                            changing one of them); structured as an
+  *                            associative array of key/value pairs
+  * boolean $compose_new_win   Whether or not the user prefs are set to compose
+  *                            messages in a popup window
+  * int     $compose_width     Width of popup compose window if needed
+  * int     $compose_height    Height of popup compose window if needed
+  * int     $current_backend   Number of backend currently displayed.
+  * string  $abook_select      Code for widget to display the address book
+  *                            backend selection drop down
+  * boolean $abook_has_extra_field TRUE if the address book contains an
+  *                                additional field.  FALSE otherwise.
+  * array   $backends          Contains all available abook backends for selection.
+  *                            This will be empty if only 1 backend is available! 
+  * array   $addresses         Contains backends in the address book.  Each element
+  *                            is an array containing the following fields:
+  *          ['BackendID']       - integer unique identifier for each source of 
+  *                                addresses in the book.  this should also be
+  *                                the same as the array key for this value
+  *          ['BackendSource']   - description of each source of addresses
+  *          ['BackendWritable'] - boolean TRUE if the address book can be
+  *                                modified.  FALSE otherwise.
+  *          ['Addresses']       - array containing address from this source.
+  *                                Each array element contains the following:
+  *                       ['FirstName']   - The entry's first name
+  *                       ['LastName']    - The entry's last name (surname)
+  *                       ['FullName']    - The entry's full name (first + last)
+  *                       ['NickName']    - The entry's nickname
+  *                       ['Email']       - duh
+  *                       ['FullAddress'] - Email with full name or nick name
+  *                                         optionally prepended.
+  *                       ['Info']        - Additional info about this contact
+  *                       ['Extra']       - Additional field, if provided.  NULL if
+  *                                         this field is not provided by the book.
+  *                       ['JSEmail']     - email address scrubbed for use with
+  *                                         javascript functions.
+  *
+  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
+  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+  * @version $Id$
+  * @package squirrelmail
+  * @subpackage templates
+  */
 
 /** add required includes **/
 include_once(SM_PATH . 'functions/template/abook_util.php');
@@ -56,6 +64,7 @@ extract($t);
 $source = $addresses[$current_backend];
 $colspan = $abook_has_extra_field ? 6 : 5;
 ?>
+<form action="<?php echo $form_action; ?>" method="post" id="address_book_form" name="address_book_form">
 <div id="addressList">
 <table cellspacing="0">
  <tr>
@@ -64,13 +73,21 @@ $colspan = $abook_has_extra_field ? 6 : 5;
   </td>
  </tr>
  <tr>
-  <td colspan="3" class="abookButtons">
-   <input type="submit" value="<?php echo _("Edit Selected"); ?>" name="editaddr" id="editaddr" />
-   <input type="submit" value="<?php echo _("Delete Selected"); ?>" name="deladdr" id="deladdr" />
-   <input type="submit" value="<?php echo _("Compose to Selected") . ($javascript_on && $compose_new_win ? '" onclick="var send_to = \'\'; var f = document.forms.length; var i = 0; var grab_next_hidden = \'\'; while (i < f) { var e = document.forms[i].elements.length; var j = 0; while (j < e) { if (document.forms[i].elements[j].type == \'checkbox\' && document.forms[i].elements[j].checked) { var pos = document.forms[i].elements[j].value.indexOf(\'_\'); if (pos >= 1) { grab_next_hidden = document.forms[i].elements[j].value; } } else if (document.forms[i].elements[j].type == \'hidden\' && grab_next_hidden == document.forms[i].elements[j].name) { if (send_to != \'\') { send_to += \', \'; } send_to += document.forms[i].elements[j].value; } j++; } i++; } if (send_to != \'\') { comp_in_new(\''. $base_uri . 'src/compose.php?send_to=\' + send_to, ' . $compose_width . ', ' . $compose_height . '); } return false;"' : '"'); ?> name="compose_to" id="compose_to" />
-   <?php if (!empty($plugin_output['address_book_navigation'])) echo $plugin_output['address_book_navigation']; ?>
+  <td colspan="3" class="abookPaginationAndButtons">
+    <div class="abookPagination">
+      <?php
+          $this->display('addressbook_paginator.tpl');
+          if (!empty($plugin_output['address_book_navigation'])) echo $plugin_output['address_book_navigation'];
+      ?>
+    </div><div class="abookButtons">
+      <input type="submit" value="<?php echo _("Edit Selected"); ?>" name="editaddr" id="editaddr" />
+      <input type="submit" value="<?php echo _("Delete Selected"); ?>" name="deladdr" id="deladdr" />
+      <input type="submit" value="<?php echo /*FIXME: save space?  yes?  no? _("Compose to Selected")*/_("Compose To") . ($javascript_on && $compose_new_win ? '" onclick="var send_to = \'\'; var f = document.forms.length; var i = 0; var grab_next_hidden = \'\'; while (i < f) { var e = document.forms[i].elements.length; var j = 0; while (j < e) { if (document.forms[i].elements[j].type == \'checkbox\' && document.forms[i].elements[j].checked) { var pos = document.forms[i].elements[j].value.indexOf(\'_\'); if (pos >= 1) { grab_next_hidden = document.forms[i].elements[j].value; } } else if (document.forms[i].elements[j].type == \'hidden\' && grab_next_hidden == document.forms[i].elements[j].name) { if (send_to != \'\') { send_to += \', \'; } send_to += document.forms[i].elements[j].value; } j++; } i++; } if (send_to != \'\') { comp_in_new(\''. $base_uri . 'src/compose.php?send_to=\' + send_to, ' . $compose_width . ', ' . $compose_height . '); } return false;"' : '"'); ?> name="compose_to" id="compose_to" />
+      <?php if (!empty($plugin_output['address_book_buttons'])) echo $plugin_output['address_book_buttons']; ?>
+    </div>
   </td>
   <td colspan="<?php echo ($colspan - 3); ?>" class="abookSwitch">
+   <?php if (!empty($plugin_output['address_book_filter'])) echo $plugin_output['address_book_filter']; ?>
    <?php
     if (count($backends) > 0) {
         ?>
@@ -91,10 +108,10 @@ $colspan = $abook_has_extra_field ? 6 : 5;
  </tr>
  <tr>
   <td class="colHeader" style="width:1%"><input type="checkbox" name="toggleAll" id="toggleAll" title="<?php echo _("Toggle All"); ?>" onclick="toggle_all('address_book_form', 'sel', false); return false;" /></td>
-  <td class="colHeader" style="width:15%"><?php echo addAbookSort('nickname', $current_backend); ?></td>
-  <td class="colHeader"><?php echo addAbookSort('fullname', $current_backend); ?></td>
-  <td class="colHeader"><?php echo addAbookSort('email', $current_backend); ?></td>
-  <td class="colHeader"><?php echo addAbookSort('info', $current_backend); ?></td>
+  <td class="colHeader" style="width:15%"><?php echo addAbookSort('nickname', $current_page_args); ?></td>
+  <td class="colHeader"><?php echo addAbookSort('fullname', $current_page_args); ?></td>
+  <td class="colHeader"><?php echo addAbookSort('email', $current_page_args); ?></td>
+  <td class="colHeader"><?php echo addAbookSort('info', $current_page_args); ?></td>
   <?php
    if ($abook_has_extra_field) {
     echo '<td class="colHeader"></td>';
@@ -107,17 +124,21 @@ $colspan = $abook_has_extra_field ? 6 : 5;
         echo '<tr><td class="abookEmpty" colspan="'.$colspan.'">'._("Address book is empty").'</td></tr>'."\n";
     }
     foreach ($source['Addresses'] as $contact) {
-        $id = $current_backend . '_' . $contact['NickName'];
-        ?>
- <tr class="<?php echo ($count%2 ? 'even' : 'odd'); ?>">
+        echo '<tr class="' . ($count%2 ? 'even' : 'odd') . '">';
+        if (!empty($contact['special_message'])) {
+            echo '<td class="abookEmpty" colspan="' . $colspan . '">' . $contact['special_message'] . '</td>';
+        } else {
+            $id = $current_backend . '_' . $contact['NickName'];
+            ?>
   <td class="abookField" style="width:1%"><?php echo ($source['BackendWritable'] ? '<input type="checkbox" name="sel[' . $count . ']" value="'.$id.'" id="'.$id.'" ' . (!empty($plugin_output['address_book_checkbox_extra']) ? $plugin_output['address_book_checkbox_extra'] : '') . ' />' : ''); ?></td>
   <td class="abookField" style="width:15%"><label for="<?php echo $id . '">' . $contact['NickName']; ?></label></td>
   <td class="abookField"><label for="<?php echo $id . '">' . $contact['FullName']; ?></label></td>
   <td class="abookField"><input type="hidden" name="<?php echo $id; ?>" value="<?php echo rawurlencode($contact['FullAddress']); ?>" /><?php echo composeLink($contact); ?></td>
   <td class="abookField"><label for="<?php echo $id . '">' . $contact['Info']; ?></label></td>
         <?php 
-        if ($abook_has_extra_field) {
-            echo '<td class="abookField">'.$contact['Extra'].'</td>'."\n";
+            if ($abook_has_extra_field) {
+                echo '<td class="abookField">'.$contact['Extra'].'</td>'."\n";
+            }
         }
         ?>
  </tr>
@@ -127,3 +148,4 @@ $colspan = $abook_has_extra_field ? 6 : 5;
 ?>
 </table>
 </div>
+</form>
diff --git a/templates/default/addressbook_paginator.tpl b/templates/default/addressbook_paginator.tpl
new file mode 100644 (file)
index 0000000..c1c167f
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+/**
+  * addressbook_paginator.tpl
+  *
+  * Template to create an address book list paginator
+  * 
+  * The following variables are available in this template:
+  * 
+  * boolean $abook_compact_paginator Whether or not to show smaller paginator
+  * boolean $abook_page_selector     Whether or not to use the paginator
+  * int     $abook_page_selector_max How many page links to show on screen
+  *                                  in the non-compact paginator format
+  * int     $page_number             What page is being viewed - 0 if not used
+  * int     $page_size               Maximum number of addresses to be shown
+  *                                  per page
+  * int     $total_addresses         The total count of addresses in the backend
+  * boolean $show_all                Whether or not all addresses are being shown
+  * boolean $abook_compact_paginator Whether or not pagination should be shown
+  *                                  using the smaller, "compact" paginator
+  * array   $current_page_args       All known query string arguments for the
+  *                                  current page request, for use when constructing
+  *                                  links pointing back to same page (possibly
+  *                                  changing one of them); structured as an
+  *                                  associative array of key/value pairs
+  *
+  * @copyright &copy; 1999-2008 The SquirrelMail Project Team
+  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+  * @version $Id: addressbook_list.tpl 13146 2008-05-15 19:00:03Z pdontthink $
+  * @package squirrelmail
+  * @subpackage templates
+  */
+
+/** add required includes **/
+include_once(SM_PATH . 'functions/template/abook_util.php');
+
+static $bAlreadyExecuted;
+
+/** extract template variables **/
+extract($t);
+
+/** Begin template **/
+
+if (!isset($bAlreadyExecuted)) {
+    $bAlreadyExecuted = true;
+    ?><input type="hidden" name="current_page_number" value="<?php echo $page_number; ?>" /><?php
+
+    if ($javascript_on && $abook_compact_paginator) {
+?>
+
+<!-- start of compact paginator javascript -->
+<script type="text/javascript">
+    function SubmitOnSelect(select, URL)
+    {
+        URL += select.options[select.selectedIndex].value;
+        window.location.href = URL;
+    }
+</script>
+<!-- end of compact paginator javascript -->
+
+<?php
+    }
+}
+
+//FIXME: added <small> tag just to buy needed space on crowded nav bar -- should we remove <small> and find another solution for un-crowding the nav bar?
+    echo '<small>' . get_abook_paginator($abook_page_selector, $abook_page_selector_max, $page_number, $page_size, $total_addresses, $show_all, $current_page_args, $abook_compact_paginator) . '</small>';
+
index 1a89b89..249e5a0 100644 (file)
@@ -529,13 +529,23 @@ td.message_count  {
     text-align: center;
     background: #ababab /* __COLOR9__ */;
 }
-#addressList    td.abookSwitch  {
+
+#addressList    select {
+    vertical-align: middle;
+}
+
+#addressList    td.abookPaginationAndButtons  {
     background: #dcdcdc /* __COLOR0__ */;
     text-align: right;
 }
 
-#addressList    td.abookButtons  {
+#addressList    div.abookPagination  {
+    float: left;
+}
+
+#addressList    td.abookSwitch  {
     background: #dcdcdc /* __COLOR0__ */;
+    text-align: right;
 }
 
 #addressList    td.abookField   {