Selaa lähdekoodia

Add address list pagination, 'Compose To' button, more labels for checkboxes, hook points for plugins to modify abook nav bar and filter address listings

pdontthink 17 vuotta sitten
vanhempi
commit
766622207d

+ 5 - 0
ChangeLog

@@ -248,6 +248,11 @@ Version 1.5.2 - SVN
     default_pref file next to hardcoding them into the DB class, thanks
     default_pref file next to hardcoding them into the DB class, thanks
     Thierry Godefroy.
     Thierry Godefroy.
   - Reimplement printer friendly to make use of CSS.
   - 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)
 Version 1.5.1 (branched on 2006-02-12)
 --------------------------------------
 --------------------------------------

+ 2 - 3
functions/addressbook.php

@@ -363,9 +363,8 @@ function show_abook_sort_button($abook_sort_order, $alt_tag,
         $which = 8;
         $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. */
     /* Now that we have everything figured out, show the actual button. */
     return create_hyperlink($uri,
     return create_hyperlink($uri,

+ 257 - 11
functions/template/abook_util.php

@@ -14,16 +14,17 @@
 
 
 
 
 /**
 /**
- * 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;
     global $abook_sort_order, $nbsp;
 
 
     switch ($field) {
     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
     // 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);
+
 }
 }
 
 
 
 

+ 6 - 0
include/load_prefs.php

@@ -278,6 +278,12 @@ $page_selector = getPref($data_dir, $username, 'page_selector', SMPREF_ON);
 $compact_paginator = getPref($data_dir, $username, 'compact_paginator', SMPREF_OFF);
 $compact_paginator = getPref($data_dir, $username, 'compact_paginator', SMPREF_OFF);
 $page_selector_max = getPref($data_dir, $username, 'page_selector_max', 10);
 $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 */
 /* SqClock now in the core */
 $date_format = getPref($data_dir, $username, 'date_format', 3);
 $date_format = getPref($data_dir, $username, 'date_format', 3);
 $hour_format = getPref($data_dir, $username, 'hour_format', SMPREF_TIME_12HR);
 $hour_format = getPref($data_dir, $username, 'hour_format', SMPREF_TIME_12HR);

+ 39 - 0
include/options/display.php

@@ -15,6 +15,7 @@
 define('SMOPT_GRP_GENERAL', 0);
 define('SMOPT_GRP_GENERAL', 0);
 define('SMOPT_GRP_MAILBOX', 1);
 define('SMOPT_GRP_MAILBOX', 1);
 define('SMOPT_GRP_MESSAGE', 2);
 define('SMOPT_GRP_MESSAGE', 2);
+define('SMOPT_GRP_ABOOK', 3);
 
 
 global $use_iframe;
 global $use_iframe;
 if (! isset($use_iframe)) $use_iframe=false;
 if (! isset($use_iframe)) $use_iframe=false;
@@ -400,6 +401,44 @@ FIXME!
         'refresh' => SMOPT_REFRESH_ALL
         '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. */
     /* Assemble all this together and return it as our result. */
     $result = array(
     $result = array(
         'grps' => $optgrps,
         'grps' => $optgrps,

+ 106 - 17
src/addressbook.php

@@ -39,6 +39,12 @@ sqgetGlobalVar('sel',           $sel,           SQ_POST);
 sqgetGlobalVar('oldnick',       $oldnick,       SQ_POST);
 sqgetGlobalVar('oldnick',       $oldnick,       SQ_POST);
 sqgetGlobalVar('backend',       $backend,       SQ_POST);
 sqgetGlobalVar('backend',       $backend,       SQ_POST);
 sqgetGlobalVar('doedit',        $doedit,        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 */
 /* Get sorting order */
 $abook_sort_order = get_abook_sort();
 $abook_sort_order = get_abook_sort();
@@ -51,7 +57,7 @@ displayPageHeader($color);
 */
 */
 $abook = addressbook_init(true, false);
 $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) {
 if($abook->localbackend == 0) {
     plain_error_message(_("No personal address book is defined. Contact administrator."));
     plain_error_message(_("No personal address book is defined. Contact administrator."));
     exit();
     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
     // Some times we end output before forms are printed
     if($abortform) {
     if($abortform) {
+//FIXME: use footer.tpl; remove HTML from core
         echo "</body></html>\n";
         echo "</body></html>\n";
         exit();
         exit();
     }
     }
@@ -294,38 +301,120 @@ while (list($k, $backend) = each ($abook->backends)) {
     $a['BackendWritable'] = $backend->writeable;
     $a['BackendWritable'] = $backend->writeable;
     $a['Addresses'] = array();
     $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 {
     } 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) {
 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('addresses', $addresses);
     $oTemplate->assign('current_backend', $current_backend);
     $oTemplate->assign('current_backend', $current_backend);
     $oTemplate->assign('backends', $list_backends);
     $oTemplate->assign('backends', $list_backends);
     $oTemplate->assign('abook_has_extra_field', $abook->add_extra_field);
     $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');
     $oTemplate->display('addressbook_list.tpl');
     
     
-//FIXME: Remove HTML from here!
-    echo "</form>\n";
 }
 }
 
 
 /* Display the "new address" form */
 /* Display the "new address" form */

+ 81 - 59
templates/default/addressbook_list.tpl

@@ -1,50 +1,58 @@
 <?php
 <?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 **/
 /** add required includes **/
 include_once(SM_PATH . 'functions/template/abook_util.php');
 include_once(SM_PATH . 'functions/template/abook_util.php');
@@ -56,6 +64,7 @@ extract($t);
 $source = $addresses[$current_backend];
 $source = $addresses[$current_backend];
 $colspan = $abook_has_extra_field ? 6 : 5;
 $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">
 <div id="addressList">
 <table cellspacing="0">
 <table cellspacing="0">
  <tr>
  <tr>
@@ -64,13 +73,21 @@ $colspan = $abook_has_extra_field ? 6 : 5;
   </td>
   </td>
  </tr>
  </tr>
  <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>
   <td colspan="<?php echo ($colspan - 3); ?>" class="abookSwitch">
   <td colspan="<?php echo ($colspan - 3); ?>" class="abookSwitch">
+   <?php if (!empty($plugin_output['address_book_filter'])) echo $plugin_output['address_book_filter']; ?>
    <?php
    <?php
     if (count($backends) > 0) {
     if (count($backends) > 0) {
         ?>
         ?>
@@ -91,10 +108,10 @@ $colspan = $abook_has_extra_field ? 6 : 5;
  </tr>
  </tr>
  <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: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
   <?php
    if ($abook_has_extra_field) {
    if ($abook_has_extra_field) {
     echo '<td class="colHeader"></td>';
     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";
         echo '<tr><td class="abookEmpty" colspan="'.$colspan.'">'._("Address book is empty").'</td></tr>'."\n";
     }
     }
     foreach ($source['Addresses'] as $contact) {
     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: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" 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"><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"><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>
   <td class="abookField"><label for="<?php echo $id . '">' . $contact['Info']; ?></label></td>
         <?php 
         <?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>
  </tr>
@@ -127,3 +148,4 @@ $colspan = $abook_has_extra_field ? 6 : 5;
 ?>
 ?>
 </table>
 </table>
 </div>
 </div>
+</form>

+ 67 - 0
templates/default/addressbook_paginator.tpl

@@ -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>';
+

+ 12 - 2
templates/default/css/default.css

@@ -529,13 +529,23 @@ td.message_count	{
     text-align: center;
     text-align: center;
     background: #ababab /* __COLOR9__ */;
     background: #ababab /* __COLOR9__ */;
 }
 }
-#addressList    td.abookSwitch  {
+
+#addressList    select {
+    vertical-align: middle;
+}
+
+#addressList    td.abookPaginationAndButtons  {
     background: #dcdcdc /* __COLOR0__ */;
     background: #dcdcdc /* __COLOR0__ */;
     text-align: right;
     text-align: right;
 }
 }
 
 
-#addressList    td.abookButtons  {
+#addressList    div.abookPagination  {
+    float: left;
+}
+
+#addressList    td.abookSwitch  {
     background: #dcdcdc /* __COLOR0__ */;
     background: #dcdcdc /* __COLOR0__ */;
+    text-align: right;
 }
 }
 
 
 #addressList    td.abookField   {
 #addressList    td.abookField   {