KCLS local oils_web templates/javascript/css from devcatalog
authorJason Etheridge <jason@esilibrary.com>
Wed, 16 Feb 2011 17:43:52 +0000 (12:43 -0500)
committerJason Etheridge <jason@esilibrary.com>
Mon, 6 Jun 2011 17:53:09 +0000 (13:53 -0400)
39 files changed:
Open-ILS/examples/oils_web.xml.example
Open-ILS/web/css/skin/kcls/selfcheck.css [new file with mode: 0644]
Open-ILS/web/js/ui/kcls/circ/selfcheck/floating.js [new file with mode: 0644]
Open-ILS/web/js/ui/kcls/circ/selfcheck/payment.js [new file with mode: 0644]
Open-ILS/web/js/ui/kcls/circ/selfcheck/selfcheck.js [new file with mode: 0644]
Open-ILS/web/local_templates/base.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/base.tt2-aug17.old2 [new file with mode: 0644]
Open-ILS/web/local_templates/base.tt2.old [new file with mode: 0644]
Open-ILS/web/local_templates/default/actor/user/register_table.tt2.disabled [new file with mode: 0644]
Open-ILS/web/local_templates/default/actor/user/register_table.tt2.orig [new file with mode: 0644]
Open-ILS/web/local_templates/default/base.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/base.tt2.old [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/audio_config.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/banner.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/circ_page.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/fines.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/KCLS_logo_horiz.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/arrow.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/barcodedetailbook.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/go-btn.png [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/gobutton.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/libcard_barcode.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/login-btn.png [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logout.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutbutton.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutnoreceipt.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutwithoutreceiptbutton.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/printlist.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_font.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_mail.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_print.gif [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner-right.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner.jpg [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/holds_page.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/main.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/patron_login.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/payment.tt2 [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/style.css [new file with mode: 0644]
Open-ILS/web/local_templates/default/circ/selfcheck/summary.tt2 [new file with mode: 0644]

index 60f1573..5e09bc5 100644 (file)
@@ -23,6 +23,7 @@
          a path in front of the default template path -->
     <template_paths>
         <!-- XXX we should really move these out of the default web root -->
+        <path>/openils/var/web/local_templates</path>
         <path>/openils/var/web/templates</path>
     </template_paths>
 
diff --git a/Open-ILS/web/css/skin/kcls/selfcheck.css b/Open-ILS/web/css/skin/kcls/selfcheck.css
new file mode 100644 (file)
index 0000000..2a5dc79
--- /dev/null
@@ -0,0 +1,208 @@
+@charset "utf-8";\r
+/* CSS Document */\r
+\r
+html, body {\r
+       margin:0;\r
+       font-family: Arial, Helvetica, sans-serif;\r
+       font-size: 18px;\r
+       background:#fff;\r
+       width:100%;\r
+}\r
+\r
+img {\r
+       border: none;\r
+}\r
+\r
+a {\r
+       color: #003399;\r
+       text-decoration: none;\r
+}\r
+\r
+a:hover {\r
+       text-decoration: underline;\r
+}\r
+\r
+h1 {\r
+       margin:0;\r
+       margin-bottom: 5px;\r
+       font-size: 22px;\r
+       font-weight:normal;\r
+}\r
+\r
+h2 {\r
+       margin:0;\r
+       margin-bottom: 5px;\r
+       font-size: 20px;\r
+       font-weight:bold;\r
+}\r
+\r
+#header {\r
+       color: #bda964;\r
+       font-weight:bold;\r
+       padding: 12px 0px 9px 17px;\r
+       width: 694px;\r
+       margin: auto;\r
+}\r
+\r
+#content-wrapper {\r
+       background: white;\r
+}\r
+\r
+#main-content {\r
+       width: 694px;\r
+       margin:auto;\r
+       padding-left:17px;\r
+}\r
+\r
+.checkout {\r
+       font-size:18px;\r
+}\r
+\r
+.checkout h1 {\r
+       font-size:36px;\r
+}\r
+\r
+.checkout h2 {\r
+       font-size:24px;\r
+}\r
+\r
+.checkout .sidebar h3 {\r
+       font-size: 19px;\r
+       margin:0;\r
+       padding-left:3px;\r
+}\r
+\r
+.checkout .sidebar a {\r
+       font-size:18px;\r
+}\r
+\r
+.checkout .sidebar a span {\r
+       font-weight:bold;\r
+}\r
+\r
+.checkout .sidebar p {\r
+       margin:4px 0px;\r
+       padding:3px;\r
+}\r
+\r
+.checkout .sidebar div, .checkout .sidebar p {\r
+       font-size: 18px;\r
+       line-height: 1em;\r
+}\r
+\r
+.checkout input[type=text], .checkout input[type=password] {\r
+       border: 2px solid black;\r
+       width:300px;\r
+       height:22px;\r
+       padding:2px;\r
+       padding-top:1px;\r
+       margin:0px;\r
+       font-size:18px;\r
+}\r
+\r
+.checkout .sidebar {\r
+       background: #b0b0b0;\r
+       border-left:2px ridge #eee;\r
+       border-right:2px ridge #eee;\r
+       border-bottom:2px ridge #eee;\r
+       padding:10px 7px;\r
+}\r
+\r
+.checkout .sidebar .top {\r
+       float:right;\r
+       padding-right:5px;\r
+}\r
+\r
+.checkout .sidebar .greet {\r
+       clear:both;\r
+       padding:15px 3px;\r
+}\r
+\r
+.checkout .sidebar .selected {\r
+       background:#999\r
+}\r
+\r
+.checkout .header1 {\r
+       height:108px;\r
+       border-bottom:1px solid #a83135;\r
+       padding-top:20px;\r
+}\r
+\r
+.checkout .userid {\r
+       width:200px !important;\r
+       font-size:18px;\r
+       font-weight:bold;\r
+       padding:5px 6px 6px 6px !important;\r
+       border:2px solid black !important;\r
+       background: none !important;\r
+       margin:0 !important;\r
+}\r
+\r
+.checkout .item_table {\r
+       border-collapse: collapse;\r
+}\r
+\r
+.checkout .item_table td {\r
+       font-size:18px;\r
+       border:2px solid black;\r
+       text-align: left;\r
+}\r
+\r
+.checkout .item_table table td.label {\r
+       font-weight:bold;\r
+       text-transform: uppercase;\r
+       text-align: right;\r
+       white-space:nowrap;\r
+       padding-right:5px;\r
+       width:1px;\r
+}\r
+\r
+.checkout .item_table table td {\r
+       border:none;\r
+}\r
+\r
+.checkout #back_button:hover {\r
+       text-decoration: none;\r
+}\r
+\r
+.checkout .status_box {\r
+       color:red;\r
+       font-weight:bold;\r
+       height:20px;\r
+}\r
+\r
+.checkout .oils-selfck-status-div {\r
+       height:inherit !important;\r
+       vertical-align:inherit !important;\r
+       font-size: 18px;\r
+       font-weight: bold;\r
+       color: red;\r
+}\r
+\r
+#oils-base-body-block {\r
+       height: auto;\r
+}\r
+\r
+body .dijitAlignClient {\r
+       position:inherit;\r
+}\r
+\r
+.dijitLayoutContainer {\r
+       position: inherit;\r
+}\r
+\r
+#oils-base-content-block {\r
+       height: auto !important;\r
+       width: auto !important;\r
+       padding:0;\r
+}\r
+\r
+#oils-base-main-block {\r
+       height: auto !important;\r
+       width: auto !important;\r
+}\r
+\r
+#oils-base-header-block {\r
+       width:0px !important;\r
+}\r
+\r
diff --git a/Open-ILS/web/js/ui/kcls/circ/selfcheck/floating.js b/Open-ILS/web/js/ui/kcls/circ/selfcheck/floating.js
new file mode 100644 (file)
index 0000000..863cde8
--- /dev/null
@@ -0,0 +1,223 @@
+/* Script by: www.jtricks.com\r
+ * Version: 20071017\r
+ * Latest version:\r
+ * www.jtricks.com/javascript/navigation/floating.html\r
+ */\r
+var floatingMenuId = 'floatdiv';\r
+var floatingMenu =\r
+{\r
+    targetX: -250,\r
+    targetY: -75,\r
+\r
+    hasInner: typeof(window.innerWidth) == 'number',\r
+    hasElement: typeof(document.documentElement) == 'object'\r
+        && typeof(document.documentElement.clientWidth) == 'number',\r
+\r
+    menu:\r
+        document.getElementById\r
+        ? document.getElementById(floatingMenuId)\r
+        : document.all\r
+          ? document.all[floatingMenuId]\r
+          : document.layers[floatingMenuId]\r
+};\r
+\r
+floatingMenu.move = function ()\r
+{\r
+    floatingMenu.menu.style.left = floatingMenu.nextX + 'px';\r
+    floatingMenu.menu.style.top = floatingMenu.nextY + 'px';\r
+}\r
+\r
+floatingMenu.computeShifts = function ()\r
+{\r
+    var de = document.documentElement;\r
+\r
+    floatingMenu.shiftX =  \r
+        floatingMenu.hasInner  \r
+        ? pageXOffset  \r
+        : floatingMenu.hasElement  \r
+          ? de.scrollLeft  \r
+          : document.body.scrollLeft;  \r
+    if (floatingMenu.targetX < 0)\r
+    {\r
+        floatingMenu.shiftX +=\r
+            floatingMenu.hasElement\r
+            ? de.clientWidth\r
+            : document.body.clientWidth;\r
+    }\r
+\r
+    floatingMenu.shiftY = \r
+        floatingMenu.hasInner\r
+        ? pageYOffset\r
+        : floatingMenu.hasElement\r
+          ? de.scrollTop\r
+          : document.body.scrollTop;\r
+floatingMenu.shiftY = ( floatingMenu.shiftY < 76 ) ? 76 :\r
+floatingMenu.shiftY;\r
+    if (floatingMenu.targetY < -75)\r
+    {\r
+        if (floatingMenu.hasElement && floatingMenu.hasInner)\r
+        {\r
+            // Handle Opera 8 problems\r
+            floatingMenu.shiftY +=\r
+                de.clientHeight > window.innerHeight\r
+                ? window.innerHeight\r
+                : de.clientHeight\r
+        }\r
+        else\r
+        {\r
+            floatingMenu.shiftY +=\r
+                floatingMenu.hasElement\r
+                ? de.clientHeight\r
+                : document.body.clientHeight;\r
+        }\r
+    }\r
+}\r
+\r
+floatingMenu.calculateCornerX = function()\r
+{\r
+       return 0;\r
+    if (floatingMenu.targetX != 'center')\r
+        return floatingMenu.shiftX + floatingMenu.targetX;\r
+\r
+    var width = parseInt(floatingMenu.menu.offsetWidth);\r
+\r
+    var cornerX =\r
+        floatingMenu.hasElement\r
+        ? (floatingMenu.hasInner\r
+           ? pageXOffset\r
+           : document.documentElement.scrollLeft) + \r
+          (document.documentElement.clientWidth - width)/2\r
+        : document.body.scrollLeft + \r
+          (document.body.clientWidth - width)/2;\r
+    return cornerX;\r
+};\r
+\r
+floatingMenu.calculateCornerY = function()\r
+{\r
+    if (floatingMenu.targetY != 'center')\r
+        return floatingMenu.shiftY + floatingMenu.targetY;\r
+\r
+    var height = parseInt(floatingMenu.menu.offsetHeight);\r
+\r
+    // Handle Opera 8 problems\r
+    var clientHeight = \r
+        floatingMenu.hasElement && floatingMenu.hasInner\r
+        && document.documentElement.clientHeight \r
+            > window.innerHeight\r
+        ? window.innerHeight\r
+        : document.documentElement.clientHeight\r
+\r
+    var cornerY =\r
+        floatingMenu.hasElement\r
+        ? (floatingMenu.hasInner  \r
+           ? pageYOffset\r
+           : document.documentElement.scrollTop) + \r
+          (clientHeight - height)/2\r
+        : document.body.scrollTop + \r
+          (document.body.clientHeight - height)/2;\r
+    return cornerY;\r
+};\r
+\r
+floatingMenu.doFloat = function()\r
+{\r
+    // Check if reference to menu was lost due\r
+    // to ajax manipuations\r
+    if (!floatingMenu.menu)\r
+    {\r
+        menu = document.getElementById\r
+            ? document.getElementById(floatingMenuId)\r
+            : document.all\r
+              ? document.all[floatingMenuId]\r
+              : document.layers[floatingMenuId];\r
+\r
+        initSecondary();\r
+    }\r
+\r
+    var stepX, stepY;\r
+\r
+    floatingMenu.computeShifts();\r
+\r
+    var cornerX = floatingMenu.calculateCornerX();\r
+\r
+    var stepX = (cornerX - floatingMenu.nextX) * .07;\r
+    if (Math.abs(stepX) < .5)\r
+    {\r
+        stepX = cornerX - floatingMenu.nextX;\r
+    }\r
+\r
+    var cornerY = floatingMenu.calculateCornerY();\r
+\r
+    var stepY = (cornerY - floatingMenu.nextY) * .07;\r
+    if (Math.abs(stepY) < .5)\r
+    {\r
+        stepY = cornerY - floatingMenu.nextY;\r
+    }\r
+\r
+    if (Math.abs(stepX) > 0 ||\r
+        Math.abs(stepY) > 0)\r
+    {\r
+        floatingMenu.nextX += stepX;\r
+        floatingMenu.nextY += stepY;\r
+        floatingMenu.move();\r
+    }\r
+\r
+    setTimeout('floatingMenu.doFloat()', 20);\r
+};\r
+\r
+// addEvent designed by Aaron Moore\r
+floatingMenu.addEvent = function(element, listener, handler)\r
+{\r
+    if(typeof element[listener] != 'function' || \r
+       typeof element[listener + '_num'] == 'undefined')\r
+    {\r
+        element[listener + '_num'] = 0;\r
+        if (typeof element[listener] == 'function')\r
+        {\r
+            element[listener + 0] = element[listener];\r
+            element[listener + '_num']++;\r
+        }\r
+        element[listener] = function(e)\r
+        {\r
+            var r = true;\r
+            e = (e) ? e : window.event;\r
+            for(var i = element[listener + '_num'] -1; i >= 0; i--)\r
+            {\r
+                if(element[listener + i](e) == false)\r
+                    r = false;\r
+            }\r
+            return r;\r
+        }\r
+    }\r
+\r
+    //if handler is not already stored, assign it\r
+    for(var i = 0; i < element[listener + '_num']; i++)\r
+        if(element[listener + i] == handler)\r
+            return;\r
+    element[listener + element[listener + '_num']] = handler;\r
+    element[listener + '_num']++;\r
+};\r
+\r
+floatingMenu.init = function()\r
+{\r
+    floatingMenu.initSecondary();\r
+    floatingMenu.doFloat();\r
+};\r
+\r
+// Some browsers init scrollbars only after\r
+// full document load.\r
+floatingMenu.initSecondary = function()\r
+{\r
+    floatingMenu.computeShifts();\r
+    floatingMenu.nextX = floatingMenu.calculateCornerX();\r
+    floatingMenu.nextY = floatingMenu.calculateCornerY();\r
+    floatingMenu.move();\r
+}\r
+\r
+if (document.layers)\r
+    floatingMenu.addEvent(window, 'onload', floatingMenu.init);\r
+else\r
+{\r
+    floatingMenu.init();\r
+    floatingMenu.addEvent(window, 'onload',\r
+        floatingMenu.initSecondary);\r
+}
\ No newline at end of file
diff --git a/Open-ILS/web/js/ui/kcls/circ/selfcheck/payment.js b/Open-ILS/web/js/ui/kcls/circ/selfcheck/payment.js
new file mode 100644 (file)
index 0000000..a08d0ae
--- /dev/null
@@ -0,0 +1,120 @@
+function PaymentForm() {}\r
+var proto = (typeof(SelfCheckManager) == "undefined" ?\r
+    PaymentForm : SelfCheckManager).prototype;\r
+\r
+proto.drawPayFinesPage = function(patron, total, xacts, onPaymentSubmit) {\r
+    if (typeof(this.authtoken) == "undefined")\r
+        this.authtoken = patron.session;\r
+\r
+    dojo.query("span", "oils-selfck-cc-payment-summary")[0].innerHTML = total;\r
+\r
+       var d = new Date().getFullYear();\r
+    oilsSelfckCCNumber.attr('value', '');\r
+    oilsSelfckCCCVV.attr('value', '');\r
+    oilsSelfckCCMonth.attr('value', '01');\r
+    oilsSelfckCCYear.attr('value', d);\r
+    oilsSelfckCCFName.attr('value', patron.first_given_name());\r
+    oilsSelfckCCLName.attr('value', patron.family_name());\r
+       oilsSelfckCCYear.constraints.min=d;\r
+       oilsSelfckCCYear.constraints.max=d+10;\r
+\r
+    var addr = patron.billing_address() || patron.mailing_address();\r
+\r
+    if (typeof(addr) != "object") {\r
+        /* still don't have usable address? try getting better user object. */\r
+        fieldmapper.standardRequest(\r
+            ["open-ils.actor", "open-ils.actor.user.fleshed.retrieve"], {\r
+                "params": [\r
+                    patron.session, patron.id(), [\r
+                        "billing_address", "mailing_address"\r
+                    ]\r
+                ],\r
+                "async": false,\r
+                "oncomplete": function(r) {\r
+                    var usr = openils.Util.readResponse(r);\r
+                    if (usr)\r
+                        addr = usr.billing_address() || usr.mailing_address();\r
+                }\r
+            }\r
+        );\r
+    }\r
+\r
+    if (addr) {\r
+        oilsSelfckCCStreet.attr('value', addr.street1()+' '+addr.street2());\r
+        oilsSelfckCCCity.attr('value', addr.city());\r
+        oilsSelfckCCState.attr('value', addr.state());\r
+        oilsSelfckCCZip.attr('value', addr.post_code());\r
+    }\r
+\r
+    dojo.connect(oilsSelfckEditDetails, 'onChange',\r
+        function(newVal) {\r
+            dojo.forEach(\r
+                [   oilsSelfckCCFName,\r
+                    oilsSelfckCCLName,\r
+                    oilsSelfckCCStreet,\r
+                    oilsSelfckCCCity,\r
+                    oilsSelfckCCState,\r
+                    oilsSelfckCCZip\r
+                ],\r
+                function(dij) { dij.attr('disabled', !newVal); }\r
+            );\r
+        }\r
+    );\r
+\r
+\r
+    var self = this;\r
+    dojo.connect(oilsSelfckCCSubmit, 'onClick',\r
+        function() {\r
+            /* XXX better to replace this check on progressDialog with some\r
+             * kind of passed-in function to support different use cases */\r
+            if (typeof(progressDialog) != "undefined")\r
+                progressDialog.show(true);\r
+\r
+            self.sendCCPayment(patron, xacts, onPaymentSubmit);\r
+        }\r
+    );\r
+}\r
+\r
+// In this form, this code only supports global on/off credit card\r
+// payments and does not dissallow payments to transactions that started\r
+// at remote locations or transactions that have accumulated billings at\r
+// remote locations that dissalow credit card payments.\r
+// TODO add per-transaction blocks for orgs that do not support CC payments\r
+\r
+proto.sendCCPayment = function(patron, xacts, onPaymentSubmit) {\r
+       this.keepMeLoggedIn();\r
+    var args = {\r
+        userid : patron.id(),\r
+        payment_type : 'credit_card_payment',\r
+        payments : xacts,\r
+        cc_args : {\r
+            where_process : 1,\r
+            //type :  'MasterCard',//oilsSelfckCCType.attr('value'),\r
+            number : oilsSelfckCCNumber.attr('value'),\r
+            cvv2 : oilsSelfckCCCVV.attr('value'),\r
+            expire_year : oilsSelfckCCYear.attr('value'),\r
+            expire_month : oilsSelfckCCMonth.attr('value'),\r
+            billing_first : oilsSelfckCCFName.attr('value'),\r
+            billing_last : oilsSelfckCCLName.attr('value'),\r
+            billing_address : oilsSelfckCCStreet.attr('value'),\r
+            billing_city : oilsSelfckCCCity.attr('value'),\r
+            billing_state : oilsSelfckCCState.attr('value'),\r
+            billing_zip : oilsSelfckCCZip.attr('value')\r
+        }\r
+    }\r
+\r
+    var resp = fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.money.payment'],\r
+        {params : [this.authtoken, args, patron.last_xact_id()]}\r
+    );\r
+\r
+    if (typeof(progressDialog) != "undefined")\r
+        progressDialog.hide();\r
+\r
+    if (typeof(onPaymentSubmit) == "function") {\r
+        onPaymentSubmit(resp);\r
+    } else {\r
+        var evt = openils.Event.parse(resp);\r
+        if (evt) alert(evt);\r
+    }\r
+}\r
diff --git a/Open-ILS/web/js/ui/kcls/circ/selfcheck/selfcheck.js b/Open-ILS/web/js/ui/kcls/circ/selfcheck/selfcheck.js
new file mode 100644 (file)
index 0000000..0859ec1
--- /dev/null
@@ -0,0 +1,1488 @@
+dojo.require('dojo.date.locale');\r
+dojo.require('dojo.date.stamp');\r
+dojo.require('dijit.form.CheckBox');\r
+dojo.require('dijit.form.NumberSpinner');\r
+dojo.require('openils.CGI');\r
+dojo.require('openils.Util');\r
+dojo.require('openils.User');\r
+dojo.require('openils.Event');\r
+dojo.require('openils.widget.ProgressDialog');\r
+dojo.require('openils.widget.OrgUnitFilteringSelect');\r
+\r
+dojo.requireLocalization('openils.circ', 'selfcheck');\r
+var localeStrings = dojo.i18n.getLocalization('openils.circ', 'selfcheck');\r
+var selfCheckMgr;\r
+var itemsOutCirc = [];\r
+var itemsOutMod = [];\r
+var itemsOutCopy = [];\r
+var TIMEOUT = 45; // logout timer\r
+\r
+\r
+const SET_BARCODE_REGEX = 'opac.barcode_regex';\r
+const SET_PATRON_TIMEOUT = 'circ.selfcheck.patron_login_timeout';\r
+const SET_AUTO_OVERRIDE_EVENTS = 'circ.selfcheck.auto_override_checkout_events';\r
+const SET_PATRON_PASSWORD_REQUIRED = 'circ.selfcheck.patron_password_required';\r
+const SET_AUTO_RENEW_INTERVAL = 'circ.checkout_auto_renew_age';\r
+const SET_WORKSTATION_REQUIRED = 'circ.selfcheck.workstation_required';\r
+const SET_ALERT_POPUP = 'circ.selfcheck.alert.popup';\r
+const SET_ALERT_SOUND = 'circ.selfcheck.alert.sound';\r
+const SET_CC_PAYMENT_ALLOWED = 'credit.payments.allow';\r
+// This setting only comes into play if COPY_NOT_AVAILABLE is in the SET_AUTO_OVERRIDE_EVENTS list\r
+const SET_BLOCK_CHECKOUT_ON_COPY_STATUS = 'circ.selfcheck.block_checkout_on_copy_status';\r
+\r
+function SelfCheckManager() {\r
+       selfCheckMgr = this;\r
+       switchTo('step1');\r
+       \r
+       this.timer = null;\r
+    this.cgi = new openils.CGI();\r
+    this.staff = null; \r
+    this.workstation = null;\r
+    this.authtoken = null;\r
+\r
+    this.patron = null; \r
+    this.patronBarcodeRegex = null;\r
+\r
+    this.checkouts = [];\r
+    this.itemsOut = [];\r
+\r
+    // During renewals, keep track of the ID of the previous circulation. \r
+    // Previous circ is used for tracking failed renewals (for receipts).\r
+    this.prevCirc = null;\r
+\r
+    // current item barcode\r
+    this.itemBarcode = null; \r
+\r
+    // are we currently performing a renewal?\r
+    this.isRenewal = false; \r
+\r
+    // dict of org unit settings for "here"\r
+    this.orgSettings = {};\r
+\r
+    // Construct a mock checkout for debugging purposes\r
+    if(this.mockCheckouts = this.cgi.param('mock-circ')) {\r
+\r
+        this.mockCheckout = {\r
+            payload : {\r
+                record : new fieldmapper.mvr(),\r
+                copy : new fieldmapper.acp(),\r
+                circ : new fieldmapper.circ()\r
+            }\r
+        };\r
+\r
+        this.mockCheckout.payload.record.title('Jazz improvisation for guitar');\r
+        this.mockCheckout.payload.record.author('Wise, Les');\r
+        this.mockCheckout.payload.record.isbn('0634033565');\r
+        this.mockCheckout.payload.copy.barcode('123456789');\r
+        this.mockCheckout.payload.circ.renewal_remaining(1);\r
+        this.mockCheckout.payload.circ.parent_circ(1);\r
+        this.mockCheckout.payload.circ.due_date('2012-12-21');\r
+    }\r
+\r
+    this.initPrinter();\r
+}\r
+\r
+SelfCheckManager.prototype.keepMeLoggedIn = function() {\r
+       //alert(this.timer);\r
+       if(this.timer) try {clearTimeout(this.timer)} catch(e){}\r
+       this.timer = setTimeout('selfCheckMgr.logoutPatron();', TIMEOUT*1000);\r
+}\r
+\r
+/**\r
+ * Fetch the org-unit settings, initialize the display, etc.\r
+ */\r
+SelfCheckManager.prototype.init = function() {\r
+    this.staff = openils.User.user;\r
+    this.workstation = openils.User.workstation;\r
+    this.authtoken = openils.User.authtoken;\r
+    this.loadOrgSettings();\r
+\r
+    this.circTbody = dojo.byId('oils-selfck-circ-tbody');\r
+    this.itemsOutTbody = dojo.byId('oils-selfck-circ-out-tbody');\r
+\r
+    // workstation is required but none provided\r
+    if(this.orgSettings[SET_WORKSTATION_REQUIRED] && !this.workstation) {\r
+        if(confirm(dojo.string.substitute(localeStrings.WORKSTATION_REQUIRED))) {\r
+            this.registerWorkstation();\r
+        }\r
+        return;\r
+    }\r
+    \r
+    var self = this;\r
+    // connect onclick handlers to the various navigation links\r
+    var linkHandlers = {\r
+        'oils-selfck-hold-details-link' : function() { self.drawHoldsPage(true); },\r
+        'oils-selfck-view-fines-link' : function() { self.drawFinesPage(); openils.Util.show('oils-selfck-fines-tbody'); openils.Util.hide('pay_fines'); },\r
+        'oils-selfck-pay-fines-link' : function() {\r
+            switchTo('step3','step3c');\r
+                       openils.Util.hide('oils-selfck-fines-tbody');\r
+                       openils.Util.show('pay_fines');\r
+                       self.keepMeLoggedIn();\r
+            self.drawPayFinesPage(\r
+                self.patron,\r
+                self.getSelectedFinesTotal(),\r
+                self.getSelectedFineTransactions(),\r
+                function(resp) {\r
+                    var evt = openils.Event.parse(resp);\r
+                    if(evt) {\r
+                        var message = evt + '';\r
+                        if(evt.textcode == 'CREDIT_PROCESSOR_DECLINED_TRANSACTION' && evt.payload)\r
+                            message += '\n' + evt.payload.error_message;\r
+                        self.handleAlert(message, true, 'payment-failure');\r
+                        return;\r
+                    }\r
+                                       self.patron.last_xact_id(resp.last_xact_id);\r
+                    self.printPaymentReceipt(\r
+                        resp,\r
+                        function() {\r
+                            self.updateFinesSummary();\r
+                            self.drawFinesPage();\r
+                        }\r
+                    );\r
+                }\r
+            );\r
+        },\r
+        //'oils-selfck-nav-home' : function() { self.drawCircPage(); },\r
+        'oils-selfck-nav-logout' : function() { self.logoutPatron(); },\r
+        'oils-selfck-nav-logout-print' : function() { self.logoutPatron(true); },\r
+        'oils-selfck-items-out-details-link' : function() { self.drawItemsOutPage(); },\r
+        //'oils-selfck-print-list-link' : function() { self.printList(); }\r
+    }\r
+\r
+    for(var id in linkHandlers) {\r
+               //var obj1 = dojo.byId(id);\r
+               //obj1.onclick = linkHandlers[id];\r
+        dojo.connect(dojo.byId(id), 'onclick', linkHandlers[id]);\r
+       }\r
+\r
+\r
+    if(this.cgi.param('patron')) {\r
+        \r
+        // Patron barcode via cgi param.  Mainly used for debugging and\r
+        // only works if password is not required by policy\r
+        this.loginPatron(this.cgi.param('patron'));\r
+\r
+    } else {\r
+        this.drawLoginPage();\r
+    }\r
+\r
+    /**\r
+     * To test printing, pass a URL param of 'testprint'.  The value for the param\r
+     * should be a JSON string like so:  [{circ:<circ_id>}, ...]\r
+     */\r
+    var testPrint = this.cgi.param('testprint');\r
+    if(testPrint) {\r
+        this.checkouts = JSON2js(testPrint);\r
+        this.printSessionReceipt();\r
+        this.checkouts = [];\r
+    }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.getSelectedFinesTotal = function() {\r
+    var total = 0;\r
+    dojo.forEach(\r
+        dojo.query("[name=selector]", this.finesTbody),\r
+        function(input) {\r
+            if(input.checked)\r
+                total += Number(input.balance_owed);\r
+        }\r
+    );\r
+    return total.toFixed(2);\r
+};\r
+\r
+SelfCheckManager.prototype.getSelectedFineTransactions = function() {\r
+    return dojo.query("[name=selector]", this.finesTbody).\r
+        filter(function (o) { return o.checked }).\r
+        map(\r
+            function (o) {\r
+                return [\r
+                    o.getAttribute("xact"),\r
+                    Number(o.balance_owed).toFixed(2)\r
+                ];\r
+            }\r
+        );\r
+};\r
+\r
+/**\r
+ * Registers a new workstion\r
+ */\r
+SelfCheckManager.prototype.registerWorkstation = function() {\r
+    \r
+    oilsSelfckWsDialog.show();\r
+\r
+    new openils.User().buildPermOrgSelector(\r
+        'REGISTER_WORKSTATION', \r
+        oilsSelfckWsLocSelector, \r
+        this.staff.home_ou()\r
+    );\r
+\r
+\r
+    var self = this;\r
+    dojo.connect(oilsSelfckWsSubmit, 'onClick', \r
+\r
+        function() {\r
+            oilsSelfckWsDialog.hide();\r
+            var name = oilsSelfckWsLocSelector.attr('displayedValue') + '-' + oilsSelfckWsName.attr('value');\r
+\r
+            var res = fieldmapper.standardRequest(\r
+                ['open-ils.actor', 'open-ils.actor.workstation.register'],\r
+                { params : [\r
+                        self.authtoken, name, oilsSelfckWsLocSelector.attr('value')\r
+                    ]\r
+                }\r
+            );\r
+\r
+            if(evt = openils.Event.parse(res)) {\r
+                if(evt.textcode == 'WORKSTATION_NAME_EXISTS') {\r
+                    if(confirm(localeStrings.WORKSTATION_EXISTS)) {\r
+                        location.href = location.href.replace(/\?.*/, '') + '?ws=' + name;\r
+                    } else {\r
+                        self.registerWorkstation();\r
+                    }\r
+                    return;\r
+                } else {\r
+                    alert(evt);\r
+                }\r
+            } else {\r
+                location.href = location.href.replace(/\?.*/, '') + '?ws=' + name;\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+/**\r
+ * Loads the org unit settings\r
+ */\r
+SelfCheckManager.prototype.loadOrgSettings = function() {\r
+\r
+    var settings = fieldmapper.aou.fetchOrgSettingBatch(\r
+        this.staff.ws_ou(), [\r
+            SET_BARCODE_REGEX,\r
+            SET_PATRON_TIMEOUT,\r
+            SET_ALERT_POPUP,\r
+            SET_ALERT_SOUND,\r
+            SET_AUTO_OVERRIDE_EVENTS,\r
+            SET_BLOCK_CHECKOUT_ON_COPY_STATUS,\r
+            SET_PATRON_PASSWORD_REQUIRED,\r
+            SET_AUTO_RENEW_INTERVAL,\r
+            SET_WORKSTATION_REQUIRED,\r
+            SET_CC_PAYMENT_ALLOWED\r
+        ]\r
+    );\r
+\r
+    for(k in settings) {\r
+        if(settings[k])\r
+            this.orgSettings[k] = settings[k].value;\r
+    }\r
+\r
+    if(settings[SET_BARCODE_REGEX]) \r
+        this.patronBarcodeRegex = new RegExp(settings[SET_BARCODE_REGEX].value);\r
+}\r
+\r
+SelfCheckManager.prototype.drawLoginPage = function() {\r
+    var self = this;\r
+    var bcHandler = function(barcode) {\r
+        // handle patron barcode entry\r
+\r
+        if(self.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) {\r
+            \r
+            // password is required.  wire up the scan box to read it\r
+            self.updateScanBox({\r
+                msg : 'Please enter your password', // TODO i18n \r
+                handler : function(pw) { self.loginPatron(barcode, pw); },\r
+                password : true\r
+            });\r
+\r
+        } else {\r
+            // password is not required, go ahead and login\r
+            self.loginPatron(barcode);\r
+        }\r
+    };\r
+\r
+    this.updateScanBox({\r
+        msg : 'Please log in with your library barcode.', // TODO\r
+        handler : bcHandler\r
+    });\r
+       \r
+       var txtBox = (dojo.byId('step2').style.display=='none') ? 'patron-login-username' : 'patron-login-password';\r
+       try{var a=dojo.byId(txtBox);a.focus();a.select();}catch(e){}\r
+}\r
+\r
+/**\r
+ * Login the patron.  \r
+ */\r
+SelfCheckManager.prototype.loginPatron = function(barcode, passwd) {\r
+       \r
+    //if(this.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) { // password always reqired, per KCLS - fail safe\r
+        if(!passwd) {\r
+            // would only happen in dev/debug mode when using the patron= param\r
+            alert('password required by org setting.  remove patron= from URL'); \r
+            return;\r
+        }\r
+\r
+        // patron password is required.  Verify it.\r
+\r
+        var res = fieldmapper.standardRequest(\r
+            ['open-ils.actor', 'open-ils.actor.verify_user_password'],\r
+            {params : [this.authtoken, barcode, null, hex_md5(passwd)]}\r
+        );\r
+\r
+        if(res == 0) {\r
+            // user-not-found results in login failure\r
+            this.handleAlert(\r
+                dojo.string.substitute(localeStrings.LOGIN_FAILED, [barcode]),\r
+                false, 'login-failure'\r
+            );\r
+            this.drawLoginPage();\r
+                       openils.Util.show('back_to_login');\r
+            return;\r
+        }\r
+    //} \r
+\r
+    // retrieve the fleshed user by barcode\r
+    this.patron = fieldmapper.standardRequest(\r
+        ['open-ils.actor', 'open-ils.actor.user.fleshed.retrieve_by_barcode'],\r
+        {params : [this.authtoken, barcode]}\r
+    );\r
+\r
+    var evt = openils.Event.parse(this.patron);\r
+    if(evt) {\r
+        this.handleAlert(\r
+            dojo.string.substitute(localeStrings.LOGIN_FAILED, [barcode]),\r
+            false, 'login-failure'\r
+        );\r
+        this.drawLoginPage();\r
+               openils.Util.show('back_to_login');\r
+\r
+    } else {\r
+\r
+        //this.handleAlert('', true, 'login-success');\r
+        dojo.byId('user_name').innerHTML = \r
+            dojo.string.substitute(localeStrings.WELCOME_BANNER, [this.patron.first_given_name()]);\r
+               dojo.byId('oils-selfck-status-div').innerHTML = '';\r
+               dojo.byId('oils-selfck-status-div2').innerHTML = '';\r
+               dojo.byId('oils-selfck-status-div3').innerHTML = '';\r
+               openils.Util.hide('back_to_login');\r
+        this.drawCircPage();\r
+    }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.handleAlert = function(message, shouldPopup, sound) {\r
+    console.log("Handling alert " + message);\r
+\r
+    dojo.byId('oils-selfck-status-div').innerHTML = message;\r
+       if(!this.patron){\r
+               dojo.byId('oils-selfck-status-div2').innerHTML = message;\r
+               dojo.byId('oils-selfck-status-div3').innerHTML = message;\r
+       }\r
+       \r
+    if(shouldPopup && this.orgSettings[SET_ALERT_POPUP]) \r
+        alert(message);\r
+\r
+    if(this.orgSettings[SET_ALERT_SOUND])\r
+        openils.Util.playAudioUrl(SelfCheckManager.audioConfig[sound]);\r
+}\r
+\r
+\r
+/**\r
+ * Manages the main input box\r
+ * @param msg The context message to display with the box\r
+ * @param clearOnly Don't update the context message, just clear the value and re-focus\r
+ * @param handler Optional "on-enter" handler.  \r
+ */\r
+SelfCheckManager.prototype.updateScanBox = function(args) {\r
+    args = args || {};\r
+\r
+    if(args.select) {\r
+        selfckScanBox.domNode.select();\r
+    } else {\r
+        selfckScanBox.attr('value', '');\r
+    }\r
+\r
+    if(args.password) {\r
+        selfckScanBox.domNode.setAttribute('type', 'password');\r
+    } else {\r
+        selfckScanBox.domNode.setAttribute('type', '');\r
+    }\r
+\r
+    if(args.value)\r
+        selfckScanBox.attr('value', args.value);\r
+\r
+    if(args.msg) \r
+        dojo.byId('oils-selfck-scan-text').innerHTML = args.msg;\r
+\r
+    if(selfckScanBox._lastHandler && (args.handler || args.clearHandler)) {\r
+        dojo.disconnect(selfckScanBox._lastHandler);\r
+    }\r
+\r
+    if(args.handler) {\r
+\r
+        selfckScanBox._lastHandler = dojo.connect(\r
+            selfckScanBox, \r
+            'onKeyDown', \r
+            function(e) {\r
+                if(e.keyCode != dojo.keys.ENTER) \r
+                    return;\r
+                args.handler(selfckScanBox.attr('value'));\r
+            }\r
+        );\r
+    }\r
+\r
+    selfckScanBox.focus();\r
+}\r
+\r
+/**\r
+ *  Sets up the checkout/renewal interface\r
+ */\r
+SelfCheckManager.prototype.drawCircPage = function() {\r
+       this.keepMeLoggedIn();\r
+    openils.Util.show('oils-selfck-circ-tbody', 'table-row-group');\r
+       switchTo('step3');\r
+\r
+    var self = this;\r
+    this.updateScanBox({\r
+        msg : 'Please enter an item barcode', // TODO i18n\r
+        handler : function(barcode) { \r
+               openils.Util.show('oils-selfck-fines-tbody'); \r
+               openils.Util.hide('pay_fines'); switchTo('step3'); \r
+               self.checkout(barcode); }\r
+    });\r
+\r
+    if(!this.circTemplate)\r
+        this.circTemplate = this.circTbody.removeChild(dojo.byId('oils-selfck-circ-row'));\r
+\r
+    // fines summary\r
+    this.updateFinesSummary();\r
+\r
+    // holds summary\r
+    this.updateHoldsSummary();\r
+\r
+    // items out summary\r
+    this.updateCircSummary();\r
+\r
+    // render mock checkouts for debugging?\r
+    if(this.mockCheckouts) {\r
+        for(var i in [1,2,3]) \r
+            this.displayCheckout(this.mockCheckout, 'checkout');\r
+    }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.updateFinesSummary = function() {\r
+    var self = this; \r
+\r
+    // fines summary\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.actor', 'open-ils.actor.user.fines.summary'],\r
+        {   async : true,\r
+            params : [this.authtoken, this.patron.id()],\r
+            oncomplete : function(r) {\r
+                var summary = openils.Util.readResponse(r);\r
+                               var finesSum = dojo.byId('acct_fines');\r
+                               var bal = summary.balance_owed();\r
+                               var bal2 = parseFloat(bal);\r
+                               \r
+                               if(bal2>0) {finesSum.style.color="red"; openils.Util.show('oils-selfck-pay-fines-link');}\r
+                finesSum.innerHTML = dojo.string.substitute(localeStrings.TOTAL_FINES_ACCOUNT, [bal2.toFixed(2)]);\r
+                self.creditPayableBalance = bal2+'';\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawItemsOutPage = function() {\r
+       this.keepMeLoggedIn();\r
+       switchTo('step3','step3d');\r
+\r
+       if(!this.outTemplate)\r
+        this.outTemplate = this.itemsOutTbody.removeChild(dojo.byId('oils-selfck-circ-out-row'));\r
+    while(this.itemsOutTbody.childNodes[0])\r
+        this.itemsOutTbody.removeChild(this.itemsOutTbody.childNodes[0]);\r
+\r
+    progressDialog.show(true);\r
+    var self = this;\r
+       \r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.actor.user.checked_out.atomic'],\r
+        {\r
+            async : true,\r
+            params : [this.authtoken, this.patron.id()],\r
+            oncomplete : function(r) {\r
+                var resp = openils.Util.readResponse(r);\r
+\r
+                var circs = resp.sort(\r
+                    function(a, b) {\r
+                        if(a.circ.due_date() > b.circ.due_date())\r
+                            return -1;\r
+                        return 1;\r
+                    }\r
+                );\r
+\r
+                self.itemsOut = [];\r
+                dojo.forEach(circs,\r
+                    function(circ) {\r
+                        self.itemsOut.push(circ.circ.id());\r
+                        handleCheckedItems(circ);\r
+                    }\r
+                );\r
+                               progressDialog.hide();\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+function handleCheckedItems(circ) {\r
+       var self = selfCheckMgr;\r
+       var row = self.outTemplate.cloneNode(true);\r
+       \r
+       self.byName(row,'barcode').innerHTML = circ.copy.barcode();\r
+       self.byName(row,'title').innerHTML = circ.record.title();\r
+       self.byName(row,'author').innerHTML = circ.record.author();\r
+       if(dojo.date.stamp.fromISOString(circ.circ.due_date())<(new Date())) self.byName(row,'due_date').style.color="red";\r
+       self.byName(row,'due_date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(circ.circ.due_date()), {selector: 'date', fullYear: true});\r
+       self.byName(row,'format').innerHTML = circ.record.types_of_resource()[0];\r
+       \r
+       self.itemsOutTbody.appendChild(row);\r
+}\r
+\r
+SelfCheckManager.prototype.goToTab = function(name) {\r
+    this.tabName = name;\r
+\r
+    openils.Util.hide('oils-selfck-fines-page');\r
+    openils.Util.hide('oils-selfck-payment-page');\r
+    openils.Util.hide('oils-selfck-holds-page');\r
+    openils.Util.hide('oils-selfck-circ-page');\r
+    openils.Util.hide('oils-selfck-pay-fines-link');\r
+    \r
+    switch(name) {\r
+        case 'checkout':\r
+            openils.Util.show('oils-selfck-circ-page');\r
+            break;\r
+        case 'items_out':\r
+            openils.Util.show('oils-selfck-circ-page');\r
+            break;\r
+        case 'holds':\r
+            openils.Util.show('oils-selfck-holds-page');\r
+            break;\r
+        case 'fines':\r
+            openils.Util.show('oils-selfck-fines-page');\r
+            break;\r
+        case 'payment':\r
+            openils.Util.show('oils-selfck-payment-page');\r
+            break;\r
+    }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.printList = function(which) {\r
+       this.keepMeLoggedIn();\r
+    switch(which) {\r
+        case 'checkout':\r
+            this.printSessionReceipt();\r
+            break;\r
+        case 'items_out':\r
+            this.printItemsOutReceipt();\r
+            break;\r
+        case 'holds':\r
+            this.printHoldsReceipt();\r
+            break;\r
+        case 'fines':\r
+            this.printFinesReceipt();\r
+            break;\r
+    }\r
+}\r
+\r
+SelfCheckManager.prototype.updateHoldsSummary = function() {\r
+    if(!this.holdsSummary) {\r
+        var summary = fieldmapper.standardRequest(\r
+            ['open-ils.circ', 'open-ils.circ.holds.user_summary'],\r
+            {params : [this.authtoken, this.patron.id()]}\r
+        );\r
+\r
+        this.holdsSummary = {};\r
+        this.holdsSummary.ready = Number(summary['4']);\r
+        this.holdsSummary.total = 0;\r
+\r
+        for(var i in summary)\r
+            this.holdsSummary.total += Number(summary[i]);\r
+    }\r
+\r
+    dojo.byId('oils-selfck-holds-total').innerHTML =dojo.string.substitute("${0}) Item"+(this.holdsSummary.total==1?"":"s"),[this.holdsSummary.total]);\r
+    dojo.byId('oils-selfck-holds-ready').innerHTML =dojo.string.substitute("${0}) Item"+(this.holdsSummary.ready==1?"":"s"),[this.holdsSummary.ready]);\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.updateCircSummary = function(increment) {\r
+    if(!this.circSummary) {\r
+\r
+        var summary = fieldmapper.standardRequest(\r
+            ['open-ils.actor', 'open-ils.actor.user.checked_out.count'],\r
+            {params : [this.authtoken, this.patron.id()]}\r
+        );\r
+\r
+        this.circSummary = {\r
+            total : Number(summary.out) + Number(summary.overdue),\r
+            overdue : Number(summary.overdue),\r
+            session : 0\r
+        };\r
+    }\r
+\r
+    if(increment) {\r
+        // local checkout occurred.  Add to the total and the session.\r
+        this.circSummary.total += 1;\r
+        this.circSummary.session += 1;\r
+    }\r
+\r
+    dojo.byId('oils-selfck-circ-account-total').innerHTML = dojo.string.substitute("${0}) Item"+(this.circSummary.total==1?"":"s"), [this.circSummary.total]);\r
+\r
+    /*\r
+       dojo.byId('oils-selfck-circ-session-total').innerHTML = \r
+        dojo.string.substitute(\r
+            localeStrings.TOTAL_ITEMS_SESSION, \r
+            [this.circSummary.session]\r
+        );\r
+       */\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawHoldsPage = function(bool) {\r
+       this.keepMeLoggedIn();\r
+       if(bool) switchTo('step3','step3f'); else switchTo('step3','step3e');\r
+\r
+    this.holdTbody = dojo.byId('oils-selfck-hold-tbody');\r
+       this.readyTbody = dojo.byId('oils-selfck-rdy-tbody');\r
+       if(!this.readyTemplate)\r
+        this.readyTemplate = this.readyTbody.removeChild(dojo.byId('oils-selfck-rdy-row'));\r
+    if(!this.holdTemplate)\r
+        this.holdTemplate = this.holdTbody.removeChild(dojo.byId('oils-selfck-hold-row'));\r
+    while(this.holdTbody.childNodes[0])\r
+        this.holdTbody.removeChild(this.holdTbody.childNodes[0]);\r
+       while(this.readyTbody.childNodes[0])\r
+        this.readyTbody.removeChild(this.readyTbody.childNodes[0]);\r
+\r
+    progressDialog.show(true);\r
+\r
+    var self = this;\r
+    fieldmapper.standardRequest( // fetch the hold IDs\r
+\r
+        ['open-ils.circ', 'open-ils.circ.holds.id_list.retrieve'],\r
+        {   async : true,\r
+            params : [this.authtoken, this.patron.id()],\r
+\r
+            oncomplete : function(r) { \r
+                var ids = openils.Util.readResponse(r);\r
+                if(!ids || ids.length == 0) {\r
+                    progressDialog.hide();\r
+                    return;\r
+                }\r
+\r
+                fieldmapper.standardRequest( // fetch the hold objects with fleshed details\r
+                    ['open-ils.circ', 'open-ils.circ.hold.details.batch.retrieve'],\r
+                    {   async : true,\r
+                        params : [self.authtoken, ids],\r
+\r
+                        onresponse : function(rr) {\r
+                                                       progressDialog.hide(); \r
+                            self.drawHolds(openils.Util.readResponse(rr));\r
+                        }\r
+                    }\r
+                );\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+/**\r
+ * Fetch and add a single hold to the list of holds\r
+ */\r
+SelfCheckManager.prototype.drawHolds = function(holds) {\r
+       //this.keepMeLoggedIn();\r
+    this.holds = holds;\r
+    progressDialog.hide();\r
+       \r
+       var data = holds;\r
+       if(!data) return;\r
+       var row = this.holdTemplate.cloneNode(true);\r
+       var row2 = this.readyTemplate.cloneNode(true);\r
+\r
+       //if(data.mvr.isbn()) {\r
+       //    this.byName(row, 'jacket').setAttribute('src', '/opac/extras/ac/jacket/small/' + data.mvr.isbn());\r
+       //}\r
+       \r
+       if(data.status == 4) {\r
+               this.byName(row2, 'title').innerHTML = data.mvr.title();\r
+               this.byName(row2, 'format').innerHTML = data.mvr.types_of_resource()[0];\r
+               this.byName(row2, 'lib').innerHTML = fieldmapper.aou.findOrgUnit(data.hold.pickup_lib()).name();\r
+               if(dojo.date.stamp.fromISOString(data.hold.capture_time())<(new Date())) this.byName(row2, 'date').style.color="red";\r
+               this.byName(row2, 'date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(data.hold.capture_time()), {selector: 'date', fullYear: true});\r
+               this.readyTbody.appendChild(row2);\r
+       } else {\r
+\r
+               this.byName(row, 'title').innerHTML = data.mvr.title();\r
+               this.byName(row, 'author').innerHTML = data.mvr.author();\r
+               this.byName(row, 'format').innerHTML = data.mvr.types_of_resource()[0];\r
+\r
+                       // hold is still pending\r
+               this.byName(row, 'status').innerHTML = dojo.string.substitute(localeStrings.HOLD_STATUS_WAITING,[data.queue_position, data.potential_copies]);\r
+               this.holdTbody.appendChild(row);\r
+       }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawFinesPage = function() {\r
+       this.keepMeLoggedIn();\r
+    // TODO add option to hid scanBox\r
+    // this.updateScanBox(...)\r
+\r
+    //this.goToTab('fines');\r
+       switchTo('step3','step3c');\r
+    progressDialog.show(true);\r
+\r
+    //if(this.creditPayableBalance > 0 && this.orgSettings[SET_CC_PAYMENT_ALLOWED])\r
+    //  openils.Util.show('oils-selfck-pay-fines-link', 'inline');\r
+    \r
+\r
+    this.finesTbody = dojo.byId('oils-selfck-fines-tbody');\r
+    if(!this.finesTemplate)\r
+        this.finesTemplate = this.finesTbody.removeChild(dojo.byId('oils-selfck-fines-row'));\r
+    while(this.finesTbody.childNodes[0])\r
+        this.finesTbody.removeChild(this.finesTbody.childNodes[0]);\r
+\r
+/*\r
+    // when user clicks on a selector checkbox, update the total owed\r
+    var updateSelected = function() {\r
+        var total = 0;\r
+        dojo.forEach(\r
+            dojo.query('[name=selector]', this.finesTbody),\r
+            function(input) {\r
+                if(input.checked)\r
+                    total += Number(input.getAttribute('balance_owed'));\r
+            }\r
+        );\r
+\r
+        total = total.toFixed(2);\r
+        dojo.byId('oils-selfck-selected-total').innerHTML = \r
+            dojo.string.substitute(localeStrings.TOTAL_FINES_SELECTED, [total]);\r
+    }\r
+\r
+    // wire up the batch on/off selector\r
+    var sel = dojo.byId('oils-selfck-fines-selector');\r
+    sel.onchange = function() {\r
+        dojo.forEach(\r
+            dojo.query('[name=selector]', this.finesTbody),\r
+            function(input) {\r
+                input.checked = sel.checked;\r
+            }\r
+        );\r
+    };\r
+*/\r
+    var self = this;\r
+    var handler = function(dataList) {\r
+\r
+        self.finesCount = dataList.length;\r
+        self.finesData = dataList;\r
+\r
+        for(var i in dataList) {\r
+\r
+            var data = dataList[i];\r
+            var row = self.finesTemplate.cloneNode(true);\r
+            var type = data.transaction.xact_type();\r
+\r
+            if(type == 'circulation') {\r
+                self.byName(row, 'title').innerHTML = data.record.title();\r
+                               if(dojo.date.stamp.fromISOString(data.circ.due_date())<(new Date())) self.byName(row, 'due_date').style.color="red";\r
+                self.byName(row, 'due_date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(data.circ.due_date()), {selector: 'date', fullYear: true});\r
+                               self.byName(row, 'date_return').innerHTML = (data.circ.checkin_time())?dojo.date.locale.format(dojo.date.stamp.fromISOString(data.circ.checkin_time()), {selector: 'date', fullYear: true}):"";\r
+\r
+            } else if(type == 'grocery') {\r
+                self.byName(row, 'title').innerHTML = (data.transaction.last_billing_type())?("Miscellaneous - "+data.transaction.last_billing_type()):"Miscellaneous"; // Go ahead and head off any confusion around "grocery".  TODO i18n\r
+            }\r
+\r
+            //self.byName(row, 'total_owed').innerHTML = data.transaction.total_owed();\r
+            //self.byName(row, 'total_paid').innerHTML = data.transaction.total_paid();\r
+            self.byName(row, 'balance').innerHTML = data.transaction.balance_owed();\r
+                       self.byName(row, 'selector').balance_owed = data.transaction.balance_owed();\r
+                       self.byName(row, 'selector').setAttribute('xact', data.transaction.id());\r
+/*\r
+            // row selector\r
+            var selector = self.byName(row, 'selector')\r
+            selector.onchange = updateSelected;\r
+            selector.setAttribute('xact', data.transaction.id());\r
+            selector.setAttribute('balance_owed', data.transaction.balance_owed());\r
+            selector.checked = true;\r
+*/\r
+            self.finesTbody.appendChild(row);\r
+        }\r
+\r
+        //updateSelected();\r
+    }\r
+\r
+\r
+    fieldmapper.standardRequest( \r
+        ['open-ils.actor', 'open-ils.actor.user.transactions.have_balance.fleshed'],\r
+        {   async : true,\r
+            params : [this.authtoken, this.patron.id()],\r
+            oncomplete : function(r) { \r
+                progressDialog.hide();\r
+                handler(openils.Util.readResponse(r));\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+SelfCheckManager.prototype.checkin = function(barcode, abortTransit) {\r
+    var resp = fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.transit.abort'],\r
+        {params : [this.authtoken, {barcode : barcode}]}\r
+    );\r
+\r
+    // resp == 1 on success\r
+    if(openils.Event.parse(resp))\r
+        return false;\r
+\r
+    var resp = fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.checkin.override'],\r
+        {params : [\r
+            this.authtoken, {\r
+                patron_id : this.patron.id(),\r
+                copy_barcode : barcode,\r
+                noop : true\r
+            }\r
+        ]}\r
+    );\r
+\r
+    if(!resp.length) resp = [resp];\r
+    for(var i = 0; i < resp.length; i++) {\r
+        var tc = openils.Event.parse(resp[i]).textcode;\r
+        if(tc == 'SUCCESS' || tc == 'NO_CHANGE') {\r
+            continue;\r
+        } else {\r
+            return false;\r
+        }\r
+    }\r
+\r
+    return true;\r
+}\r
+\r
+/**\r
+ * Check out a single item.  If the item is already checked \r
+ * out to the patron, redirect to renew()\r
+ */\r
+SelfCheckManager.prototype.checkout = function(barcode, override) {\r
+       this.keepMeLoggedIn();\r
+    this.prevCirc = null;\r
+\r
+    if(!barcode) {\r
+        this.updateScanbox(null, true);\r
+        return;\r
+    }\r
+\r
+    if(this.mockCheckouts) {\r
+        // if we're in mock-checkout mode, just insert another\r
+        // fake circ into the table and get out of here.\r
+        this.displayCheckout(this.mockCheckout, 'checkout');\r
+        return;\r
+    }\r
+\r
+    // TODO see if it's a patron barcode\r
+    // TODO see if this item has already been checked out in this session\r
+\r
+    var method = 'open-ils.circ.checkout.full';\r
+    if(override) method += '.override';\r
+\r
+    console.log("Checkout out item " + barcode + " with method " + method);\r
+\r
+    var result = fieldmapper.standardRequest(\r
+        ['open-ils.circ', method],\r
+        {params: [\r
+            this.authtoken, {\r
+                patron_id : this.patron.id(),\r
+                copy_barcode : barcode\r
+            }\r
+        ]}\r
+    );\r
+\r
+    var stat = this.handleXactResult('checkout', barcode, result);\r
+\r
+    if(stat.override) {\r
+        this.checkout(barcode, true);\r
+    } else if(stat.doOver) {\r
+        this.checkout(barcode);\r
+    } else if(stat.renew) {\r
+        this.renew(barcode);\r
+    }\r
+}\r
+\r
+SelfCheckManager.prototype.failPartMessage = function(result) {\r
+    if (result.payload && result.payload.fail_part) {\r
+        var stringKey = "FAIL_PART_" +\r
+            result.payload.fail_part.replace(/\./g, "_");\r
+        return localeStrings[stringKey];\r
+    } else {\r
+        return null;\r
+    }\r
+}\r
+\r
+SelfCheckManager.prototype.handleXactResult = function(action, item, result) {\r
+    var displayText = '';\r
+\r
+    // If true, the display message is important enough to pop up.  Whether or not\r
+    // an alert() actually occurs, depends on org unit settings\r
+    var popup = false;  \r
+    var sound = ''; // sound file reference\r
+    var payload = result.payload || {};\r
+    var overrideEvents = this.orgSettings[SET_AUTO_OVERRIDE_EVENTS];\r
+    var blockStatuses = this.orgSettings[SET_BLOCK_CHECKOUT_ON_COPY_STATUS];\r
+       result.payload = payload;\r
+        \r
+    if(result.textcode == 'NO_SESSION') {\r
+\r
+        return this.logoutStaff();\r
+\r
+    } else if(result.textcode == 'SUCCESS') {\r
+\r
+        if(action == 'checkout') {\r
+\r
+            displayText = dojo.string.substitute(localeStrings.CHECKOUT_SUCCESS, [item]);\r
+            this.displayCheckout(result, 'checkout');\r
+\r
+            if(payload.holds_fulfilled && payload.holds_fulfilled.length) {\r
+                // A hold was fulfilled, update the hold numbers in the circ summary\r
+                console.log("fulfilled hold " + payload.holds_fulfilled + " during checkout");\r
+                this.holdsSummary = null;\r
+                this.updateHoldsSummary();\r
+            }\r
+\r
+            this.updateCircSummary(true);\r
+\r
+        } else if(action == 'renew') {\r
+\r
+            displayText = dojo.string.substitute(localeStrings.RENEW_SUCCESS, [item]);\r
+            this.displayCheckout(result, 'renew');\r
+        }\r
+\r
+        this.checkouts.push({circ : result.payload.circ.id()});\r
+        sound = 'checkout-success';\r
+        this.updateScanBox();\r
+\r
+    } else if(result.textcode == 'OPEN_CIRCULATION_EXISTS' && action == 'checkout') {\r
+\r
+        // Server says the item is already checked out.  If it's checked out to the\r
+        // current user, we may need to renew it.  \r
+\r
+        if(payload.old_circ) { \r
+\r
+            /*\r
+            old_circ refers to the previous checkout IFF it's for the same user. \r
+            If no auto-renew interval is not defined, assume we should renew it\r
+            If an auto-renew interval is defined and the payload comes back with\r
+            auto_renew set to true, do the renewal.  Otherwise, let the patron know\r
+            the item is already checked out to them.  */\r
+\r
+            if( !this.orgSettings[SET_AUTO_RENEW_INTERVAL] ||\r
+                (this.orgSettings[SET_AUTO_RENEW_INTERVAL] && payload.auto_renew) ) {\r
+                this.prevCirc = payload.old_circ.id();\r
+                return { renew : true };\r
+            }\r
+\r
+            popup = false;\r
+            sound = 'checkout-failure';\r
+            displayText = dojo.string.substitute(localeStrings.ALREADY_OUT, [item]);\r
+\r
+        } else {\r
+\r
+            if( // copy is marked lost.  if configured to do so, check it in and try again.\r
+                result.payload.copy && \r
+                result.payload.copy.status() == /* LOST */ 3 &&\r
+                overrideEvents && overrideEvents.length &&\r
+                overrideEvents.indexOf('COPY_STATUS_LOST') != -1) {\r
+\r
+                    if(this.checkin(item)) {\r
+                        return { doOver : true };\r
+                    }\r
+            }\r
+\r
+            \r
+            // item is checked out to some other user\r
+            popup = false;\r
+            sound = 'checkout-failure';\r
+            displayText = dojo.string.substitute(localeStrings.OPEN_CIRCULATION_EXISTS, [item]);\r
+        }\r
+\r
+        this.updateScanBox();\r
+\r
+    } else {\r
+\r
+    \r
+        if(overrideEvents && overrideEvents.length) {\r
+            \r
+            // see if the events we received are all in the list of\r
+            // events to override\r
+    \r
+            if(!result.length) result = [result];\r
+    \r
+            var override = true;\r
+            for(var i = 0; i < result.length; i++) {\r
+\r
+                var match = overrideEvents.filter(function(e) { return (e == result[i].textcode); })[0];\r
+\r
+                if(!match) {\r
+                    override = false;\r
+                    break;\r
+                }\r
+\r
+                if(result[i].textcode == 'COPY_NOT_AVAILABLE' && blockStatuses && blockStatuses.length) {\r
+\r
+                    var stat = result[i].payload.status(); // copy status\r
+                    if(typeof stat == 'object') stat = stat.id();\r
+\r
+                    var match2 = blockStatuses.filter(function(e) { return (e == stat); })[0];\r
+\r
+                    if(match2) { // copy is in a blocked status\r
+                        override = false;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if(result[i].textcode == 'COPY_IN_TRANSIT') {\r
+                    // to override a transit, we have to abort the transit and check it in first\r
+                    if(this.checkin(item, true)) {\r
+                        return { doOver : true };\r
+                    } else {\r
+                        override = false;\r
+                    }\r
+                }\r
+            }\r
+\r
+            if(override) \r
+                return { override : true };\r
+        }\r
+    \r
+        this.updateScanBox();\r
+        popup = false;\r
+        sound = 'checkout-failure';\r
+\r
+        if(action == 'renew')\r
+            this.checkouts.push({circ : this.prevCirc, renewal_failure : true});\r
+\r
+        if(result.length) \r
+            result = result[0];\r
+\r
+        switch(result.textcode) {\r
+\r
+            // TODO custom handler for blocking penalties\r
+\r
+            case 'MAX_RENEWALS_REACHED' :\r
+                displayText = dojo.string.substitute(\r
+                    localeStrings.MAX_RENEWALS, [item]);\r
+                break;\r
+\r
+            case 'ITEM_NOT_CATALOGED' :\r
+                displayText = dojo.string.substitute(\r
+                    localeStrings.ITEM_NOT_CATALOGED, [item]);\r
+                break;\r
+\r
+            case 'OPEN_CIRCULATION_EXISTS' :\r
+                displayText = dojo.string.substitute(\r
+                    localeStrings.OPEN_CIRCULATION_EXISTS, [item]);\r
+\r
+                break;\r
+\r
+            default:\r
+                console.error('Unhandled event ' + result.textcode);\r
+\r
+                if (!(displayText = this.failPartMessage(result))) {\r
+                    if (action == 'checkout' || action == 'renew') {\r
+                        displayText = dojo.string.substitute(\r
+                            localeStrings.GENERIC_CIRC_FAILURE, [item]);\r
+                    } else {\r
+                        displayText = dojo.string.substitute(\r
+                            localeStrings.UNKNOWN_ERROR, [result.textcode]);\r
+                    }\r
+                }\r
+        }\r
+    }\r
+\r
+    this.handleAlert(displayText, popup, sound);\r
+    return {};\r
+}\r
+\r
+\r
+/**\r
+ * Renew an item\r
+ */\r
+SelfCheckManager.prototype.renew = function(barcode, override) {\r
+\r
+    var method = 'open-ils.circ.renew';\r
+    if(override) method += '.override';\r
+\r
+    console.log("Renewing item " + barcode + " with method " + method);\r
+\r
+    var result = fieldmapper.standardRequest(\r
+        ['open-ils.circ', method],\r
+        {params: [\r
+            this.authtoken, {\r
+                patron_id : this.patron.id(),\r
+                copy_barcode : barcode\r
+            }\r
+        ]}\r
+    );\r
+\r
+    console.log(js2JSON(result));\r
+\r
+    var stat = this.handleXactResult('renew', barcode, result);\r
+\r
+    if(stat.override)\r
+        this.renew(barcode, true);\r
+}\r
+\r
+/**\r
+ * Display the result of a checkout or renewal in the items out table\r
+ */\r
+SelfCheckManager.prototype.displayCheckout = function(evt, type, itemsOut) {\r
+    var copy = evt.payload.copy;\r
+    var record = evt.payload.record;\r
+    var circ = evt.payload.circ;\r
+    var row = this.circTemplate.cloneNode(true);\r
+\r
+    //if(record.isbn()) {\r
+    //    this.byName(row, 'jacket').setAttribute('src', '/opac/extras/ac/jacket/small/' + record.isbn());\r
+    //}\r
+\r
+    this.byName(row, 'barcode').innerHTML = copy.barcode();\r
+    this.byName(row, 'title').innerHTML = record.title();\r
+    //this.byName(row, 'author').innerHTML = record.author();\r
+    //this.byName(row, 'remaining').innerHTML = circ.renewal_remaining();\r
+    openils.Util.show(this.byName(row, type));\r
+\r
+    var date = dojo.date.stamp.fromISOString(circ.due_date());\r
+    this.byName(row, 'due_date').innerHTML = \r
+        dojo.date.locale.format(date, {selector : 'date'});\r
+\r
+    // put new circs at the top of the list\r
+    var tbody = this.circTbody;\r
+    if(itemsOut) tbody = this.itemsOutTbody;\r
+    tbody.insertBefore(row, tbody.getElementsByTagName('tr')[0]);\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.byName = function(node, name) {\r
+    return dojo.query('[name=' + name+']', node)[0];\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.initPrinter = function() {\r
+    try { // Mozilla only\r
+               netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");\r
+        netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');\r
+        netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesRead');\r
+        netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesWrite');\r
+        var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);\r
+        if (pref)\r
+            pref.setBoolPref('print.always_print_silent', true);\r
+    } catch(E) {\r
+        console.log("Unable to initialize auto-printing"); \r
+    }\r
+}\r
+\r
+/**\r
+ * Print a receipt for this session's checkouts\r
+ */\r
+SelfCheckManager.prototype.printSessionReceipt = function(callback) {\r
+    var circIds = [];\r
+    var circCtx = []; // circ context data.  in this case, renewal_failure info\r
+\r
+    // collect the circs and failure info\r
+    dojo.forEach(\r
+        this.checkouts, \r
+        function(blob) {\r
+            circIds.push(blob.circ);\r
+            circCtx.push({renewal_failure:blob.renewal_failure});\r
+        }\r
+    );\r
+\r
+    var params = [\r
+        this.authtoken, \r
+        this.staff.ws_ou(),\r
+        null,\r
+        'format.selfcheck.checkout',\r
+        'print-on-demand',\r
+        circIds,\r
+        circCtx\r
+    ];\r
+\r
+    var self = this;\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.fire_circ_trigger_events'],\r
+        {   \r
+            async : true,\r
+            params : params,\r
+            oncomplete : function(r) {\r
+                var resp = openils.Util.readResponse(r);\r
+                var output = resp.template_output();\r
+                if(output) {\r
+                    self.printData(output.data(), self.checkouts.length, callback); \r
+                } else {\r
+                    var error = resp.error_output();\r
+                    if(error) {\r
+                        throw new Error("Error creating receipt: " + error.data());\r
+                    } else {\r
+                        throw new Error("No receipt data returned from server");\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+SelfCheckManager.prototype.printData = function(data, numItems, callback) {\r
+    var win = window.open('', '', 'resizable,width=350,height=250,scrollbars=1'); \r
+    win.document.body.innerHTML = data;\r
+    win.print();\r
+\r
+    /*\r
+     * There is no way to know when the browser is done printing.\r
+     * Make a best guess at when to close the print window by basing\r
+     * the setTimeout wait on the number of items to be printed plus\r
+     * a small buffer\r
+     */\r
+    var sleepTime = 1000;\r
+    if(numItems > 0) \r
+        sleepTime += (numItems / 2) * 1000;\r
+\r
+    setTimeout(\r
+        function() { \r
+            win.close(); // close the print window\r
+            if(callback) callback(); // fire optional post-print callback\r
+        },\r
+        sleepTime \r
+    );\r
+}\r
+\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printItemsOutReceipt = function(callback) {\r
+    if(!this.itemsOut.length) return;\r
+\r
+    progressDialog.show(true);\r
+\r
+    var params = [\r
+        this.authtoken, \r
+        this.staff.ws_ou(),\r
+        null,\r
+        'format.selfcheck.items_out',\r
+        'print-on-demand',\r
+        this.itemsOut\r
+    ];\r
+\r
+    var self = this;\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.fire_circ_trigger_events'],\r
+        {   \r
+            async : true,\r
+            params : params,\r
+            oncomplete : function(r) {\r
+                progressDialog.hide();\r
+                var resp = openils.Util.readResponse(r);\r
+                var output = resp.template_output();\r
+                if(output) {\r
+                    self.printData(output.data(), self.itemsOut.length, callback); \r
+                } else {\r
+                    var error = resp.error_output();\r
+                    if(error) {\r
+                        throw new Error("Error creating receipt: " + error.data());\r
+                    } else {\r
+                        throw new Error("No receipt data returned from server");\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printHoldsReceipt = function(callback) {\r
+    if(!this.holds.length) return;\r
+\r
+    progressDialog.show(true);\r
+\r
+    var holdIds = [];\r
+    var holdData = [];\r
+\r
+    dojo.forEach(this.holds,\r
+        function(data) {\r
+            holdIds.push(data.hold.id());\r
+            if(data.status == 4) {\r
+                holdData.push({ready : true});\r
+            } else {\r
+                holdData.push({\r
+                    queue_position : data.queue_position, \r
+                    potential_copies : data.potential_copies\r
+                });\r
+            }\r
+        }\r
+    );\r
+\r
+    var params = [\r
+        this.authtoken, \r
+        this.staff.ws_ou(),\r
+        null,\r
+        'format.selfcheck.holds',\r
+        'print-on-demand',\r
+        holdIds,\r
+        holdData\r
+    ];\r
+\r
+    var self = this;\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.fire_hold_trigger_events'],\r
+        {   \r
+            async : true,\r
+            params : params,\r
+            oncomplete : function(r) {\r
+                progressDialog.hide();\r
+                var resp = openils.Util.readResponse(r);\r
+                var output = resp.template_output();\r
+                if(output) {\r
+                    self.printData(output.data(), self.holds.length, callback); \r
+                } else {\r
+                    var error = resp.error_output();\r
+                    if(error) {\r
+                        throw new Error("Error creating receipt: " + error.data());\r
+                    } else {\r
+                        throw new Error("No receipt data returned from server");\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.printPaymentReceipt = function(paymentIds, callback) {\r
+    var self = this;\r
+    progressDialog.show(true);\r
+\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.money.payment_receipt.print'],\r
+        {\r
+            async : true,\r
+            params : [this.authtoken, paymentIds],\r
+            oncomplete : function(r) {\r
+                var resp = openils.Util.readResponse(r);\r
+                var output = resp.template_output();\r
+                progressDialog.hide();\r
+                if(output) {\r
+                    self.printData(output.data(), 1, callback); \r
+                } else {\r
+                    var error = resp.error_output();\r
+                    if(error) {\r
+                        throw new Error("Error creating receipt: " + error.data());\r
+                    } else {\r
+                        throw new Error("No receipt data returned from server");\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printFinesReceipt = function(callback) {\r
+    progressDialog.show(true);\r
+\r
+    var params = [\r
+        this.authtoken, \r
+        this.staff.ws_ou(),\r
+        null,\r
+        'format.selfcheck.fines',\r
+        'print-on-demand',\r
+        [this.patron.id()]\r
+    ];\r
+\r
+    var self = this;\r
+    fieldmapper.standardRequest(\r
+        ['open-ils.circ', 'open-ils.circ.fire_user_trigger_events'],\r
+        {   \r
+            async : true,\r
+            params : params,\r
+            oncomplete : function(r) {\r
+                progressDialog.hide();\r
+                var resp = openils.Util.readResponse(r);\r
+                var output = resp.template_output();\r
+                if(output) {\r
+                    self.printData(output.data(), self.finesCount, callback); \r
+                } else {\r
+                    var error = resp.error_output();\r
+                    if(error) {\r
+                        throw new Error("Error creating receipt: " + error.data());\r
+                    } else {\r
+                        throw new Error("No receipt data returned from server");\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    );\r
+}\r
+\r
+\r
+/**\r
+ * Logout the patron and return to the login page\r
+ */\r
+SelfCheckManager.prototype.logoutPatron = function(print) {\r
+    progressDialog.show(true); // prevent patron from clicking logout link twice\r
+    if(print && this.checkouts.length) {\r
+        this.printSessionReceipt(\r
+            function() {\r
+                location.href = location.href;\r
+            }\r
+        );\r
+    } else {\r
+        location.href = location.href;\r
+    }\r
+}\r
+\r
+\r
+function checkLogin() {\r
+       selfCheckMgr.keepMeLoggedIn();\r
+       if(selfCheckMgr.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) {\r
+               switchTo('step2');\r
+               try{dojo.byId('patron-login-password').focus();}catch(e){}\r
+       } else {\r
+               selfCheckMgr.loginPatron(dojo.byId('patron-login-username').value);\r
+       }\r
+}\r
+\r
+\r
+function cancelLogin() {\r
+       dojo.byId('oils-selfck-status-div').innerHTML = '';\r
+       dojo.byId('oils-selfck-status-div2').innerHTML = '';\r
+       dojo.byId('oils-selfck-status-div3').innerHTML = '';\r
+       dojo.byId('patron-login-password').value = '';\r
+       openils.Util.hide('back_to_login');\r
+       switchTo('step1');\r
+       try {\r
+               dojo.byId('patron-login-username').focus();\r
+               dojo.byId('patron-login-username').select();\r
+       } catch(e) {}\r
+}\r
+\r
+/**\r
+ * Fire up the manager on page load\r
+ */\r
+openils.Util.addOnLoad(\r
+    function() {\r
+        new SelfCheckManager().init();\r
+               openils.Util.registerEnterHandler(dojo.byId('patron-login-username'), function(){checkLogin();});\r
+               openils.Util.registerEnterHandler(dojo.byId('patron-login-password'), function(){selfCheckMgr.loginPatron(dojo.byId('patron-login-username').value,dojo.byId('patron-login-password').value);});\r
+    }\r
+);\r
diff --git a/Open-ILS/web/local_templates/base.tt2 b/Open-ILS/web/local_templates/base.tt2
new file mode 100644 (file)
index 0000000..c95f117
--- /dev/null
@@ -0,0 +1,27 @@
+[%- ctx.final_dtd = 
+    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' -%]
+[%- IF !ctx.dtd; ctx.dtd = ctx.final_dtd; END -%]
+[% ctx.dtd %]
+<html xmlns='http://www.w3.org/1999/xhtml' lang='[% ctx.locale %]' xml:lang='[% ctx.locale %]'>
+    <head>
+        <title>[% ctx.page_title %]</title>
+        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+        <link rel='stylesheet' type='text/css'
+            href='[% ctx.media_prefix %]/css/skin/[% ctx.skin %].css' />
+        <link rel='stylesheet' type='text/css'
+            href='[% ctx.media_prefix %]/css/theme/[% ctx.skin %].css' />
+       <script language='javascript' src='/IDL2js' type='text/javascript'></script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/dojo.js"
+            djConfig="parseOnLoad: true, isDebug:false"></script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/openils_dojo.js"></script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/opensrf/md5.js"></script>
+        <script type="text/javascript">
+            var oilsBasePath = '[% ctx.base_path %]';
+        </script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/ui/base.js"></script>
+    </head>
+    <body class='tundra'>
+        [% INCLUDE login.tt2 %] <!-- shared login page -->
+        [% content %] <!-- Page body -->
+    </body>
+</html>
diff --git a/Open-ILS/web/local_templates/base.tt2-aug17.old2 b/Open-ILS/web/local_templates/base.tt2-aug17.old2
new file mode 100644 (file)
index 0000000..6bb7874
--- /dev/null
@@ -0,0 +1,26 @@
+[%- ctx.final_dtd = 
+    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' -%]
+[%- IF !ctx.dtd; ctx.dtd = ctx.final_dtd; END -%]
+[% ctx.dtd %]
+<html xmlns='http://www.w3.org/1999/xhtml' lang='[% ctx.locale %]' xml:lang='[% ctx.locale %]'>
+    <head>
+        <title>[% ctx.page_title %]</title>
+        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+        <link rel='stylesheet' type='text/css'
+            href='[% ctx.media_prefix %]/css/skin/[% ctx.skin %].css' />
+        <link rel='stylesheet' type='text/css'
+            href='[% ctx.media_prefix %]/css/theme/[% ctx.skin %].css' />
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/dojo.js"
+            djConfig="parseOnLoad: true, isDebug:false"></script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/openils_dojo.js"></script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/opensrf/md5.js"></script>
+        <script type="text/javascript">
+            var oilsBasePath = '[% ctx.base_path %]';
+        </script>
+        <script type="text/javascript" src="[% ctx.media_prefix %]/js/ui/base.js"></script>
+    </head>
+    <body class='tundra'>
+        [% INCLUDE login.tt2 %] <!-- shared login page -->
+        [% content %] <!-- Page body -->
+    </body>
+</html>
diff --git a/Open-ILS/web/local_templates/base.tt2.old b/Open-ILS/web/local_templates/base.tt2.old
new file mode 100644 (file)
index 0000000..9e7c8c3
--- /dev/null
@@ -0,0 +1,64 @@
+[%- ctx.final_dtd = \r
+    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' -%]\r
+[%- ctx.home_path ='/local_templates/default/circ/selfcheck' -%]\r
+[%- IF !ctx.dtd; ctx.dtd = ctx.final_dtd; END -%]\r
+[% ctx.dtd %]\r
+<html xmlns='http://www.w3.org/1999/xhtml' lang='[% ctx.locale %]' xml:lang='[% ctx.locale %]'>\r
+  <head>\r
+       <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />\r
+       <title>[% ctx.page_title %]</title>\r
+       \r
+       \r
+           <link rel='stylesheet' type='text/css' href='[% ctx.media_prefix %]/css/skin/[% ctx.skin %].css' />\r
+               <link rel='stylesheet' type='text/css' href='[% ctx.media_prefix %]/css/theme/[% ctx.skin %].css' />\r
+       \r
+       <link rel='stylesheet' type='text/css' href='[% ctx.home_path %]/style.css' />\r
+       \r
+<script type="text/javascript">\r
+function switchTo(str,subpage) {\r
+       var pages = [];\r
+       var sidebarLinks = [];\r
+       pages['step0'] = document.getElementById('step0');\r
+       pages['step1'] = document.getElementById('step1');\r
+       pages['step2'] = document.getElementById('step2');\r
+       pages['step3'] = document.getElementById('step3');\r
+       pages['step3a'] = document.getElementById('step3a');\r
+       //pages['step3b'] = document.getElementById('step3b');\r
+       pages['step3c'] = document.getElementById('step3c');\r
+       pages['step3d'] = document.getElementById('step3d');\r
+       pages['step3e'] = document.getElementById('step3e');\r
+       pages['step3f'] = document.getElementById('step3f');\r
+       pages['step4'] = document.getElementById('step4');\r
+       pages['step5'] = document.getElementById('step5');\r
+       pages['pay_fines'] = document.getElementById('pay_fines');\r
+       \r
+       sidebarLinks['sidebar_step3c'] = document.getElementById('sidebar_step3c');\r
+       sidebarLinks['sidebar_step3d'] = document.getElementById('sidebar_step3d');\r
+       sidebarLinks['sidebar_step3e'] = document.getElementById('sidebar_step3e');\r
+       sidebarLinks['sidebar_step3f'] = document.getElementById('sidebar_step3f');\r
+\r
+       for(var i in pages) { if(!pages[i]) continue; pages[i].style.display="none"; }\r
+       for(var i in sidebarLinks) { if(!sidebarLinks[i]) continue; sidebarLinks[i].className=""; }\r
+       \r
+       if(subpage) {\r
+               pages[subpage].style.display="block";\r
+               sidebarLinks['sidebar_'+subpage].className="selected";\r
+       }\r
+       pages[str].style.display="block";\r
+       if(str=='step3' && !subpage) pages['step3a'].style.display="block";\r
+       try{dojo.byId('selfckScanBox').focus();dojo.byId('selfckScanBox').select();}catch(e){}\r
+}\r
+</script>\r
+       <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/dojo.js" djConfig="parseOnLoad: true, isDebug:false"></script>\r
+       <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/dojo/openils_dojo.js"></script>\r
+       <script type="text/javascript" src="[% ctx.media_prefix %]/js/dojo/opensrf/md5.js"></script>\r
+       <script type="text/javascript">var oilsBasePath = '[% ctx.base_path %]';</script>\r
+       <script type="text/javascript" src="[% ctx.media_prefix %]/js/ui/base.js"></script>\r
+  \r
+  </head>\r
\r
+<body class='tundra'> \r
+[% INCLUDE login.tt2 %] <!-- shared login page -->\r
+[% content %] <!-- Page body -->\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/Open-ILS/web/local_templates/default/actor/user/register_table.tt2.disabled b/Open-ILS/web/local_templates/default/actor/user/register_table.tt2.disabled
new file mode 100644 (file)
index 0000000..5083acc
--- /dev/null
@@ -0,0 +1,116 @@
+<tbody id='uedit-tbody'>
+    <tr fmclass='au' fmfield='dob'/>
+    <tr fmclass='au' fmfield='juvenile'/>
+    <tr fmclass='au' fmfield='ident_value2'><td/><td>Parent/Guardian</td></tr>
+    <tr fmclass='au' fmfield='family_name' required='required'/>
+    <tr fmclass='au' fmfield='first_given_name' required='required'/>
+    <tr fmclass='au' fmfield='second_given_name'/>
+
+
+    <!-- Address ============================== -->
+    <tr name='uedit-addr-divider' class='divider' type='addr-template' required='show'>
+        <td colspan='2'>Address</td>
+        <td>
+            <span>Mailing</span><input type='radio' name='mailing_address'>
+            <span>Billing</span><input type='radio' name='billing_address'>
+            <button name='delete-button' class='uedit-addr-del-button'>X</button>
+        </td>
+    </tr>
+
+    <tr name='uedit-addr-pending-row' type='addr-template' class='pending-addr-row hidden'>
+        <td colspan='3'>
+            <span style='padding-right:10px;'>This is a pending address: </span>
+            <button name='approve-button'>Approve Address</button>
+            <div name='replaced-addr-div'>
+                <div name='replaced-addr'></div>
+            </div>
+        </td>
+    </tr>
+
+    <tr name='uedit-addr-owner-row' type='addr-template' class='pending-addr-row hidden'>
+        <td colspan='3'>
+            <span style='padding-right:10px;'>This address is owned by another user: </span>
+            <a href='javascript:void(0);'  name='addr-owner'></a>
+        </td>
+    </tr>
+
+    <tr id='new-addr-row' class='newaddr-row' required='show'>
+        <td colspan='0' style='text-align:center;'>
+            <button dojoType='dijit.form.Button' onClick='uEditNewAddr'>New Address</button>
+        </td>
+    </tr>
+    <!-- ====================================== -->
+
+
+
+    <tr fmclass='au' fmfield='day_phone'/>
+    <tr fmclass='au' fmfield='evening_phone'/>
+    <tr fmclass='au' fmfield='other_phone'/>
+    <tr fmclass='au' fmfield='email'/>
+
+    <tr fmclass='ac' fmfield='barcode' required='required'>
+        <td/><td/><td/>
+        <td>
+            <button dojoType='dijit.form.Button' jsId='replaceBarcode'>Replace Barcode</button>
+            <span id='uedit-dupe-barcode-warning' style='color:red; font-weight:bold' class='hidden'>
+                Barcode is already in use
+            </span>
+        </td>
+        <td id='uedit-all-barcodes' class='hidden'>
+            <button dojoType='dijit.form.Button' jsId='allCards'>See All</button>
+        </td>
+    </tr>
+    <tr fmclass='au' fmfield='usrname' required='required'>
+        <td/><td/><td/>
+        <td>
+            <span id='uedit-dupe-username-warning' style='color:red; font-weight:bold' class='hidden'>
+                Username is already in use
+            </span>
+        </td>
+    </tr>
+    <tr fmclass='au' fmfield='passwd' required='required'/>
+    <tr fmclass='au' fmfield='passwd2' required='required'><td/><td>Verify Password</td><td/></tr>
+    <tr fmclass='au' fmfield='alias'/>
+    <tr fmclass='au' fmfield='profile' required='required'/>
+    <tr fmclass='au' fmfield='home_ou' required='required'/>
+    <tr fmclass='au' fmfield='expire_date' required='required'/>
+    <tr fmclass='au' fmfield='net_access_level' required='required'/>
+    <tr fmclass='au' fmfield='active'/>
+    <tr fmclass='au' fmfield='barred'/>
+    <tr fmclass='au' fmfield='master_account'/>
+
+
+    <tr fmclass='au' fmfield='suffix'/>
+    <tr fmclass='au' fmfield='ident_type' required='required'/>
+    <tr fmclass='au' fmfield='ident_value'/>
+    <tr fmclass='au' fmfield='claims_returned_count' wclass='dijit.form.NumberSpinner' wconstraints="{min:0,places:0}" wvalue='0'/>
+    <tr fmclass='au' fmfield='claims_never_checked_out_count' wclass='dijit.form.NumberSpinner' wconstraints="{min:0,places:0}" wvalue='0'/>
+    <tr fmclass='au' fmfield='alert_message' wclass='dijit.form.Textarea' wstyle='height:5em'/>
+
+    <tr class='divider hidden' id='uedit-settings-divider'><td colspan='0'>User Settings</td></tr>
+    <tr class='hidden' id='uedit-user-setting-template'>
+        <td/>
+        <td><span name='label'></span></td>
+        <td><div name='widget'></div></td>
+    </tr>
+
+    <tr fmclass='aua' fmfield='address_type' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='post_code' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='street1' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='street2' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='city' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='county' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='state' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='country' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='valid' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='within_city_limits' type='addr-template' required='show'/>
+
+    <!-- stat cats -->
+    <tr class='divider' id='stat-cat-divider'><td colspan='0'>Statistical Categories</td></tr>
+    <tr id='stat-cat-row-template'><td class='uedit-help'/><td name='name'/><td name='widget'/></tr>
+
+    <!-- surveys -->
+    <tr id='survey-row-template' class='divider'><td colspan='0' name='name'/></tr>
+    <tr id='survey-question-row-template'><td class='uedit-help'/><td name='question'/><td name='answers'/></tr>
+</tbody>
+
diff --git a/Open-ILS/web/local_templates/default/actor/user/register_table.tt2.orig b/Open-ILS/web/local_templates/default/actor/user/register_table.tt2.orig
new file mode 100644 (file)
index 0000000..e90e925
--- /dev/null
@@ -0,0 +1,98 @@
+<tbody id='uedit-tbody'>
+    <tr fmclass='au' fmfield='dob'/>
+    <tr fmclass='au' fmfield='juvenile'/>
+    <tr fmclass='au' fmfield='ident_value2'><td/><td>Parent/Guardian</td></tr>
+    <tr fmclass='au' fmfield='family_name' required='required'/>
+    <tr fmclass='au' fmfield='first_given_name' required='required'/>
+    <tr fmclass='au' fmfield='second_given_name'/>
+
+
+    <!-- Address ============================== -->
+    <tr name='uedit-addr-divider' class='divider' type='addr-template' required='show'>
+        <td colspan='2'>Address</td>
+        <td>
+            <span>Mailing</span><input type='radio' name='mailing_address'>
+            <span>Billing</span><input type='radio' name='billing_address'>
+            <button name='delete-button' class='uedit-addr-del-button'>X</button>
+        </td>
+    </tr>
+
+    <tr name='uedit-addr-pending-row' type='addr-template' class='pending-addr-row hidden'>
+        <td colspan='3'>
+            <span style='padding-right:10px;'>This is a pending address: </span>
+            <button name='approve-button'>Approve Address</button>
+            <div name='replaced-addr-div'>
+                <div name='replaced-addr'></div>
+            </div>
+        </td>
+    </tr>
+
+    <tr name='uedit-addr-owner-row' type='addr-template' class='pending-addr-row hidden'>
+        <td colspan='3'>
+            <span style='padding-right:10px;'>This address is owned by another user: </span>
+            <a href='javascript:void(0);'  name='addr-owner'></a>
+        </td>
+    </tr>
+
+    <tr id='new-addr-row' class='newaddr-row' required='show'>
+        <td colspan='0' style='text-align:center;'>
+            <button dojoType='dijit.form.Button' onClick='uEditNewAddr'>New Address</button>
+        </td>
+    </tr>
+    <!-- ====================================== -->
+
+
+
+    <tr fmclass='au' fmfield='day_phone'/>
+    <tr fmclass='au' fmfield='evening_phone'/>
+    <tr fmclass='au' fmfield='other_phone'/>
+    <tr fmclass='au' fmfield='email'/>
+
+    <tr fmclass='ac' fmfield='barcode' required='required'/>
+    <tr fmclass='au' fmfield='usrname' required='required'/>
+    <tr fmclass='au' fmfield='passwd' required='required'/>
+    <tr fmclass='au' fmfield='passwd2' required='required'><td/><td>Verify Password</td><td/></tr>
+    <tr fmclass='au' fmfield='alias'/>
+    <tr fmclass='au' fmfield='profile' required='required'/>
+    <tr fmclass='au' fmfield='home_ou' required='required'/>
+    <tr fmclass='au' fmfield='expire_date' required='required'/>
+    <tr fmclass='au' fmfield='net_access_level' required='required'/>
+    <tr fmclass='au' fmfield='active'/>
+    <tr fmclass='au' fmfield='barred'/>
+    <tr fmclass='au' fmfield='master_account'/>
+
+
+    <tr fmclass='au' fmfield='suffix'/>
+    <tr fmclass='au' fmfield='ident_type' required='required'/>
+    <tr fmclass='au' fmfield='ident_value'/>
+    <tr fmclass='au' fmfield='claims_returned_count' wclass='dijit.form.NumberSpinner' wconstraints="{min:0,places:0}" wvalue='0'/>
+    <tr fmclass='au' fmfield='claims_never_checked_out_count' wclass='dijit.form.NumberSpinner' wconstraints="{min:0,places:0}" wvalue='0'/>
+    <tr fmclass='au' fmfield='alert_message' wclass='dijit.form.Textarea' wstyle='height:5em'/>
+
+    <tr class='divider hidden' id='uedit-settings-divider'><td colspan='0'>User Settings</td></tr>
+    <tr class='hidden' id='uedit-user-setting-template'>
+        <td/>
+        <td><span name='label'></span></td>
+        <td><div name='widget'></div></td>
+    </tr>
+
+    <tr fmclass='aua' fmfield='address_type' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='post_code' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='street1' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='street2' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='city' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='county' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='state' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='country' type='addr-template' required='required'/>
+    <tr fmclass='aua' fmfield='valid' type='addr-template' required='show'/>
+    <tr fmclass='aua' fmfield='within_city_limits' type='addr-template' required='show'/>
+
+    <!-- stat cats -->
+    <tr class='divider' id='stat-cat-divider'><td colspan='0'>Statistical Categories</td></tr>
+    <tr id='stat-cat-row-template'><td class='uedit-help'/><td name='name'/><td name='widget'/></tr>
+
+    <!-- surveys -->
+    <tr id='survey-row-template' class='divider'><td colspan='0' name='name'/></tr>
+    <tr id='survey-question-row-template'><td class='uedit-help'/><td name='question'/><td name='answers'/></tr>
+</tbody>
+
diff --git a/Open-ILS/web/local_templates/default/base.tt2 b/Open-ILS/web/local_templates/default/base.tt2
new file mode 100644 (file)
index 0000000..0570b12
--- /dev/null
@@ -0,0 +1,39 @@
+[% WRAPPER 'base.tt2' %]
+<script type="text/javascript">
+ dojo.require("dijit.layout.LayoutContainer");
+ dojo.require("dijit.layout.ContentPane");
+</script>
+
+<!-- define the basic page structure -->
+<div id="oils-base-body-block" class="tundra" dojoType="dijit.layout.LayoutContainer"> 
+    <div id="oils-base-header-block" dojoType="dijit.layout.ContentPane" layoutAlign="top">
+
+        <!-- Hide the non-xul menu for now.  
+             Will probably remove at some point since it's perpetually out 
+             of sync and exists solely as a development tool
+
+        <div id='oils-base-header-menu-block'>
+            [%# INCLUDE default/menu.tt2 #%]
+        </div>
+        -->
+
+        <div id='oils-base-header-auto-login-block'>
+            [% INCLUDE default/header.tt2 %]
+        </div>
+    </div>
+    <div id="oils-base-main-block" dojoType="dijit.layout.LayoutContainer" layoutAlign="client">
+        <!--
+        <div id="oils-base-navigate-block" dojoType="dijit.layout.ContentPane" layoutAlign="left">
+        </div>
+        -->
+        <div id="oils-base-content-block" dojoType="dijit.layout.ContentPane" layoutAlign="client">
+            [% content %]
+        </div>
+    </div>
+    <!--
+    <div id="oils-base-footer-block">
+        [% INCLUDE default/footer.tt2 %]
+    </div>
+    -->
+</div>
+[% END %]
diff --git a/Open-ILS/web/local_templates/default/base.tt2.old b/Open-ILS/web/local_templates/default/base.tt2.old
new file mode 100644 (file)
index 0000000..507fc1d
--- /dev/null
@@ -0,0 +1,41 @@
+[% WRAPPER 'base.tt2' %]\r
+<script type="text/javascript">\r
+ dojo.require("dijit.layout.LayoutContainer");\r
+ dojo.require("dijit.layout.ContentPane");\r
+</script>\r
+\r
+<div dojoType='openils.widget.ProgressDialog' jsId='progressDialog'></div>\r
+<div dojoType="dijit.Dialog" jsId='oilsSelfckWsDialog' class='oils-login-dialog' style='display:none;'>\r
+    <form>\r
+        <table>\r
+            <tr>\r
+                <td>Choose a location</td>\r
+                <td><div dojoType='openils.widget.OrgUnitFilteringSelect' jsId='oilsSelfckWsLocSelector' \r
+                    searchAttr='shortname' labelAttr='shortname'/></td>\r
+            </tr>\r
+            <tr>\r
+                <td>Enter a workstation name</td>\r
+                <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckWsName'/></td>\r
+            </tr>\r
+            <tr>\r
+                <td colspan='2' align='center'>\r
+                    <button jsId='oilsSelfckWsSubmit' dojoType='dijit.form.Button'>Submit</button>\r
+                </td>\r
+            </tr>\r
+        </table>\r
+    </form>\r
+</div>\r
+\r
+<div style="height:66px;background:#ae2c2a;"><div id='header'>\r
+  <a href='javascript:;'><img src='[% ctx.home_path %]/graphics/KCLS_logo_horiz.gif' /></a>\r
+  <span style="font-size:36px;color:white;position:relative;top:-10px;left:15px;">CHECK OUT HERE</span>\r
+</div></div>\r
+\r
+<div id='content-wrapper'>\r
+  <div id='main-content'>\r
+       <div style='clear:both;'></div>\r
+       [% content %]  \r
+       <div style='clear:both;'></div> \r
+  </div>\r
+</div>\r
+[% END %]\r
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/audio_config.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/audio_config.tt2
new file mode 100644 (file)
index 0000000..9b084a1
--- /dev/null
@@ -0,0 +1,13 @@
+[%#\r
+    Override the audio config values by copying this template into your local templates\r
+    directory (matching the relative path) and change the values accordingly.\r
+#%]\r
+\r
+<script type="text/javascript">\r
+    SelfCheckManager.audioConfig = {\r
+        'login-success' : '',\r
+        'login-failure' : '/xul/current/server/skin/media/audio/question.wav',\r
+        'checkout-success' : '/xul/current/server/skin/media/audio/bonus.wav',\r
+        'checkout-failure' : '/xul/current/server/skin/media/audio/question.wav',\r
+    }\r
+</script>\r
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/banner.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/banner.tt2
new file mode 100644 (file)
index 0000000..cda4866
--- /dev/null
@@ -0,0 +1,10 @@
+<div id='oils-selfck-user-banner'></div>
+<div id='oils-selfck-logo-div'>
+    <img src='[% ctx.media_prefix %]/images/eg_logo.jpg'/>
+</div>
+<div id='oils-selfck-scan-div'>
+    <div id='oils-selfck-scan-text'></div>
+    <input jsId='selfckScanBox' dojoType='dijit.form.TextBox'/>
+</div>
+<div id='oils-selfck-status-div'></div>
+
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/circ_page.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/circ_page.tt2
new file mode 100644 (file)
index 0000000..868f5f9
--- /dev/null
@@ -0,0 +1,30 @@
+<div id='oils-selfck-circ-table-div'>
+    <table id='oils-selfck-circ-table' class='oils-selfck-item-table'>
+        <thead>
+            <tr>
+                <td id='oils-self-circ-pic-cell'></td>
+                <td>Barcode</td>
+                <td>Title</td>
+                <td>Author</td>
+                <td>Due Date</td>
+                <td class='hidden'>Renewals Left</td>
+                <td>Type</td>
+            </tr>
+        </thead>
+        <tbody id='oils-selfck-circ-tbody'>
+            <tr id='oils-selfck-circ-row'>
+                <td><img class='oils-selfck-jacket' name='jacket'/></td>
+                <td name='barcode'></td>
+                <td name='title'></td>
+                <td name='author'></td>
+                <td name='due_date'></td>
+                <td class='hidden' name='remaining'></td>
+                <td>
+                    <div name='checkout' class='hidden'>Checkout</div>
+                    <div name='renew' class='hidden'>Renewal</div>
+                </td>
+            </tr>
+        </tbody>
+        <tbody id='oils-selfck-circ-out-tbody' class='oils-selfck-item-table'></tbody>
+    </table>
+</div>
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/fines.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/fines.tt2
new file mode 100644 (file)
index 0000000..fee782e
--- /dev/null
@@ -0,0 +1,26 @@
+<span id='oils-selfck-selected-total'></span>
+<span style='padding-left:5px;'><a href='javascript:void(0);' id='oils-selfck-pay-fines-link'>Pay Fines</a></span>
+<div id='oils-selfck-fines-table-div'>
+    <table id='oils-selfck-fines-table' class='oils-selfck-item-table'>
+        <thead>
+            <tr>
+                <td><input type='checkbox' checked='checked' id='oils-selfck-fines-selector'/></td>
+                <td>Type</td>
+                <td>Details</td>
+                <td>Total Billed</td>
+                <td>Total Paid</td>
+                <td>Balance Owed</td>
+            </tr>
+        </thead>
+        <tbody id='oils-selfck-fines-tbody'>
+            <tr id='oils-selfck-fines-row'>
+                <td><input type='checkbox' name='selector' checked='checked'/></td>
+                <td name='type'></td>
+                <td name='details'></td>
+                <td name='total_owed'></td>
+                <td name='total_paid'></td>
+                <td name='balance' style='color:red;'></td>
+            </tr>
+        </tbody>
+    </table>
+</div>
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/KCLS_logo_horiz.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/KCLS_logo_horiz.gif
new file mode 100644 (file)
index 0000000..8e1d56e
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/KCLS_logo_horiz.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/arrow.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/arrow.gif
new file mode 100644 (file)
index 0000000..bf17978
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/arrow.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/barcodedetailbook.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/barcodedetailbook.jpg
new file mode 100644 (file)
index 0000000..f0a237e
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/barcodedetailbook.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/go-btn.png b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/go-btn.png
new file mode 100644 (file)
index 0000000..24091c9
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/go-btn.png differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/gobutton.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/gobutton.jpg
new file mode 100644 (file)
index 0000000..33e7c38
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/gobutton.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/libcard_barcode.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/libcard_barcode.jpg
new file mode 100644 (file)
index 0000000..31419f6
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/libcard_barcode.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/login-btn.png b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/login-btn.png
new file mode 100644 (file)
index 0000000..ae9d9de
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/login-btn.png differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logout.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logout.gif
new file mode 100644 (file)
index 0000000..11d6160
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logout.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutbutton.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutbutton.jpg
new file mode 100644 (file)
index 0000000..61092ed
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutbutton.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutnoreceipt.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutnoreceipt.gif
new file mode 100644 (file)
index 0000000..1c88f4a
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutnoreceipt.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutwithoutreceiptbutton.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutwithoutreceiptbutton.jpg
new file mode 100644 (file)
index 0000000..20228bd
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/logoutwithoutreceiptbutton.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/printlist.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/printlist.jpg
new file mode 100644 (file)
index 0000000..a83c0fc
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/printlist.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_font.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_font.gif
new file mode 100644 (file)
index 0000000..9dc10a9
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_font.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_mail.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_mail.gif
new file mode 100644 (file)
index 0000000..83c3573
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_mail.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_print.gif b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_print.gif
new file mode 100644 (file)
index 0000000..d3d7ee3
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/tool_print.gif differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner-right.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner-right.jpg
new file mode 100644 (file)
index 0000000..1559897
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner-right.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner.jpg b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner.jpg
new file mode 100644 (file)
index 0000000..4932a28
Binary files /dev/null and b/Open-ILS/web/local_templates/default/circ/selfcheck/graphics/utils-corner.jpg differ
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/holds_page.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/holds_page.tt2
new file mode 100644 (file)
index 0000000..3336249
--- /dev/null
@@ -0,0 +1,20 @@
+<div id='oils-selfck-hold-table-div'>
+    <table id='oils-selfck-hold-table' class='oils-selfck-item-table'>
+        <thead>
+            <tr>
+                <td id='oils-self-hold-pic-cell'></td>
+                <td>Title</td>
+                <td>Author</td>
+                <td>Status</td>
+            </tr>
+        </thead>
+        <tbody id='oils-selfck-hold-tbody'>
+            <tr id='oils-selfck-hold-row'>
+                <td><img class='oils-selfck-jacket' name='jacket'/></td>
+                <td name='title'></td>
+                <td name='author'></td>
+                <td name='status'></td>
+            </tr>
+        </tbody>
+    </table>
+</div>
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/main.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/main.tt2
new file mode 100644 (file)
index 0000000..9c89e55
--- /dev/null
@@ -0,0 +1,238 @@
+[%- ctx.home_path ='/local_templates/default/circ/selfcheck' -%]\r
+[% ctx.page_title = 'Self Checkout' %]\r
+[% WRAPPER default/base.tt2 %]\r
+<!-- ***************************************** main.tt2 ***************************************************** -->\r
+\r
+\r
+<div id="selfcheck-main">\r
+<script type="text/javascript">\r
+function switchTo(str,subpage) {\r
+       var pages = [];\r
+       var sidebarLinks = [];\r
+       pages['step0'] = document.getElementById('step0');\r
+       pages['step1'] = document.getElementById('step1');\r
+       pages['step2'] = document.getElementById('step2');\r
+       pages['step3'] = document.getElementById('step3');\r
+       pages['step3a'] = document.getElementById('step3a');\r
+       //pages['step3b'] = document.getElementById('step3b');\r
+       pages['step3c'] = document.getElementById('step3c');\r
+       pages['step3d'] = document.getElementById('step3d');\r
+       pages['step3e'] = document.getElementById('step3e');\r
+       pages['step3f'] = document.getElementById('step3f');\r
+       pages['step4'] = document.getElementById('step4');\r
+       pages['step5'] = document.getElementById('step5');\r
+       pages['pay_fines'] = document.getElementById('pay_fines');\r
+       \r
+       sidebarLinks['sidebar_step3c'] = document.getElementById('sidebar_step3c');\r
+       sidebarLinks['sidebar_step3d'] = document.getElementById('sidebar_step3d');\r
+       sidebarLinks['sidebar_step3e'] = document.getElementById('sidebar_step3e');\r
+       sidebarLinks['sidebar_step3f'] = document.getElementById('sidebar_step3f');\r
+\r
+       for(var i in pages) { if(!pages[i]) continue; pages[i].style.display="none"; }\r
+       for(var i in sidebarLinks) { if(!sidebarLinks[i]) continue; sidebarLinks[i].className=""; }\r
+       \r
+       if(subpage) {\r
+               pages[subpage].style.display="block";\r
+               sidebarLinks['sidebar_'+subpage].className="selected";\r
+       }\r
+       pages[str].style.display="block";\r
+       if(str=='step3' && !subpage) pages['step3a'].style.display="block";\r
+       try{dojo.byId('selfckScanBox').focus();dojo.byId('selfckScanBox').select();}catch(e){}\r
+}\r
+</script>\r
+\r
+\r
+\r
+<div dojoType='openils.widget.ProgressDialog' jsId='progressDialog'></div>\r
+<div dojoType="dijit.Dialog" jsId='oilsSelfckWsDialog' class='oils-login-dialog' style='display:none;'>\r
+    <form>\r
+        <table>\r
+            <tr>\r
+                <td>Choose a location</td>\r
+                <td><div dojoType='openils.widget.OrgUnitFilteringSelect' jsId='oilsSelfckWsLocSelector' \r
+                    searchAttr='shortname' labelAttr='shortname'/></td>\r
+            </tr>\r
+            <tr>\r
+                <td>Enter a workstation name</td>\r
+                <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckWsName'/></td>\r
+            </tr>\r
+            <tr>\r
+                <td colspan='2' align='center'>\r
+                    <button jsId='oilsSelfckWsSubmit' dojoType='dijit.form.Button'>Submit</button>\r
+                </td>\r
+            </tr>\r
+        </table>\r
+    </form>\r
+</div>\r
+\r
+<div style="height:66px;background:#ae2c2a;"><div id='header'>\r
+  <a href='javascript:;'><img src='[% ctx.home_path %]/graphics/KCLS_logo_horiz.gif' alt='kcls logo' /></a>\r
+  <span style="font-size:36px;color:white;position:relative;top:-10px;left:15px;">CHECK OUT HERE</span>\r
+</div></div>\r
+\r
+<div id='content-wrapper'>\r
+  <div id='main-content'>\r
+       <div style='clear:both;'></div>\r
+       \r
+\r
+<script src='[% ctx.media_prefix %]/js/ui/kcls/circ/selfcheck/selfcheck.js'> </script>\r
+<script src="[% ctx.media_prefix %]/js/ui/kcls/circ/selfcheck/payment.js"></script>\r
+<link rel='stylesheet' type='text/css' href='[% ctx.media_prefix %]/css/skin/kcls/selfcheck.css'/>\r
+[% INCLUDE 'default/circ/selfcheck/audio_config.tt2' %]\r
+\r
+  <div id="step0" class="checkout" style="width=100%;text-align:center;">Staff login required</div>\r
+  <div id="step1" class="checkout hidden" style="padding-top:15px;">\r
+       <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr>\r
+    <td align="center"><h1>Scan your library card barcode<br />OR type your library card number</h1></td></tr></table>\r
+    <table cellpadding="0" cellspacing="0" border="0" style="margin:20px auto;"><tr>\r
+    <td><img src="[% ctx.home_path %]/graphics/libcard_barcode.jpg" alt='library card' /></td><td style="padding-left:10px;"><span style="font-size:18px;">Example 0017620030</span><br /><input type="text" id='patron-login-username' />\r
+               <div style="position:absolute;"><div style="position:relative;top:-70px;"><div id='oils-selfck-status-div2' class='status_box'></div></div></div></td>\r
+    <td><a href="javascript:;" onclick="checkLogin();" style="position:relative;top:12px;left:5px;"><img alt='go' src="[% ctx.home_path %]/graphics/gobutton.jpg" /></a></td></tr></table>\r
+  </div>\r
+  <div id="step2" class="checkout hidden" style="padding-top:15px;">\r
+       <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr>\r
+    <td align="center"><h1>Enter your PIN or password</h1></td></tr></table>\r
+    <table cellpadding="0" cellspacing="0" border="0" style="margin:20px auto;"><tr>\r
+    <td style="padding-left:10px;"><span style="font-size:18px;">Example 0926</span><br /><input type="password" id='patron-login-password' />\r
+               <div style="position:absolute;"><div style="position:relative;top:10px;"><div id='oils-selfck-status-div3' class='status_box'></div><div class="hidden" id="back_to_login"><a href="javascript:;" onclick="cancelLogin();">Cancel</a></div></div></div></td>\r
+    <td><a href="javascript:;" onclick="selfCheckMgr.loginPatron(dojo.byId('patron-login-username').value,dojo.byId('patron-login-password').value);" style="position:relative;top:12px;left:5px;"><img alt='go' src="[% ctx.home_path %]/graphics/gobutton.jpg" /></a></td></tr></table>\r
+  </div>\r
+  <div id="step3" class="checkout" style="display:none;">\r
+       <table cellpadding="0" cellspacing="0" border="0" width="694" height="410" style="margin-bottom:2px;">\r
+      <tr><td valign="top" width="444" style="padding:3px;" rowspan="2">\r
+               <img src="[% ctx.home_path %]/graphics/barcodedetailbook.jpg" alt='item barcode' style="float:left;" />\r
+        <div class="header1">\r
+          <h2>Scan your library item to begin checkout</h2>\r
+                 <input type="text" jsId='selfckScanBox' class="userid" id="selfckScanBox" dojoType='dijit.form.TextBox' />\r
+        </div>\r
+        <br />\r
+\r
+        <div id="step3a" style="">\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%" height="70"><tr><td width="100%"><div id='oils-selfck-status-div' class="oils-selfck-status-div"></div></td></tr></table>\r
+                 <div id='oils-selfck-scan-text' class='hidden'></div>\r
+          <br /><br />\r
+          <table cellpadding="5" cellspacing="0" border="0" class="item_table" width="100%">\r
+                  <tbody id='oils-selfck-circ-tbody'>\r
+               <tr id='oils-selfck-circ-row'><td>\r
+              <table cellpadding="2" cellspacing="0" border="0">\r
+                <tr><td class="label">BARCODE:</td><td name="barcode"></td></tr>\r
+                <tr><td class="label">TITLE:</td><td name="title"></td></tr>\r
+                <tr><td class="label" nowrap="nowrap">DUE DATE:</td><td name="due_date"></td></tr>\r
+                               <tr><td></td><td><div class="hidden"><div name='checkout' class='hidden'>Checkout</div><div name='renew' class='hidden'>Renewal</div></div></td></tr>\r
+              </table>\r
+            </td></tr>\r
+                  </tbody>\r
+          </table>\r
+        </div>\r
+        \r
+        <div id="step3c" style="display:none;">\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center" style="font-weight:bold;font-size:20px;">Fines</td></tr></table>\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td><a href="javascript:;" onclick="selfCheckMgr.printList('fines')"><img src="[% ctx.home_path %]/graphics/printlist.jpg" alt='print' /></a></td><td class="hidden"><a class="hidden" href="javascript:;" id="oils-selfck-pay-fines-link">Pay Fines</a></td></tr></table><br />\r
+          <table cellpadding="5" cellspacing="0" border="0" class="item_table" width="100%">\r
+                  <tbody id='oils-selfck-fines-tbody'>\r
+               <tr id='oils-selfck-fines-row'><td width="443">\r
+              <table cellpadding="2" cellspacing="0" border="0" width="100%">\r
+                <tr><td class="label"><input style="float:left;margin:2px;" class="hidden" type="checkbox" checked="checked" name='selector' onclick='selfCheckMgr.keepMeLoggedIn();' title='pay this fine' /> TITLE:</td><td name="title"></td></tr>\r
+                <tr><td class="label">DUE DATE:</td><td name="due_date"></td></tr>\r
+                <tr><td class="label">DATE RETURN:</td><td name="date_return"></td></tr>\r
+                <tr><td class="label">BALANCE OWED:</td><td style="color:red;">$<span name="balance"></span></td></tr>\r
+              </table>\r
+            </td></tr>\r
+                  </tbody>\r
+          </table>\r
+<div id="pay_fines" class="hidden">\r
+[% INCLUDE 'default/circ/selfcheck/payment.tt2' %]\r
+</div>\r
+        </div>\r
+        \r
+               <div id="step3d" style="display:none;">\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center" style="font-weight:bold;font-size:20px;">Items Checked Out</td></tr></table><br />\r
+          <a href="javascript:;" onclick="selfCheckMgr.printList('items_out');"><img src="[% ctx.home_path %]/graphics/printlist.jpg" alt='print' /></a><br /><br />\r
+          <table cellpadding="5" cellspacing="0" border="0" class="item_table" width="100%">\r
+                  <tbody id='oils-selfck-circ-out-tbody'>\r
+               <tr id='oils-selfck-circ-out-row'><td>\r
+              <table cellpadding="2" cellspacing="0" border="0">\r
+               <tr><td class="label">BARCODE:</td><td name="barcode"></td></tr>\r
+                <tr><td class="label">TITLE:</td><td name="title"></td></tr>\r
+                <tr><td class="label">AUTHOR:</td><td name="author"></td></tr>\r
+                <tr><td class="label">DUE DATE:</td><td name="due_date"></td></tr>\r
+                <tr><td class="label hidden">FORMAT:</td><td class="hidden" name="format"></td></tr>\r
+              </table>\r
+            </td></tr>\r
+                  </tbody>\r
+          </table>\r
+        </div>\r
+        \r
+        <div id="step3e" style="display:none;">\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center" style="font-weight:bold;font-size:20px;">Items Ready for Pick-Up</td></tr></table><br />\r
+          <a href="javascript:;"><img src="[% ctx.home_path %]/graphics/printlist.jpg" alt='print' /></a><br /><br />\r
+          <table cellpadding="5" cellspacing="0" border="0" class="item_table" width="100%">\r
+                  <tbody id='oils-selfck-rdy-tbody'>\r
+               <tr id='oils-selfck-rdy-row'><td>\r
+              <table cellpadding="2" cellspacing="0" border="0">\r
+                <tr><td class="label">TITLE:</td><td name="title"></td></tr>\r
+                <tr><td class="label hidden">FORMAT:</td><td name="format" class="hidden"></td></tr>\r
+                <tr><td class="label">PICKUP LOCATION:</td><td name="lib"></td></tr>\r
+                <tr><td class="label">PICK UP BY:</td><td name="date"></td></tr>\r
+              </table>\r
+            </td></tr>\r
+                  </tbody>\r
+          </table>\r
+        </div>\r
+        \r
+        <div id="step3f" style="display:none;">\r
+          <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center" style="font-weight:bold;font-size:20px;">Holds</td></tr></table><br />\r
+          <a href="javascript:;" onclick="selfCheckMgr.printList('holds')"><img alt='print' src="[% ctx.home_path %]/graphics/printlist.jpg" /></a><br /><br />\r
+          <table cellpadding="5" cellspacing="0" border="0" class="item_table" width="100%">\r
+                  <tbody id='oils-selfck-hold-tbody'>\r
+               <tr id='oils-selfck-hold-row'><td>\r
+              <table cellpadding="2" cellspacing="0" border="0">\r
+                <tr><td class="label">TITLE:</td><td name="title"></td></tr>\r
+                <tr><td class="label">AUTHOR:</td><td name="author"></td></tr>\r
+                <tr><td class="label hidden">FORMAT:</td><td class="hidden" name="format"></td></tr>\r
+                <tr><td class="label">STATUS:</td><td name="status"></td></tr>\r
+              </table>\r
+            </td></tr>\r
+                  </tbody>\r
+          </table>\r
+        </div>\r
+\r
+      </td>\r
+      <td class="sidebar" valign="top" width="226">\r
+          <div id="floatdiv" style="position:relative; width:226px; height:375px;left:0px;top:0px;z-index:100;">\r
+               <h3 class="top" id="todays_date"></h3>\r
+        <div class="greet">Hello, <span id="user_name"></span>.</div>\r
+        <h3>Your Account</h3>\r
+        <p id="sidebar_step3c">Fines: <span id="acct_fines"></span><br /><a href="javascript:;" id='oils-selfck-view-fines-link'>View Details</a></p>\r
+        <p id="sidebar_step3d">(<span id="oils-selfck-circ-account-total">0) Items</span> Checked Out<br /><a href="javascript:;" id='oils-selfck-items-out-details-link'>View Details</a></p>\r
+        <p id="sidebar_step3e">(<span id="oils-selfck-holds-ready">0) Items</span> Ready for Pick-Up<br /><a href="javascript:;" onclick="selfCheckMgr.drawHoldsPage();">View Details</a></p>\r
+        <p id="sidebar_step3f">(<span id="oils-selfck-holds-total">0) Items</span> on Hold<br /><a href="javascript:;" id='oils-selfck-hold-details-link'>View Details</a></p>\r
+\r
+               <div style="padding-left:40px;padding-top:10px;">\r
+          <div style="padding-bottom:5px;"><a href="javascript:;" id='oils-selfck-nav-logout-print'><img alt='logout with receipt' src="[% ctx.home_path %]/graphics/logoutbutton.jpg" style="" /></a></div>\r
+          <div style=""><a href="javascript:;" id='oils-selfck-nav-logout'><img alt='logout without receipt' src="[% ctx.home_path %]/graphics/logoutwithoutreceiptbutton.jpg" style="" /></a></div>\r
+        </div>\r
+        <div style="clear:both;padding-top:15px;padding-left:3px;">\r
+          <a href="javascript:;" id="back_button" onclick="selfCheckMgr.keepMeLoggedIn();switchTo('step3');"><img alt='back to checkout' src="[% ctx.home_path %]/graphics/arrow.gif" /></a> <a href="javascript:;" onclick="selfCheckMgr.keepMeLoggedIn();switchTo('step3');"><span style="position:relative;top:-4px;left:2px;">Back to Checkout</span></a>\r
+        </div>\r
+          </div>\r
+<script src="[% ctx.media_prefix %]/js/ui/kcls/circ/selfcheck/floating.js"></script>\r
+      </td></tr>\r
+    </table>\r
+  </div>\r
+  \r
+  <div id="step4" class="checkout" style="padding-top:15px;display:none;">\r
+       <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center"><h1>Checkout Complete.<br />Please take your reciept.</h1></td></tr></table>\r
+  </div>\r
+  \r
+  <div id="step5" class="checkout" style="padding-top:15px;display:none;">\r
+       <table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td align="center"><h1>Checkout Complete.</h1></td></tr></table>\r
+  </div>\r
+  \r
+  \r
+       <div style='clear:both;'></div> \r
+  </div>\r
+</div>\r
+</div>\r
+<!-- ***************************************** END: main.tt2 ***************************************************** -->\r
+[% END %]
\ No newline at end of file
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/patron_login.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/patron_login.tt2
new file mode 100644 (file)
index 0000000..da65d79
--- /dev/null
@@ -0,0 +1,7 @@
+<div>Please login using your library barcode</div>
+<div class='oils-selfck-login-box'>
+    <input jsId='selfckBarcodeBox' dojoType='dijit.form.TextBox'></input>
+</div>
+<div id='oils-selfck-login-pw' class='hidden oils-selfck-login-box'>
+    <input jsId='selfckPwBox' dojoType='dijit.form.TextBox'></input>
+</div>
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/payment.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/payment.tt2
new file mode 100644 (file)
index 0000000..f4fe97e
--- /dev/null
@@ -0,0 +1,83 @@
+<div id='oils-selfck-cc-payment-summary'>
+    Total amount to pay: $<span></span>
+</div>
+<table id='oils-selfck-cc-payment-table'>
+    <tbody>
+        <!-- Technically not needed since card type is derived from the CC number
+        <tr>
+            <td>Type of Card</td>
+            <td>
+                <select dojoType='dijit.form.FilteringSelect' jsId='oilsSelfckCCType' required='true'>
+                    <option value='VISA'>VISA</option>
+                    <option value='MasterCard'>MasterCard</option>
+                    <option value='American Express'>American Express</option>
+                </select>
+            </td>
+        </tr>
+        -->
+        <tr>
+            <td>Credit Card #</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCNumber' required='true'/></td>
+        </tr>
+        <tr>
+            <td>CVV #</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCCVV' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Exipration Month</td>
+            <td>
+                <select dojoType='dijit.form.FilteringSelect' jsId='oilsSelfckCCMonth' required='true'>
+                    <option value='01' selected='selected'>Jan</option>
+                    <option value='02'>Feb</option>
+                    <option value='03'>Mar</option>
+                    <option value='04'>April</option>
+                    <option value='05'>May</option>
+                    <option value='06'>June</option>
+                    <option value='07'>July</option>
+                    <option value='08'>Aug</option>
+                    <option value='09'>Sept</option>
+                    <option value='10'>Oct</option>
+                    <option value='11'>Nov</option>
+                    <option value='12'>Dec</option>
+                </select>
+            </td>
+        </tr>
+        <tr>
+            <td>Expiration Year</td>
+            <td><input dojoType='dijit.form.NumberSpinner' constraints='{pattern:"0000", places:0, maxlength:4}' jsId='oilsSelfckCCYear' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Edit Billing Details</td>
+            <td><input dojoType='dijit.form.CheckBox' jsId='oilsSelfckEditDetails'/></td>
+        </tr>
+        <tr>
+            <td>First Name</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCFName' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Last Name</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCLName' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Street Address</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCStreet' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>City</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCCity' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>State or Province</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCState' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>ZIP or Postal Code</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCZip' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td colspan='2' align='center'>
+                <button dojoType='dijit.form.Button' jsId='oilsSelfckCCSubmit'>Submit Payment</button>
+            </td>
+        </tr>
+    </tbody>
+</table>
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/style.css b/Open-ILS/web/local_templates/default/circ/selfcheck/style.css
new file mode 100644 (file)
index 0000000..4f342db
--- /dev/null
@@ -0,0 +1,179 @@
+@charset "utf-8";\r
+/* CSS Document */\r
+\r
+html, body {\r
+       margin:0;\r
+       font-family: Arial, Helvetica, sans-serif;\r
+       font-size: 12px;\r
+       background:#333;\r
+       width:100%;\r
+}\r
+\r
+img {\r
+       border: none;\r
+}\r
+\r
+a {\r
+       color: #003399;\r
+       text-decoration: none;\r
+}\r
+\r
+a:hover {\r
+       text-decoration: underline;\r
+}\r
+\r
+h1 {\r
+       margin:0;\r
+       margin-bottom: 5px;\r
+       font-size: 20px;\r
+       font-weight:normal;\r
+}\r
+\r
+h2 {\r
+       margin:0;\r
+       margin-bottom: 5px;\r
+       font-size: 14px;\r
+       font-weight:bold;\r
+}\r
+\r
+#header {\r
+       color: #bda964;\r
+       font-weight:bold;\r
+       padding: 12px 0px 9px 17px;\r
+       width: 694px;\r
+       margin: auto;\r
+}\r
+\r
+#content-wrapper {\r
+       background: white;\r
+       min-height: 260px;\r
+       border-bottom: 1px solid black;\r
+}\r
+\r
+#main-content {\r
+       width: 694px;\r
+       margin:auto;\r
+       padding-left:17px;\r
+}\r
+\r
+.checkout {\r
+       font-size:16px;\r
+}\r
+\r
+.checkout h1 {\r
+       font-size:36px;\r
+}\r
+\r
+.checkout h2 {\r
+       font-size:24px;\r
+}\r
+\r
+.checkout .sidebar h3 {\r
+       font-size: 16px;\r
+       margin:0;\r
+       padding-left:3px;\r
+}\r
+\r
+.checkout .sidebar a {\r
+       font-size:12px;\r
+}\r
+\r
+.checkout .sidebar a span {\r
+       font-weight:bold;\r
+}\r
+\r
+.checkout .sidebar p {\r
+       margin:4px 0px;\r
+       padding:3px;\r
+}\r
+\r
+.checkout .sidebar div, .checkout .sidebar p {\r
+       font-size: 16px;\r
+       line-height: 1em;\r
+}\r
+\r
+.checkout input[type=text], .checkout input[type=password] {\r
+       border: 1px solid black;\r
+       width:300px;\r
+       height:20px;\r
+       padding:2px;\r
+       padding-top:1px;\r
+       margin:0px;\r
+       font-size:16px;\r
+}\r
+\r
+.checkout .sidebar {\r
+       background: #b0b0b0;\r
+       border-left:2px ridge #eee;\r
+       border-right:2px ridge #eee;\r
+       padding:10px 7px;\r
+}\r
+\r
+.checkout .sidebar .top {\r
+       float:right;\r
+       padding-right:5px;\r
+}\r
+\r
+.checkout .sidebar .greet {\r
+       clear:both;\r
+       padding:15px 3px;\r
+}\r
+\r
+.checkout .sidebar .selected {\r
+       background:#999\r
+}\r
+\r
+.checkout .header1 {\r
+       height:108px;\r
+       border-bottom:1px solid #a83135;\r
+       padding-top:20px;\r
+}\r
+\r
+.checkout .userid {\r
+       width:200px;\r
+       font-size:16px;\r
+       font-weight:bold;\r
+       padding:5px 6px 6px 6px !important;\r
+       border:2px solid black !important;\r
+       background: none !important;\r
+       margin:0 !important;\r
+}\r
+\r
+.checkout .item_table {\r
+       border-collapse: collapse;\r
+}\r
+\r
+.checkout .item_table td {\r
+       font-size:16px;\r
+       border:2px solid black;\r
+       text-align: left;\r
+}\r
+\r
+.checkout .item_table table td.label {\r
+       font-weight:bold;\r
+       text-transform: uppercase;\r
+       text-align: right;\r
+       white-space:nowrap;\r
+       padding-right:5px;\r
+       width:1px;\r
+}\r
+\r
+.checkout .item_table table td {\r
+       border:none;\r
+}\r
+\r
+.checkout #back_button:hover {\r
+       text-decoration: none;\r
+}\r
+\r
+.checkout .status_box {\r
+       color:red;\r
+       font-weight:bold;\r
+       height:20px;\r
+}\r
+\r
+.checkout .oils-selfck-status-div {\r
+       height:inherit !important;\r
+       vertical-align:inherit !important;\r
+}\r
+\r
diff --git a/Open-ILS/web/local_templates/default/circ/selfcheck/summary.tt2 b/Open-ILS/web/local_templates/default/circ/selfcheck/summary.tt2
new file mode 100644 (file)
index 0000000..b037ad7
--- /dev/null
@@ -0,0 +1,27 @@
+<div id='oils-selfck-circ-info-div'>
+    <div id='oils-selfck-info-nav'>
+        <span><a id='oils-selfck-nav-home' href='javascript:void(0);' class='selected'>Home</a></span>
+        <span><a id='oils-selfck-nav-logout-print' href='javascript:void(0);'>Logout</a></span>
+        <span><a id='oils-selfck-nav-logout' href='javascript:void(0);'>Logout (No Receipt)</a></span>
+    </div>
+    <fieldset>
+        <legend>Items Checked Out</legend>
+        <div id='oils-selfck-circ-session-total'></div>
+        <div id='oils-selfck-circ-account-total'></div>
+        <div><a href='javascript:void(0);' id='oils-selfck-items-out-details-link'>View Items Out</a></div>
+    </fieldset>
+    <fieldset>
+        <legend>Holds</legend>
+        <div id='oils-selfck-holds-ready'></div>
+        <div id='oils-selfck-holds-total'></div>
+        <div><a href='javascript:void(0);' id='oils-selfck-hold-details-link'>View Holds</a></div>
+    </fieldset>
+    <fieldset>
+        <legend>Fines</legend>
+        <div id='oils-selfck-fines-total'></div>
+        <div>
+            <span><a href='javascript:void(0);' id='oils-selfck-view-fines-link'>View Details</a></span>
+        </div>
+    </fieldset>
+</div>
+