Move serials interfaces closer together
authorDan Wells <dbw2@calvin.edu>
Fri, 8 Mar 2013 22:55:52 +0000 (17:55 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Wed, 13 Mar 2013 21:27:48 +0000 (17:27 -0400)
Back in (I believe) 2.2, we brought the dijit issuance editor into the
serial control interface with two goals: having less code in more places,
and easing the transition to an eventual unified interface which would
likely be more widget-based.

That experiment was well received, so this commit takes things a large
step further in that direction.  Basically, we are embedding the
alternate subscription editing interface into the serial control
scaffolding, which ultimately amounts to giving you some of the
benefits of both.  You get the more modern and maintainable code from
the alternate interfaces, but keep the context-awareness and familiar
navigation of the non-alternate serial control.

That said, this change is not meant to be the last word in serials,
but rather a way to at least come closer together while we still
continue to learn what structures provide the best experience.

Finally, some feature additions were necessary to the alternate serials
code in order to make this change as seamless as possible.  In some
cases, the new feature only works in the embedded version, but a new
'context' variable makes that simple to adjust as we move forward.
Changes include:
  - note editors on subscriptions and distributions
  - labeled dropdown for distribution summary options
  - and legacy record entry linkages

Signed-off-by: Dan Wells <dbw2@calvin.edu>
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/templates/serial/subscription.tt2
Open-ILS/src/templates/serial/subscription/distribution.tt2
Open-ILS/src/templates/serial/subscription/issuance.tt2
Open-ILS/web/js/ui/default/serial/subscription.js
Open-ILS/web/js/ui/default/serial/subscription/distribution.js [new file with mode: 0644]
Open-ILS/xul/staff_client/server/serial/manage_subs.js
Open-ILS/xul/staff_client/server/serial/ssub_editor.xul

index bfe0f08..5d91795 100644 (file)
@@ -1,5 +1,12 @@
+[% USE CGI; %]
 [% WRAPPER "base.tt2" %]
 <script>
+    [%- IF CGI.param('context') == 'scv' %]
+    xulG = parent.xulG;
+    [%- END %]
+    [%- IF CGI.param('id') != 'new' %]
+    sub_id = [% CGI.param('id') %];
+    [%- END %]
     var cap_editor;
     var cap_importer;
 </script>
@@ -7,6 +14,7 @@
 </script>
 <script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription.js">
 </script>
+<script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription/distribution.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription/caption_and_pattern.js">
 </script>
 <script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription/issuance.js">
     class="oils-serial-tab-container">
 
     <!-- Subscription Summary -->
+    [%- IF CGI.param('context') == 'scv' -%]
+    <div dojoType="dijit.layout.ContentPane" title="[% l('View/Edit') %]" selected="true">
+        <div dojoType="dijit.layout.ContentPane" layout="top"
+            class="oils-header-panel lesser">
+            <div>[% l('Subscriptions') %]</div>
+            <div style="margin-right: 16px;">
+                <span dojoType="dijit.form.Button"
+                    onClick="open_notes('sub', ssub_grid);">[% l('View/Edit Notes') %]</span>
+            </div>
+        </div>
+
+        <script type="dojo/connect" event="onShow">
+            if(ssub_grid.store && !ssub_grid._fresh) { // onShow fires twice on initial page load; we only want to run the second time (and subsequent times)
+                ssub_grid.resetStore();
+                if (sub_id) {
+                    ssub_grid.loadAll(
+                        {"order_by": {"ssub": "start_date DESC"}},
+                        {"id": sub_id}
+                    );
+                }
+                ssub_grid._fresh = true;
+            }
+        </script>
+        <table jsId="ssub_grid"
+            dojoType="openils.widget.AutoGrid"
+            query="{id: '*'}"
+            fieldOrder="['id','owning_lib','start_date','end_date']"
+            suppressFields="['record_entry']"
+            fmClass="ssub"
+            showPaginator="true"
+            onPostSubmit="attempt_reload_opac"
+            showSequenceFields="true"
+            editOnEnter="true">
+        </table>
+    </div>
+    [%- ELSE -%]
     <div dojoType="dijit.layout.ContentPane" title="[% l('Summary') %]" selected="true">
         <script type="dojo/connect" event="onShow">
             load_sub_grid(sub_id);
                     <th field="end_date" formatter="format_date">
                         [% l('End Date') %]
                     </th>
+                    [%- IF CGI.param('context') != 'scv' -%]
                     <th field="record_entry" width="20em"
                         formatter="format_bib">
                         [% l('Bibliographic Record') %]
                     </th>
+                    [%- END -%]
                     <th field="expected_date_offset">[% l('Expected Date Offset') %]</th>
                     <th field="num_dist">[% l('Number of Distributions') %]</th>
                 </tr>
             </thead>
         </table>
     </div>
+    [%- END -%]
 
     <!-- Distributions -->
     <div dojoType="dijit.layout.ContentPane" jsId="distributions_tab"
                         "disabled": true, "value": sub_id
                     });
 
+                // attach the holding_lib selector to the record_entry selector
+                dist_grid.overrideWidgetArgs.holding_lib = {'dijitArgs' : {'onChange' : function(value) { populate_sre_selector(dist_grid, value); } }};
                 var _display_grouping_store = new dojo.data.ItemFileReadStore({
                     "data": {
                         "identifier": "display_grouping",
                     dist_grid.overrideEditWidgets.display_grouping.shove = {
                         "create": default_display_grouping
                     };
+
+                var _summary_method_store = new dojo.data.ItemFileReadStore({
+                    "data": {
+                        "identifier": "summary_method",
+                        "label": "label",
+                        "items": [
+                            {"summary_method": "add_to_sre",
+                                "label": "[% l('Add to record entry') %]"},
+                            {"summary_method": "merge_with_sre",
+                                "label": "[% l('Merge with record entry') %]"},
+                            {"summary_method": "use_sre_only",
+                                "label": "[% l('Use record entry only') %]"},
+                            {"summary_method": "use_sdist_only",
+                                "label": "[% l('Do not use record entry') %]"}
+                        ]
+                    }
+                });
+
+                dist_grid.overrideEditWidgets.summary_method =
+                    new dijit.form.FilteringSelect({
+                        "store": _summary_method_store,
+                        "searchAttr": "label",
+                        "name": "summary_method"
+                    });
+                    // TODO: add setting for default selection?
+                    dist_grid.overrideEditWidgets.summary_method.shove = {
+                        "create": "add_to_sre"
+                    };
+
             }
         </script>
         [% INCLUDE "serial/subscription/distribution.tt2" %]
index 8a3c886..f20a9d3 100644 (file)
@@ -3,13 +3,15 @@
     <div>[% l('Distributions') %]</div>
     <div style="margin-right: 16px;">
         <span dojoType="dijit.form.Button"
+            onClick="open_notes('dist', dist_grid);">[% l('View/Edit Notes') %]</span>
+        <span dojoType="dijit.form.Button"
             onClick="dist_grid.refresh();">[% l('Refresh Grid') %]</span>
         <span dojoType="dijit.form.Button"
-            onClick="sub_grid._fresh = false; dist_grid.showCreateDialog();">
+            onClick="if (cgi.param('context') != 'scv') sub_grid._fresh = false; dist_grid.showCreateDialog();">
             [% l('New Distribution') %]
         </span>
         <span dojoType="dijit.form.Button"
-            onClick="sub_grid._fresh = false; dist_grid.deleteSelected();">
+            onClick="if (cgi.param('context') != 'scv') sub_grid._fresh = false; dist_grid.deleteSelected();">
             [% l('Delete Selected') %]
         </span>
     </div>
@@ -20,8 +22,8 @@
         dojoType="openils.widget.AutoGrid"
         style="height: 550px;"
         fieldOrder="['subscription','label','holding_lib']"
-        suppressFields="['record_entry','subscription','receive_call_number','bind_call_number','bind_unit_template']"
-        suppressEditFields="['record_entry','receive_call_number','bind_call_number','bind_unit_template']"
+        suppressFields="['subscription','receive_call_number','bind_call_number','bind_unit_template']"
+        suppressEditFields="['receive_call_number','bind_call_number','bind_unit_template']"
         onPostSubmit="attempt_reload_opac"
         fmClass="sdist"
         query="{id: '*'}"
index 1519c12..aaa0ee8 100644 (file)
             onclick="iss_grid.deleteSelected();">[% l('Delete Selected') %]</span>
     </div>
 </div>
+[%- IF CGI.param('context') != 'scv' -%]
 <div class="serial-additional-controls">
     <span dojoType="dijit.form.Button"
         onclick="prediction_dialog.show();">[% l('Generate Predictions') %]</span>
 </div>
+[%- END -%]
 <div dojoType="dijit.layout.ContentPane" layout="top">
     <table jsId="iss_grid"
         dojoType="openils.widget.AutoGrid"
index 2cfac2f..c1dded3 100644 (file)
@@ -11,6 +11,8 @@ dojo.require("openils.widget.ProgressDialog");
 dojo.require("openils.widget.HoldingCode");
 dojo.require("openils.PermaCrud");
 dojo.require("openils.CGI");
+dojo.requireLocalization('openils.serial', 'serial');
+var localeStrings = dojo.i18n.getLocalization('openils.serial', 'serial');
 
 var pcrud;
 var cgi;
@@ -129,7 +131,7 @@ function format_sdist_label(blob) {
         "sstr",{"distribution":blob.id},{"id_list":true}
     );
     count = sstr_list ? sstr_list.length : 0;
-    link += "&nbsp;&nbsp; " + count + " stream(s)";
+    link += "&nbsp;&nbsp; " + count + " stream(s)"; //XXX i18n
     return link;
 }
 
@@ -226,6 +228,31 @@ function _clone_subscription(bre_id) {
     );
 }
 
+function open_notes(obj_type, grid) {
+    if (grid.getSelectedRows().length != 1) {
+        alert( localeStrings.REQUIRE_ONE_ROW );
+        return;
+    }
+
+    var id = grid.getSelectedItems()[0].id[0];
+    var args_by_obj_type = {
+        'sub' : { 'function_type' : 'SSUBN', 'object_type' : 'subscription', 'constructor' : ssubn, 'title' : dojo.string.substitute(localeStrings.NOTES_SSUB, [id]) },
+        'dist' : { 'function_type' : 'SDISTN', 'object_type' : 'distribution', 'constructor' : sdistn, 'title' : dojo.string.substitute(localeStrings.NOTES_SDIST, [id]) }
+    };
+    args_by_obj_type[obj_type].object_id = id;
+
+    try {
+        window.openDialog(
+            xulG.url_prefix('XUL_SERIAL_NOTES'),
+            obj_type+'_notes',
+            'chrome,resizable,modal',
+            args_by_obj_type[obj_type]
+        );
+    } catch (E) {
+        alert(E); /* XXX */
+    }
+}
+
 openils.Util.addOnLoad(
     function() {
         var tab_dispatch = {
@@ -236,15 +263,50 @@ openils.Util.addOnLoad(
         cgi = new openils.CGI();
         pcrud = new openils.PermaCrud();
 
+        context = cgi.param("context");
         sub_id = cgi.param("id");
-        load_sub_grid(
-            sub_id,
-            (cgi.param("tab") in tab_dispatch) ?
-                function() {
-                    tab_container.selectChild(
-                        tab_dispatch[cgi.param("tab")]
-                    );
-                } : null
-        );
+        owning_lib = cgi.param("owning_lib");
+        record_entry = cgi.param("record_entry");
+
+        if (context != 'scv') {
+            load_sub_grid(
+                sub_id,
+                (cgi.param("tab") in tab_dispatch) ?
+                    function() {
+                        tab_container.selectChild(
+                            tab_dispatch[cgi.param("tab")]
+                        );
+                    } : null
+            );
+        } else {
+            build_sre_maps(dist_grid);
+            dist_grid.empty_store = new dojo.data.ItemFileReadStore({
+                "data": {
+                    "identifier": "record_entry",
+                    "label": "label",
+                    "items": []
+                }
+            })
+            dist_grid.overrideEditWidgets.record_entry =
+                new dijit.form.FilteringSelect({
+                    "store" : dist_grid.empty_store,
+                    "searchAttr" : "label",
+                    "name" : "record_entry"
+                });
+            dist_grid.overrideEditWidgets.record_entry.shove = {};
+            if (sub_id == 'new') {
+                ssub_grid.overrideEditWidgets.record_entry =
+                        new dijit.form.TextBox({
+                            "disabled": true, "value": record_entry
+                        });
+                ssub_grid.overrideWidgetArgs.owning_lib = {widgetValue : owning_lib, dijitArgs : {disabled : true}};
+
+                ssub_grid.onPostCreate = function(fmObject) {
+                    sub_id = fmObject.id();
+                }
+
+                ssub_grid.showCreateDialog();
+            }
+        }
     }
 );
diff --git a/Open-ILS/web/js/ui/default/serial/subscription/distribution.js b/Open-ILS/web/js/ui/default/serial/subscription/distribution.js
new file mode 100644 (file)
index 0000000..dd8a478
--- /dev/null
@@ -0,0 +1,60 @@
+/* Build maps of sre details for both display and selection purposes */
+
+function build_sre_maps(grid) {
+    try {
+        //grid.sre_id_map = {};
+        grid.sres_ou_map = {};
+        var parent_g = window.parent.parent.g;
+        if (parent_g.mfhd) {
+            var mfhd_details = parent_g.mfhd.details;
+            for (var i = 0; i < mfhd_details.length; i++) {
+                var mfhd_detail = {};
+                for (j in mfhd_details[i]) {
+                    mfhd_detail[j] = mfhd_details[i][j];
+                }
+                var entry = {};
+                entry.label = mfhd_detail.label + ' (' + (mfhd_detail.entryNum + 1) + ')';
+                entry.record_entry = mfhd_detail.id;
+                var org_unit_id = mfhd_detail.owning_lib;
+                //grid.sre_id_map[sre_id] = mfhd_detail;
+                if (!grid.sres_ou_map[org_unit_id]) {
+                    grid.sres_ou_map[org_unit_id] = 
+                        {
+                            "identifier": "record_entry",
+                            "label": "label",
+                            "items": []
+                        };
+                }
+                grid.sres_ou_map[org_unit_id].items.push(entry);
+            }
+
+            for (i in grid.sres_ou_map) {
+                grid.sres_ou_map[i] = new dojo.data.ItemFileReadStore({
+                    "data": grid.sres_ou_map[i]
+                });
+            }
+        }
+    } catch(E) {
+        alert(E); //XXX
+    }
+}
+
+
+function populate_sre_selector(grid, holding_lib_id, temp) {
+    if (grid.sres_ou_map[holding_lib_id]) {
+        grid.overrideEditWidgets.record_entry.attr
+            ("store", grid.sres_ou_map[holding_lib_id]);
+        grid.overrideEditWidgets.record_entry.shove = {};
+        grid.overrideEditWidgets.record_entry.attr("disabled", false);
+        // this is needed to reload the value after we change the store
+        // XXX is there a better way to do this?
+        grid.overrideEditWidgets.record_entry.setValue
+            (grid.overrideEditWidgets.record_entry._lastQuery);
+    } else {
+        grid.overrideEditWidgets.record_entry.attr
+            ("store", grid.empty_store);
+        grid.overrideEditWidgets.record_entry.attr("disabled", true);
+        grid.overrideEditWidgets.record_entry.attr("value", "");
+    }
+}
+
index 7607964..0f724ba 100644 (file)
@@ -56,6 +56,17 @@ serial.manage_subs.prototype = {
                     iframe.refresh_command = function () { /* TODO: redraw tree node */ };
                 }
                 iframe.setAttribute("src", src);
+            } else if (type == "ssub") {
+                var iframe = dojo.byId('alt_ssub_editor');
+                var src;
+                if (mode == "add") {
+                    src = '/eg/serial/subscription?id=new&owning_lib='+params.owning_lib+'&record_entry='+params.record_entry+'&context=scv';
+                    iframe.refresh_command = function () {obj.refresh_list();};
+                } else {
+                    src = '/eg/serial/subscription?id=' + params.ssub_ids[0] + '&context=scv';
+                    iframe.refresh_command = function () {}; //TODO: redraw tree node
+                }
+                iframe.setAttribute("src", src);
             } else {
                 var editor_type = type + '_editor';
                 if (typeof obj[editor_type] == 'undefined') {
@@ -508,12 +519,9 @@ serial.manage_subs.prototype = {
                                         alert(document.getElementById('catStrings').getString('staff.cat.copy_browser.add_volume.permission_error'));
                                         return; // no read-only view for this interface
                                     } */
-                                    var new_ssub = new ssub();
-                                    new_ssub.owning_lib(list[0]);//TODO: add multiple at once support?
-                                    new_ssub.isnew(1);
-                                    new_ssub.record_entry(obj.docid);
                                     var params = {};
-                                    params.ssubs = [new_ssub];
+                                    params.owning_lib = list[0];
+                                    params.record_entry = obj.docid;
                                     obj.editor_init('ssub', 'add', params);
                                 } catch(E) {
                                     obj.error.standard_unexpected_error_alert(document.getElementById('serialStrings').getString('staff.serial.manage_subs.add.error'),E);
index 10fabbc..1b2bf33 100644 (file)
 <overlay id="serial_ssub_editor_panel_overlay" 
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-       <vbox flex="1" id="serial_ssub_editor_panel" class="my_overflow">
-        <vbox id="brief_display_box"/>
-
-               <hbox flex="1" style="overflow: auto">
-                       <vbox flex="1" id="before_splitter" oils_persist="width">
-                               <label value="Subscription" style="font-weight: bold; font-size: large"/>
-                               <vbox id="left_pane" flex="1"/>
-                       </vbox>
-                       <splitter id="splitter" oils_persist="state hidden" oils_persist_peers="before_splitter after_splitter"><grippy /></splitter>
-                       <vbox flex="1" id="after_splitter" oils_persist="width">
-                               <label value=" " style="font-weight: bold; font-size: large"/>
-                               <vbox id="right_pane" flex="1"/>
-                       </vbox>
-               </hbox>
-
-               <hbox id="nav">
-                       <spacer flex="1"/>
-                       <button id="ssub_notes" label="&staff.serial.ssub_editor.notes.label;" accesskey="&staff.serial.ssub_editor.notes.accesskey;" oncommand="g.manage_subs.ssub_editor.notes()" />
-                       <button id="ssub_save" label="&staff.serial.ssub_editor.modify.label;" hidden="true" accesskey="&staff.serial.ssub_editor.modify.accesskey;" oncommand="g.manage_subs.ssub_editor.save()" />
-                       <!--<button id="cancel" label="&staff.cat.copy_editor.cancel.label;" accesskey="&staff.cat.copy_editor.cancel.accesskey;" oncommand="window.close();"/>-->
-               </hbox>
-
-               <spacer/>
-       </vbox>
+    <vbox flex="1" id="serial_ssub_editor_panel" class="my_overflow">
+        <iframe flex="1" id="alt_ssub_editor" name="alt_ssub_editor"/>
+    </vbox>
 
 </overlay>