Ability to add records to permanent bookbags in TPAC.
authorJason Stephenson <jason@sigio.com>
Sun, 20 May 2012 20:55:38 +0000 (16:55 -0400)
committerJason Stephenson <jason@sigio.com>
Wed, 27 Jun 2012 23:15:34 +0000 (19:15 -0400)
Add an actor usr setting for holding the name of a default book
list: opac.default_list.

Add a button on the my list interface to choose a list should as
the default list for adding titles.  There is presently no way to
unset a default menu, though the default can be changed to any
other menu at any time by clicking that list's button.

Modify opac/record and opac/results so that if a patron is logged
in their my lists will populate a menu.  This menu will include
options to add to a temporary list, the default list (if any), up
to 10 of the user's other lists, to add to a newly created list,
or to see all of their lists and add to one that does not appear
on the menu.

Adding to a temporary list will function the same as adding to a
list does prior to this enhancement.

Adding to a list chosen from the menu will add the record to that
list, and return the user to the search results or record page
that they were looking at.

Choosing to add to a new list will take the user to their "my
lists" page where they can create a new list.  After the list is
created, the record they wanted to add will be added to the new
list and they will be returned to the search results or record
that they were looking at.

Choosing the "see all" menu option will also take the user to
their "my lists" page.  However, all of their bookbags will be
visible and not just the normal limit of 10.  Their will be a
button next to each list's name with the text "Add to this list."
When the user clicks one of those buttons, the record will be
added to that list and the user's session redirected back to
their search or result page.

The user will have the option to create a new list when viewing
all of their lists.

The user will also be able to use the "Add to this list" feature
when they have chosen the "Add to new list" menu option.  This is
done from simplicity in the design, but also allows the user to
change their mind at the last second.

If a patron is not logged in, the add to my list will appear the
same as it does prior to this development.  It will continue to
function as it does prior to this development.

Signed-off-by: Jason Stephenson <jason@sigio.com>
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
Open-ILS/src/templates/opac/myopac/lists.tt2
Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
Open-ILS/src/templates/opac/parts/record/summary.tt2
Open-ILS/src/templates/opac/parts/result/table.tt2
Open-ILS/web/css/skin/default/opac/style.css

index 2346542..f716f1d 100644 (file)
@@ -257,6 +257,37 @@ sub fetch_optin_prefs {
     return [map { {cust => $_, value => $user_set->{$_->name} } } @$opt_ins];
 }
 
+sub _load_lists_and_settings {
+    my $self = shift;
+    my $e = $self->editor;
+    my $stat = $self->_load_user_with_prefs;
+    unless ($stat) {
+        my $exclude = 0;
+        my $setting_map = $self->ctx->{user_setting_map};
+        $exclude = $$setting_map{'opac.default_list'} if ($$setting_map{'opac.default_list'});
+        $self->ctx->{bookbags} = $e->search_container_biblio_record_entry_bucket(
+            [
+                {owner => $self->ctx->{user}->id, btype => 'bookbag', id => {'<>' => $exclude}}, {
+                    order_by => {cbreb => 'name'},
+                    limit => $self->cgi->param('limit') || 10,
+                    offset => $self->cgi->param('offset') || 0
+                }
+            ]
+        );
+        # We also want a total count of the user's bookbags.
+        my $q = {
+            'select' => { 'cbreb' => [ { 'column' => 'id', 'transform' => 'count', 'aggregate' => 'true', 'alias' => 'count' } ] },
+            'from' => 'cbreb',
+            'where' => { 'btype' => 'bookbag', 'owner' => $self->ctx->{user}->id }
+        };
+        my $r = $e->json_query($q);
+        $self->ctx->{bookbag_count} = $r->[0]->{'count'};
+    } else {
+        return $stat;
+    }
+    return undef;
+}
+
 sub update_optin_prefs {
     my $self = shift;
     my $user_prefs = shift;
@@ -351,6 +382,7 @@ sub load_myopac_prefs_settings {
         opac.hits_per_page
         opac.default_search_location
         opac.default_pickup_location
+        opac.temporary_list_warn
     /;
 
     my $stat = $self->_load_user_with_prefs;
@@ -1645,7 +1677,10 @@ sub load_myopac_bookbags {
         $e->rollback;
         return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
     }
-    
+
+    # We load the user prefs to get their default bookbag.
+    $self->_load_user_with_prefs;
+
     # If the user wants a specific bookbag's items, load them.
     # XXX add bookbag item paging support
 
@@ -1697,6 +1732,16 @@ sub load_myopac_bookbags {
         $bookbag->items($items);
     }
 
+    # If we have add_rec, we got here from the "Add to new list"
+    # or "See all" popmenu items.
+    if (my $add_rec = $self->cgi->param('add_rec')) {
+        $self->ctx->{add_rec} = $add_rec;
+        $self->ctx->{where_from} = $self->ctx->{referer};
+        if ( my $anchor = $self->cgi->param('anchor') ) {
+            $self->ctx->{where_from} =~ s/#.*|$/#$anchor/;
+        }
+    }
+
     $e->rollback;
     return Apache2::Const::OK;
 }
@@ -1714,7 +1759,7 @@ sub load_myopac_bookbag_update {
     $action = 'save_notes' if $cgi->param('save_notes');
     $action ||= $cgi->param('action');
 
-    $list_id ||= $cgi->param('list');
+    $list_id ||= $cgi->param('list') || $cgi->param('bbid');
 
     my @add_rec = $cgi->param('add_rec') || $cgi->param('record');
     my @selected_item = $cgi->param('selected_item');
@@ -1743,9 +1788,20 @@ sub load_myopac_bookbag_update {
         $list->owner($e->requestor->id);
         $list->btype('bookbag');
         $list->pub($shared ? 't' : 'f');
-        $success = $U->simplereq('open-ils.actor', 
-            'open-ils.actor.container.create', $e->authtoken, 'biblio', $list)
-
+        $success = $U->simplereq('open-ils.actor',
+            'open-ils.actor.container.create', $e->authtoken, 'biblio', $list);
+        if (ref($success) ne 'HASH' && scalar @add_rec) {
+            $list_id = (ref($success)) ? $success->id : $success;
+            foreach my $add_rec (@add_rec) {
+                my $item = Fieldmapper::container::biblio_record_entry_bucket_item->new;
+                $item->bucket($list_id);
+                $item->target_biblio_record_entry($add_rec);
+                $success = $U->simplereq('open-ils.actor',
+                                         'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
+                last unless $success;
+            }
+            $url = $cgi->param('where_from') if ($success && $cgi->param('where_from'));
+        }
     } elsif($action eq 'place_hold') {
 
         # @hold_recs comes from anon lists redirect; selected_itesm comes from existing buckets
@@ -1779,7 +1835,21 @@ sub load_myopac_bookbag_update {
     if($action eq 'delete') {
         $success = $U->simplereq('open-ils.actor', 
             'open-ils.actor.container.full_delete', $e->authtoken, 'biblio', $list_id);
-
+        if ($success) {
+            # We check to see if we're deleting the user's default list.
+            $self->_load_user_with_prefs;
+            my $settings_map = $self->ctx->{user_setting_map};
+            if ($$settings_map{'opac.default_list'} == $list_id) {
+                # We unset the user's opac.default_list setting.
+                $success = $U->simplereq(
+                    'open-ils.actor',
+                    'open-ils.actor.patron.settings.update',
+                    $e->authtoken,
+                    $e->requestor->id,
+                    { 'opac.default_list' => 0 }
+                );
+            }
+        }
     } elsif($action eq 'show') {
         unless($U->is_true($list->pub)) {
             $list->pub('t');
@@ -1810,8 +1880,15 @@ sub load_myopac_bookbag_update {
                 'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
             last unless $success;
         }
-
-    } elsif($action eq 'del_item') {
+        # Redirect back where we came from if we have an anchor parameter:
+        if ( my $anchor = $cgi->param('anchor') ) {
+            $url = $self->ctx->{referer};
+            $url =~ s/#.*|$/#$anchor/;
+        } elsif ($cgi->param('where_from')) {
+            # Or, if we have a "where_from" parameter.
+            $url = $cgi->param('where_from');
+        }
+    } elsif ($action eq 'del_item') {
         foreach (@selected_item) {
             $success = $U->simplereq(
                 'open-ils.actor',
@@ -1822,6 +1899,22 @@ sub load_myopac_bookbag_update {
     } elsif ($action eq 'save_notes') {
         $success = $self->update_bookbag_item_notes;
         $url .= "&bbid=" . uri_escape($cgi->param("bbid")) if $cgi->param("bbid");
+    } elsif ($action eq 'make_default') {
+        $success = $U->simplereq(
+            'open-ils.actor',
+            'open-ils.actor.patron.settings.update',
+            $e->authtoken,
+            $list->owner,
+            { 'opac.default_list' => $list_id }
+        );
+    } elsif ($action eq 'remove_default') {
+        $success = $U->simplereq(
+            'open-ils.actor',
+            'open-ils.actor.patron.settings.update',
+            $e->authtoken,
+            $list->owner,
+            { 'opac.default_list' => 0 }
+        );
     }
 
     return $self->generic_redirect($url) if $success;
index c7e9b4d..67e6369 100644 (file)
@@ -49,6 +49,12 @@ sub load_record {
     $self->fetch_related_search_info($rec_id);
     $self->timelog("past related search info");
 
+    # Check for user and load lists and prefs
+    if ($self->ctx->{user}) {
+        $self->_load_lists_and_settings;
+        $self->timelog("load user lists and settings");
+    }
+
     # run copy retrieval in parallel to bib retrieval
     # XXX unapi
     my $cstore = OpenSRF::AppSession->create('open-ils.cstore');
index e4e23e5..bba1a0a 100644 (file)
@@ -447,6 +447,9 @@ sub load_rresults {
         return $stat if $stat;
     }
 
+    # load temporary_list settings for user and ou:
+    $self->_load_lists_and_settings if ($ctx->{user});
+
     # shove recs into context in search results order
     for my $rec_id (@$rec_ids) {
         push(
index efefd4d..7d0ce86 100644 (file)
                     [%- INCLUDE "opac/parts/preserve_params.tt2"; %]
                     <input id="list_create_name" type="text" name="name" />
                     <input type="hidden" name="action" value="create" />
+                    [% IF ctx.add_rec %]
+                    <input type="hidden" name="add_rec" value="[% ctx.add_rec %]" />
+                    [% END %]
+                    [% IF ctx.where_from %]
+                    <input type="hidden" name="where_from" value="[% ctx.where_from %]" />
+                    [% END %]
                 </td>
                 <td>
                     <label for="list_create_shared">[% l('Share this list?') %]</label>
                 <h2 class="bookbag-name"><a title="[% ltitle %]" href="[% url %]">[% bbag.name | html %]</a></h2>
                 [% IF bbag.description %]<div class="bookbag-description">[% bbag.description | html %]</div>[% END %]
             </div>
+            [% IF ctx.add_rec %]
+            <form action="[% mkurl(ctx.opac_root _ '/myopac/list/update', {}, 1) %]" method="POST">
+                <div class="bookbag-controls">
+                    <input type="hidden" name="action" value="add_rec" />
+                    <input type="hidden" name="list" value="[% bbag.id %]" />
+                    <input type="hidden" name="add_rec" value="[% ctx.add_rec %]" />
+                    [% IF ctx.where_from %]
+                    <input type="hidden" name="where_from" value="[% ctx.where_from %]" />
+                    [% END %]
+                    <input class="fixed" type="submit" value="[% l('Add to this list') %]" />
+                </div>
+            </form>
+            [% END %]
             <form action="[% mkurl(ctx.opac_root _ '/myopac/list/update') %]" method="POST">
                 <div class="bookbag-share">
                     <input type="hidden" name="list" value="[% bbag.id %]" />
                 -%]'>[% l('HTML View') %]</a>
                 [% END %]
             </div>
+            [% setting = 'opac.default_list'; %]
+            <form action="[% mkurl(ctx.opac_root _ '/myopac/list/update') %]" method="POST">
+                <div class="bookbag-controls">
+                    <input type="hidden" name="list" value="[% bbag.id %]" />
+                    [%- INCLUDE "opac/parts/preserve_params.tt2"; %]
+                    [% IF ctx.user_setting_map.$setting == bbag.id %]
+                    <input type="hidden" name="action" value="remove_default" />
+                    <input type="submit" value="[% l('Remove Default List') %]" />
+                    [% ELSE %]
+                    <input type="hidden" name="action" value="make_default" />
+                    <input type="submit" value="[% l('Make Default List') %]" />
+                    [% END %]
+                </div>
+            </form>
             <div class="clear-both pad-bottom-five"></div>
         </div>
         [% IF CGI.param("bbid") == bbag.id %]
index 4ee6190..864ca99 100644 (file)
                             [% IF ctx.user_setting_map.$setting; %] checked='checked' [% END %]/>
                     </td>
                 </tr>
-
+                <tr>
+                    <td>[% l('Warn when adding to temporary book list?') %]</td>
+                    <td>
+                        [% setting = 'opac.temporary_list_warn' %]
+                        <input name='[% setting %]' type="checkbox"
+                            [% IF ctx.user_setting_map.$setting %] checked='checked' [% END %]/>
+                    </td>
+                </tr>
                 <!--
                 <tr>
                     <td>[% l("Default Font Size") %]</td>
index 062bf2f..201a4e9 100644 (file)
             class="place_hold">[% l('Place Hold') %]</span></a>
         </div>
         <div class="rdetail_aux_utils toggle_list">
-        [%-  
+        [%  IF ctx.user;
+            dsetting = "opac.default_list";
+            tclass = (ctx.user_setting_map.$dsetting) ? "temporary" :
+                         (ctx.bookbags.size) ? "temporary divider" : "temporary";
+            href = mkurl(ctx.opac_root _ '/mylist/add',
+                         {record => ctx.bre_id, anchor => ctx.bre_id}, stop_parms);
+        %]
+            <ul class="popmenu">
+            <li><a href="#" class="no-dec">
+                    <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
+                    [% l("Add to my list") %]
+                </a>
+            <ul>
+            <li class="[% tclass %]">
+                <a href="[% href %]">[% l('Temporary List') %]</a>
+            </li>
+            [% IF ctx.user_setting_map.$dsetting;
+               class = (ctx.bookbags.size) ? "default divider" : "default";
+               href = mkurl(ctx.opac_root _ '/myopac/list/update',
+                            {action => 'add_rec', list => ctx.user_setting_map.$dsetting,
+                             record => ctx.bre_id, anchor => ctx.bre_id}, stop_parms);
+            %]
+            <li class="[% class %]">
+                <a href="[% href %]">[% l('Default List') %]</a>
+            </li>
+            [% END %]
+            [% IF ctx.bookbags.size;
+               i = 0;
+               FOREACH bag IN ctx.bookbags;
+                   href = mkurl(ctx.opac_root _ '/myopac/list/update',
+                                {action => 'add_rec', list => bag.id, record => ctx.bre_id,
+                                 anchor => ctx.bre_id}, stop_parms);
+                   i = i + 1;
+                   IF i == ctx.bookbags.size;
+            %]
+            <li class="divider">
+                [% ELSE %]
+            <li>
+                [% END %]
+               <a href="[% href %]">[% bag.name %]</a>
+            </li>
+            [%
+               END;
+               END
+            %]
+            <li>
+                <a href="[% mkurl(ctx.opac_root _ '/myopac/lists', {limit => ctx.bookbag_count, add_rec => ctx.bre_id}) %]">
+                [% l('See All') %]
+                </a>
+            </li>
+            <li class="new">
+                <a href="[% mkurl(ctx.opac_root _ '/myopac/lists', {add_rec => ctx.bre_id}, stop_parms) %]">
+                [% l('Add to new list') %]
+                </a>
+            </li>
+            </ul>
+            </li>
+            </ul>
+        [%  ELSE;
             operation = ctx.mylist.grep(ctx.bre_id).size ? "delete" : "add";
             label = (operation == "add") ? l("Add to my list") : l("Remove from my list"); 
         %]
@@ -38,6 +96,7 @@
                 <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
                 [% label %]
             </a>
+        [% END %]
         </div>
         <div class="rdetail_aux_utils">
             <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
index 21ccaa4..0a753b0 100644 (file)
                                                                 alt=""/><span class="result_place_hold">[% l('Place Hold') %]</span></a>
                                                         </div>
                                                         <div class="results_aux_utils result_util">
-                                                            [%  
+                                                            [%  IF ctx.user;
+                                                                dsetting = "opac.default_list";
+                                                                tclass = (ctx.user_setting_map.$dsetting) ? "temporary" :
+                                                                           (ctx.bookbags.size) ? "temporary divider" : "temporary";
+                                                                 href = mkurl(ctx.opac_root _ '/mylist/add',
+                                                                              {record => rec.id, anchor => 'record_' _ rec.id}, 1);
+                                                            %]
+                                                                <ul class="popmenu">
+                                                                    <li><a href="#" class="no-dec">
+                                                                          <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
+                                                                          [% l("Add to my list") %]
+                                                                        </a>
+                                                                    <ul>
+                                                                    <li class="[% tclass %]">
+                                                                    <a href="[% href %]">[% l('Temporary List') %]</a>
+                                                                    </li>
+                                                                    [% IF ctx.user_setting_map.$dsetting;
+                                                                       class = (ctx.bookbags.size) ? "default divider" : "default";
+                                                                       href = mkurl(ctx.opac_root _ '/myopac/list/update',
+                                                                                {action => 'add_rec', list => ctx.user_setting_map.$dsetting,
+                                                                                 record => rec.id, anchor => 'record_' _ rec.id}, 1);
+                                                                    %]
+                                                                    <li class="[% class %]">
+                                                                    <a href="[% href %]">[% l('Default List') %]</a>
+                                                                    </li>
+                                                                    [% END %]
+                                                                    [% IF ctx.bookbags.size;
+                                                                       i = 0;
+                                                                       FOREACH bag IN ctx.bookbags;
+                                                                           href = mkurl(ctx.opac_root _ '/myopac/list/update',
+                                                                                    {action => 'add_rec', list => bag.id, record => rec.id,
+                                                                                     anchor => 'record_' _ rec.id}, 1);
+                                                                           i = i + 1;
+                                                                           IF i == ctx.bookbags.size;
+                                                                    %]
+                                                                    <li class="divider">
+                                                                        [% ELSE %]
+                                                                    <li>
+                                                                        [% END %]
+                                                                    <a href="[% href %]">[% bag.name %]</a>
+                                                                    </li>
+                                                                    [%
+                                                                       END;
+                                                                       END
+                                                                    %]
+                                                                    <li>
+                                                                        <a href="[% mkurl(ctx.opac_root _ '/myopac/lists',
+                                                                                          {limit => ctx.bookbag_count, add_rec => rec.id,
+                                                                                           anchor => 'record_' _ rec.id}) %]">
+                                                                        [% l('See All') %]
+                                                                        </a>
+                                                                    </li>
+                                                                    <li class="new">
+                                                                    <a href="[% mkurl(ctx.opac_root _ '/myopac/lists',
+                                                                                     {add_rec => rec.id, anchor => 'record_' _ rec.id}, 0) %]">
+                                                                    [% l('Add to new list') %]
+                                                                    </a>
+                                                                    </li>
+                                                                    </ul>
+                                                                    </li>
+                                                                </ul>
+                                                            [%  ELSE;
                                                                 operation = ctx.mylist.grep(rec.id).size ? "delete" : "add";
                                                                 label = (operation == "add") ? l("Add to my list") : l("Remove from my list");
                                                                 href = mkurl(ctx.opac_root _ '/mylist/' _ operation, 
                                                                 <img src="[% ctx.media_prefix %]/images/clipboard.png" alt="" />
                                                                 [% label %]
                                                             </a>
+                                                            [% END %]
                                                         </div>
                                                         [% IF ENV.OILS_CONTENT_CAFE_USER %]
                                                         <div class="results_aux_utils result_util">
index 8a80c04..07fb17e 100644 (file)
@@ -1437,3 +1437,75 @@ a.preflib_change {
 .ac_tab_selected { background-color: #417860; }
 .ac_tab_selected a { color: #FFF; }
 #ac_content { clear: both; width: 100%; margin-top: 10px; }
+
+/* Popmenu styles used for making css menus. */
+.popmenu {
+    margin: 0;
+    padding: 0;
+}
+.popmenu li {
+    list-style: none;
+}
+.popmenu li a {
+    display: block;
+    padding: 3px 5px;
+}
+.popmenu li ul {
+    display: none; 
+    width: 10em; /* Width to help Opera out */
+    background-color: #00593d;
+}
+.popmenu li:hover ul {
+    display: block;
+    position: absolute;
+    margin: 0;
+    padding: 0;
+    border-color: black;
+    border-width: 1px;
+    border-style: solid;
+}
+.popmenu li:hover li {
+    float: none;
+}
+.popmenu li:hover li a {
+    background-color: #00593d; 
+    color: #f0e0e0;
+}
+.popmenu li li a:hover {
+    background-color: #f0e0e0; 
+    color: #00593d;
+}
+/* Styles for the temporary list entry. */
+.popmenu li:hover li[class~="temporary"] a {
+    background-color: #00593d; 
+    color: #f0e0e0;
+}
+.popmenu li li[class~="temporary"] a:hover {
+    background-color: #f0e0e0; 
+    color: #00593d;
+}
+/* Styles for the default list entry. */
+.popmenu li:hover li[class~="default"] a {
+    background-color: #00593d; 
+    color: #f0e0e0;
+}
+.popmenu li li[class~="default"] a:hover {
+    background-color: #f0e0e0; 
+    color: #00593d;
+}
+/* Styles for the new list entry. */
+.popmenu li:hover li[class~="new"] a {
+    background-color: #00593d; 
+    color: #f0e0e0;
+}
+.popmenu li li[class~="new"] a:hover {
+    background-color: #f0e0e0; 
+    color: #00593d;
+}
+/* Style to add a divider on the menu. */
+.popmenu li li[class~="divider"] {
+    border-bottom-width: 1px;
+    border-bottom-color: black;
+    border-bottom-style: solid;
+}
+