Org unit sibling display sort order : admin UI
authorBill Erickson <berick@esilibrary.com>
Tue, 13 Mar 2012 16:17:23 +0000 (12:17 -0400)
committerMike Rylander <mrylander@gmail.com>
Mon, 2 Apr 2012 16:15:58 +0000 (12:15 -0400)
Adds a new menu entry for Local Admin called "Library Sort Order", where
staff can configure via drag-n-drop the sibling display order for org
units in the opac.

Signed-off-by: Bill Erickson <berick@esilibrary.com>
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/src/templates/actor/org_unit/sibling_order.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/actor/org_unit/sibling_order.js [new file with mode: 0644]
Open-ILS/web/opac/locale/en-US/lang.dtd
Open-ILS/xul/staff_client/chrome/content/main/menu.js
Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties

diff --git a/Open-ILS/src/templates/actor/org_unit/sibling_order.tt2 b/Open-ILS/src/templates/actor/org_unit/sibling_order.tt2
new file mode 100644 (file)
index 0000000..49050c3
--- /dev/null
@@ -0,0 +1,57 @@
+[% WRAPPER base.tt2 %]
+[% ctx.page_title = l('Org Unit Sibling Order') %]
+<link rel='stylesheet' type='text/css' href='[% ctx.media_prefix %]/js/dojo/dojo/resources/dnd.css'/>
+<style>
+    .dimple_img { padding-right: 5px; }
+    #child-table { margin-left: 15px; margin-top: 10px;}
+    #child-tbody td { padding: 5px 10px 5px 10px; }
+    #child-tbody tr:nth-child(odd) { 
+        background-color:#E7A555; 
+        border-left: 1px solid #4A4747; 
+        border-right: 1px solid #4A4747; 
+    }
+    #wrapper { width:100%; margin-top: 15px; }
+    #left-pane { float:left; padding-right: 20px; max-width: 40%; }
+    #right-pane { float:left; padding-left: 10px; max-width: 58%; }
+    #ol { border:2px dashed #4A4747; -moz-border-radius: 10px; padding: 5px; }
+</style>
+
+<h2>[% l('Org Unit Sibling Order') %]</h2>
+<hr/>
+
+<div id='wrapper'>
+    <div id='left-pane'>
+        <div>
+            <select dojoType="openils.widget.OrgUnitFilteringSelect"
+                    jsId='contextOrgSelector'
+                    searchAttr='shortname'
+                    labelAttr='shortname'>
+            </select>
+        </div>
+        <table id='child-table'>
+            <tbody id='child-tbody'>
+                <tr id='row-template'>
+                    <td name='name'></td>
+                    <td>
+                        <img class='dimple_img' src="[% ctx.media_prefix %]/images/dimple.png"/>
+                        <img class='dimple_img' src="[% ctx.media_prefix %]/images/dimple.png"/>
+                        <img class='dimple_img' src="[% ctx.media_prefix %]/images/dimple.png"/>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    <div id='right-pane'>
+        <div id='ol'>
+            <ol>
+                <li>[% l('Select the org unit whose children you wish to sort.') %]</li>
+                <li>[% l('Drag the child org units up or down to change the position.') %]</li>
+                <li>[% l('After each drag operation, the changes are automatically saved.') %]</li>
+                <li>[% l('When finished, it will be necessary to restart/reload the web server (Apache) for the changes to take effect.') %]</li>
+            </ol>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript" src='[% ctx.media_prefix %]/js/ui/default/actor/org_unit/sibling_order.js'> </script>
+[% END %]
diff --git a/Open-ILS/web/js/ui/default/actor/org_unit/sibling_order.js b/Open-ILS/web/js/ui/default/actor/org_unit/sibling_order.js
new file mode 100644 (file)
index 0000000..c06d98d
--- /dev/null
@@ -0,0 +1,103 @@
+dojo.require("dijit.form.Button");
+dojo.require("dojo.dnd.Source");
+dojo.require("openils.User");
+dojo.require("openils.Util");
+dojo.require("openils.PermaCrud");
+dojo.require('openils.widget.OrgUnitFilteringSelect');
+
+var user;
+var pcrud;
+var dndSource;
+
+function pageInit() {
+    user = new openils.User();
+    pcrud = new openils.PermaCrud({authtoken : user.authtoken});
+    fieldmapper.aou.slim_ok = false; // we need full orgs for updates
+
+    user.buildPermOrgSelector(
+        ['UPDATE_ORG_UNIT', 'ADMIN_ORG_UNIT'],
+        contextOrgSelector, 
+        null, 
+        function() {
+            dojo.connect(contextOrgSelector, 'onChange', drawChildren)
+            // set the value to the root of the tree (instead of ws_ou).
+            contextOrgSelector.store.fetch({
+                query : {id : '*'},
+                onComplete : function(list) {
+                    contextOrgSelector.attr('value', list[0].id);
+                }
+            });
+        }
+    );
+}
+
+var tbody, rowTmpl;
+function drawChildren() {
+
+    if(!tbody) {
+        tbody = dojo.byId('child-tbody');
+        rowTmpl = tbody.removeChild(dojo.byId('row-template'));
+        dndSource = new dojo.dnd.Source(tbody);
+        dojo.connect(dndSource, 'onDndDrop', updateSiblingOrder);
+    }
+
+    dndSource.selectAll();
+    dndSource.deleteSelectedNodes();
+    dndSource.clearItems();
+
+    var org = fieldmapper.aou.findOrgUnit(contextOrgSelector.attr('value'));
+    if (!org.children()) return;
+   
+    // fetch the full child org units
+    org.children( 
+        org.children().map(
+            function(c) { return fieldmapper.aou.findOrgUnit(c.id()) }
+        )
+    );
+
+    // sort by sibling order, fall back to name
+    var children = org.children().sort(
+        function(a, b) {
+            if (a.sibling_order() < b.sibling_order()) {
+                return -1;
+            } else if (a.sibling_order() > b.sibling_order()) {
+                return 1;
+            } else if (a.name() < b.name()) {
+                return -1;
+            }
+            return 1;
+        }
+    );
+
+    dojo.forEach(
+        children,
+        function(child) {
+            var row = tbody.appendChild(rowTmpl.cloneNode(true));
+            row.setAttribute('child', child.id());
+            dojo.query('[name=name]', row)[0].innerHTML = child.name();
+            dndSource.insertNodes(false, [row]);
+        }
+    );
+}
+
+function updateSiblingOrder() {
+    var pos = 0;
+    var toUpdate = [];
+    dojo.forEach(
+        dndSource.getAllNodes(),
+        function(node) {
+            childId = node.getAttribute('child');
+            var child = fieldmapper.aou.findOrgUnit(childId);
+            if (child.sibling_order() != pos) {
+                child.sibling_order(pos);
+                toUpdate.push(child);
+            }
+            pos++;
+        }
+    );
+
+    if (toUpdate.length == 0) return;
+    pcrud.update(toUpdate); // run sync to prevent UI changes mid-update 
+}
+
+openils.Util.addOnLoad(pageInit);
index 38b9866..e42c1a1 100644 (file)
 <!ENTITY staff.server.admin.index.closed_dates "Closed Dates Editor">
 <!ENTITY staff.server.admin.index.copy_locations "Copy Locations Editor">
 <!ENTITY staff.server.admin.index.library_settings "Library Settings Editor">
+<!ENTITY staff.server.admin.index.library_sort_order "Library Sort Order">
 <!ENTITY staff.server.admin.index.non_cataloged_types "Non-cataloged Types Editor">
 <!ENTITY staff.server.admin.index.statistical_categories "Statistical Categories Editor">
 <!ENTITY staff.server.admin.index.expired_holds_shelf "Expired Holds Shelf Printable Listing">
index 4ca96d8..bc35694 100644 (file)
@@ -1106,6 +1106,17 @@ main.menu.prototype = {
                     );
                 }
             ],
+            'cmd_local_admin_lib_sort_order' : [
+                ['oncommand'],
+                function(event) {
+                    open_eg_web_page(
+                        "/eg/actor/org_unit/sibling_order",
+                        "menu.cmd_local_admin_lib_sort_order.tab",
+                        event
+                    );
+                }
+            ],
+
             'cmd_reprint' : [
                 ['oncommand'],
                 function() {
index bd98d4b..67752f5 100644 (file)
              />
     <command id="cmd_local_admin_copy_locations" />
     <command id="cmd_local_admin_lib_settings" />
+    <command id="cmd_local_admin_lib_sort_order" />
     <command id="cmd_local_admin_non_cat_types" />
     <command id="cmd_local_admin_stat_cats" />
     <command id="cmd_local_admin_standing_penalty" />
                 <menuitem label="&staff.main.menu.admin.local_admin.conify.grp_penalty_threshold.label;" command="cmd_local_admin_grp_penalty_threshold"/>
                 <menuitem label="&staff.main.menu.admin.local_admin.hold_matrix_matchpoint.label;" command="cmd_local_admin_hold_matrix_matchpoint"/>
                 <menuitem label="&staff.server.admin.index.library_settings;" command="cmd_local_admin_lib_settings"/>
+                <menuitem label="&staff.server.admin.index.library_sort_order;" command="cmd_local_admin_lib_sort_order"/>
                 <menuitem label="&staff.server.admin.index.non_cataloged_types;" command="cmd_local_admin_non_cat_types"/>
                 <menuitem label="&staff.main.menu.admin.local_admin.conify.action_trigger.label;" command="cmd_local_admin_action_trigger"/>
                 <menuitem label="&staff.main.menu.admin.local_admin.patrons_due_refunds.label;" accesskey="&staff.main.menu.admin.local_admin.patrons_due_refunds.accesskey;" command="cmd_local_admin_patrons_due_refunds"/>
index 961ad06..4f30313 100644 (file)
@@ -252,6 +252,7 @@ menu.cmd_booking_resource.tab=Resources
 menu.cmd_booking_reservation.tab=Reservations
 menu.cmd_booking_reservation_pickup.tab=Reservation Pickup
 menu.cmd_booking_reservation_return.tab=Reservation Return
+menu.cmd_local_admin_lib_sort_order.tab=Library Sort Order
 menu.cmd_booking_pull_list.tab=Booking Pull List
 menu.cmd_booking_capture.tab=Booking Capture
 menu.cmd_authority_manage.tab=Manage Authorities