[open-ils-commits] r17473 - in branches/rel_2_0/Open-ILS: web/opac/locale/en-US xul/staff_client/server/locale/en-US xul/staff_client/server/serial xul/staff_client/server/skin (senator)

svn at svn.open-ils.org svn at svn.open-ils.org
Fri Sep 3 12:32:23 EDT 2010


Author: senator
Date: 2010-09-03 12:32:19 -0400 (Fri, 03 Sep 2010)
New Revision: 17473

Added:
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/common.js
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.js
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.xul
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul
Modified:
   branches/rel_2_0/Open-ILS/web/opac/locale/en-US/lang.dtd
   branches/rel_2_0/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive.js
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.js
   branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.xul
   branches/rel_2_0/Open-ILS/xul/staff_client/server/skin/serial.css
Log:
Backport r17472 from trunk, serials pattern code wizard


Modified: branches/rel_2_0/Open-ILS/web/opac/locale/en-US/lang.dtd
===================================================================
--- branches/rel_2_0/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/web/opac/locale/en-US/lang.dtd	2010-09-03 16:32:19 UTC (rev 17473)
@@ -1567,6 +1567,9 @@
 <!ENTITY staff.serial.mfhd_menu.add.label "Add MFHD Record">
 <!ENTITY staff.serial.mfhd_menu.edit.label "Edit MFHD Record">
 <!ENTITY staff.serial.mfhd_menu.delete.label "Delete MFHD Record">
+<!ENTITY staff.serial.scap_editor.pattern_wizard "Pattern Code Wizard">
+<!ENTITY staff.serial.scap_editor.pattern_wizard.accesskey "Z">
+<!ENTITY staff.serial.scap_editor.modify.accesskey "M">
 <!ENTITY staff.serial.scap_editor.modify "Modify Caption and Pattern(s)">
 <!ENTITY staff.serial.scap_editor.modify.accesskey "M">
 <!ENTITY staff.serial.scap_editor.create "Create Caption and Pattern(s)">

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/locale/en-US/serial.properties	2010-09-03 16:32:19 UTC (rev 17473)
@@ -67,3 +67,18 @@
 batch_receive.cn_for_lib=Do you want to use this call number at %1$s?\nIt doesn't exist there, and it will have to be created.
 batch_receive.missing_units=You have not provided barcodes and call numbers for all of the selected items.  Choose OK to receive those items anyway, or choose Cancel to supply the missing information.
 batch_receive.missing_cn=You cannot assign a barcode without selecting a call number. Please correct the non-conforming units.
+pattern_wizard.enumeration.a=First level
+pattern_wizard.enumeration.b=Second level
+pattern_wizard.enumeration.c=Third level
+pattern_wizard.enumeration.d=Fourth level
+pattern_wizard.enumeration.e=Fifth level
+pattern_wizard.enumeration.f=Sixth level
+pattern_wizard.enumeration.g=First alternate
+pattern_wizard.enumeration.h=Second alternate
+pattern_wizard.chronology.i=First level
+pattern_wizard.chronology.j=Second level
+pattern_wizard.chronology.k=Third level
+pattern_wizard.chronology.l=Fourth level
+pattern_wizard.chronology.m=Alternative numbering scheme
+pattern_wizard.not_removable_row=You cannot remove this row because it's not at the end of the sequence.  Remove later rows first.
+pattern_wizard.bad_date_value=That is not a valid day for that month.

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive.js
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive.js	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive.js	2010-09-03 16:32:19 UTC (rev 17473)
@@ -1,7 +1,6 @@
+/* The code in this file relies on common.js */
+
 dojo.require("dojo.cookie");
-dojo.require("dojo.date.locale");
-dojo.require("dojo.date.stamp");
-dojo.require("dojo.string");
 dojo.require("openils.Util");
 dojo.require("openils.User");
 dojo.require("openils.CGI");
@@ -9,61 +8,6 @@
 
 var batch_receiver;
 
-String.prototype.trim = function() {return this.replace(/^\s*(.+)\s*$/,"$1");}
-
-/**
- * hard_empty() is needed because dojo.empty() doesn't seem to work on
- * XUL nodes. This also means that dojo.place() with a position argument of
- * "only" doesn't do what it should, but calling hard_empty() on the refnode
- * first will do the trick.
- */
-function hard_empty(node) {
-    if (typeof(node) == "string")
-        node = dojo.byId(node);
-
-    if (node && node.childNodes.length > 0) {
-        dojo.forEach(
-            node.childNodes,
-            function(c) {
-                if (c) {
-                    if (c.childNodes.length > 0)
-                        dojo.forEach(c.childNodes, hard_empty);
-                    dojo.destroy(c);
-                }
-            }
-        );
-    }
-}
-
-function hide(e) {
-    if (typeof(e) == "string") e = dojo.byId(e);
-    openils.Util.addCSSClass(e, "hideme");
-}
-
-function show(e) {
-    if (typeof(e) == "string") e = dojo.byId(e);
-    openils.Util.removeCSSClass(e, "hideme");
-}
-
-function hide_table_cell(e) {
-    if (typeof(e) == "string") e = dojo.byId(e);
-
-    e.style.display = "none";
-    e.style.visibility = "hidden";
-}
-
-function show_table_cell(e) {
-    if (typeof(e) == "string") e = dojo.byId(e);
-    e.style.display = "table-cell";
-    e.style.visibility = "visible";
-}
-
-function busy(on) {
-    if (typeof(busy._window) == "undefined")
-        busy._window = dojo.query("window")[0];
-    busy._window.style.cursor = on ? "wait" : "auto";
-}
-
 function S(k) {
     return dojo.byId("serialStrings").getString("batch_receive." + k).
         replace("\\n", "\n");
@@ -74,15 +18,6 @@
         getFormattedString("batch_receive." + k, args).replace("\\n", "\n");
 }
 
-function T(s) { return document.createTextNode(s); }
-function D(s) {return s ? openils.Util.timeStamp(s,{"selector":"date"}) : "";}
-function node_by_name(s, ctx) {return dojo.query("[name='"+ s +"']",ctx)[0];}
-
-function num_sort(a, b) {
-    [a, b] = [Number(a), Number(b)];
-    return a > b ? 1 : (a < b ? -1 : 0);
-}
-
 function BatchReceiver() {
     var self = this;
 

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/batch_receive_overlay.xul	2010-09-03 16:32:19 UTC (rev 17473)
@@ -6,10 +6,11 @@
     xmlns:h="http://www.w3.org/1999/xhtml"
     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
+    <script type="text/javascript" src="/xul/server/serial/common.js" />
     <script type="text/javascript" src="/xul/server/serial/batch_receive.js" />
 
     <box id="batch_receive_main" flex="1" orient="vertical" class="my_overflow">
-        <caption label="&staff.serial.batch_receive;" />
+        <caption class="top" label="&staff.serial.batch_receive;" />
 
         <vbox flex="1" id="batch_receve_main_action">
             <vbox id="batch_receive_bib" class="hideme">

Copied: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/common.js (from rev 17472, trunk/Open-ILS/xul/staff_client/server/serial/common.js)
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/common.js	                        (rev 0)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/common.js	2010-09-03 16:32:19 UTC (rev 17473)
@@ -0,0 +1,62 @@
+String.prototype.trim = function() {return this.replace(/^\s*(.+)\s*$/,"$1");}
+
+/**
+ * hard_empty() is needed because dojo.empty() doesn't seem to work on
+ * XUL nodes. This also means that dojo.place() with a position argument of
+ * "only" doesn't do what it should, but calling hard_empty() on the refnode
+ * first will do the trick.
+ */
+function hard_empty(node) {
+    if (typeof(node) == "string")
+        node = dojo.byId(node);
+    if (node)
+        dojo.forEach(node.childNodes, dojo.destroy);
+}
+
+function hide(e) {
+    if (typeof(e) == "string") e = dojo.byId(e);
+    openils.Util.addCSSClass(e, "hideme");
+}
+
+function show(e) {
+    if (typeof(e) == "string") e = dojo.byId(e);
+    openils.Util.removeCSSClass(e, "hideme");
+}
+
+function hide_table_cell(e) {
+    if (typeof(e) == "string") e = dojo.byId(e);
+
+    e.style.display = "none";
+    e.style.visibility = "hidden";
+}
+
+function show_table_cell(e) {
+    if (typeof(e) == "string") e = dojo.byId(e);
+    e.style.display = "table-cell";
+    e.style.visibility = "visible";
+}
+
+function soft_hide(e) { /* doesn't disrupt XUL grid alignment */
+    if (typeof(e) == "string") e = dojo.byId(e);
+    e.style.visibility = "hidden";
+}
+
+function soft_show(e) {
+    if (typeof(e) == "string") e = dojo.byId(e);
+    e.style.visibility = "visible";
+}
+
+function busy(on) {
+    if (typeof(busy._window) == "undefined")
+        busy._window = dojo.query("window")[0];
+    busy._window.style.cursor = on ? "wait" : "auto";
+}
+
+function T(s) { return document.createTextNode(s); }
+function D(s) {return s ? openils.Util.timeStamp(s, {"selector":"date"}) : "";}
+function node_by_name(s, ctx) {return dojo.query("[name='" + s + "']", ctx)[0];}
+
+function num_sort(a, b) {
+    [a, b] = [Number(a), Number(b)];
+    return a > b ? 1 : (a < b ? -1 : 0);
+}

Copied: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.js (from rev 17472, trunk/Open-ILS/xul/staff_client/server/serial/pattern_wizard.js)
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.js	                        (rev 0)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.js	2010-09-03 16:32:19 UTC (rev 17473)
@@ -0,0 +1,609 @@
+/* The code in this file relies on common.js */
+
+dojo.require("openils.Util");
+
+var wizard;
+
+function S(k) {
+    return dojo.byId("serialStrings").getString("pattern_wizard." + k).
+        replace("\\n", "\n");
+}
+
+function _month_menuitems() {
+    /* XXX i18n, and also this is just pathetic in general, but a datepicker
+     * seemed wrong since we don't want a year. */
+    return [
+        ["01", "January"],
+        ["02", "February"],
+        ["03", "March"],
+        ["04", "April"],
+        ["05", "May"],
+        ["06", "June"],
+        ["07", "July"],
+        ["08", "August"],
+        ["09", "September"],
+        ["10", "October"],
+        ["11", "November"],
+        ["12", "December"]
+    ].map(
+        function(t) {
+            return dojo.create("menuitem", {"value": t[0], "label": t[1]});
+        }
+    );
+}
+
+function _date_validate(date_val, month_val) {
+    /* general purpose date validation irrespective of year */
+    date_val = date_val.trim();
+
+    if (!date_val.match(/^[0123]?\d$/))
+        return false;
+
+    date_val = Number(date_val); /* do NOT use parseInt */
+    month_val = Number(month_val);
+
+    if (date_val < 1) {
+        return false;
+    } else if (month_val == 2) {
+        return date_val <= 29;
+    } else if ([1,3,5,7,8,10,12].indexOf(month_val) != -1) {
+        return date_val <= 31;
+    } else {
+        return date_val <= 30;
+    }
+}
+
+function CalendarChangeRow() {
+    var self = this;
+
+    this._init = function(template, id, manager) {
+        this.element = dojo.clone(template);
+
+        this.point_widgets = ["month", "season", "date"].map(
+            function(type) { return node_by_name(type, self.element); }
+        );
+
+        dojo.attr(
+            node_by_name("type", this.element), "oncommand", function(ev) {
+                self.point_widgets.forEach(
+                    function(w) {
+                        var active = (dojo.attr(w, "name") == ev.target.value);
+                        (active ? show : hide)(w);
+                    }
+                );
+            }
+        );
+
+        var date_month_selector = node_by_name("date_month", this.element);
+
+        dojo.attr(
+            node_by_name("date_day", this.element), "onchange", function(ev) {
+                if (_date_validate(ev.target.value,date_month_selector.value)){
+                    return true;
+                } else {
+                    alert(S("bad_date_value"));
+                    ev.target.focus();
+                    return false;
+                }
+            }
+        );
+
+        this.remover = node_by_name("remover", this.element);
+        dojo.attr(
+            this.remover, "onclick", function() { manager.remove_row(id); }
+        );
+    };
+
+    this._compile_month = function() {
+        return node_by_name("month", this.element).value;
+    };
+
+    this._compile_season = function() {
+        return node_by_name("season", this.element).value;
+    };
+
+    this._compile_date = function() {
+        var n = Number(node_by_name("date_day", this.element).value);
+        if (n < 10)
+            n = "0" + String(n);
+        else
+            n = String(n);
+
+        return node_by_name("date_month", this.element).value + n;
+    };
+
+    this.compile = function() {
+        var type = node_by_name("type", this.element).value;
+
+        return this["_compile_" + type]();
+    };
+
+    this._init.apply(this, arguments);
+};
+
+function CalendarChangeEditor() {
+    var self = this;
+
+    this._init = function() {
+        this.rows = {};
+        this.row_count = 0;
+
+        this._get_template();
+        this.add_row();
+    };
+
+    this._get_template = function() {
+        var temp_template = dojo.byId("calendar_row_template");
+        this.grid = temp_template.parentNode;
+        this.template = this.grid.removeChild(temp_template);
+        this.template.removeAttribute("id");
+
+        [
+            dojo.query("[name='month'] menupopup", this.template)[0],
+            dojo.query("[name='date_month'] menupopup", this.template)[0]
+        ].forEach(
+            function(menupopup) {
+                _month_menuitems().forEach(
+                    function(menuitem) {
+                        dojo.place(menuitem, menupopup, "last");
+                    }
+                );
+            }
+        );
+    };
+
+    this.remove_row = function(id) {
+        hard_empty(this.rows[id].element);
+        dojo.destroy(this.rows[id].element);
+        delete this.rows[id];
+
+        dojo.byId("calendar_change_add_row").disabled = false;
+    };
+
+    this.add_row = function() {
+        var id = this.row_count++;
+
+        this.rows[id] =
+            new CalendarChangeRow(dojo.clone(this.template), id, this);
+        dojo.place(this.rows[id].element, this.grid, "last");
+    };
+
+    this.toggle = function(ev) {
+        (ev.target.checked ? show : hide)("calendar_change_editor_here");
+    };
+
+    this.compile = function() {
+        return [
+            "x",
+            openils.Util.objectProperties(this.rows).sort(num_sort).map(
+                function(key) { return self.rows[key].compile(); }
+            ).join(",")
+        ];
+    };
+
+    this._init.apply(this, arguments);
+}
+
+function ChronRow() {
+    var self = this;
+
+    this._init = function(template, subfield, manager) {
+        this.subfield = subfield;
+        this.element = dojo.clone(template);
+
+        dojo.attr(
+            node_by_name("caption_label", this.element),
+            "value", S("chronology." + subfield) + ":"
+        );
+
+        this.fields = {};
+        ["caption", "display_in_holding"].forEach(
+            function(o) { self.fields[o] = node_by_name(o, self.element); }
+        );
+
+        this.remover = node_by_name("remover", this.element);
+        dojo.attr(
+            this.remover, "onclick", function(){ manager.remove_row(subfield); }
+        );
+    };
+
+    this._init.apply(this, arguments);
+};
+
+function ChronEditor() {
+    /* TODO make this enforce unique caption values for each row? */
+    var self = this;
+
+    this._init = function() {
+        this.rows = {};
+
+        this.subfields = ["i", "j", "k", "l", "m"];
+
+        this._get_template();
+        this.add_row();
+    };
+
+    this._get_template = function() {
+        var temp_template = dojo.byId("chron_row_template");
+        this.grid = temp_template.parentNode;
+        this.template = this.grid.removeChild(temp_template);
+        this.template.removeAttribute("id");
+    };
+
+    this._test_removability = function(subfield) {
+        var start = this.subfields.indexOf(subfield);
+
+        if (start < 0) {
+            /* no such field, not OK to remove */
+            return false;
+        } else if (!this.subfields[start]) {
+            /* field row not present, not OK to remove */
+            return false;
+        }
+
+        var next = this.subfields[start + 1];
+        if (typeof(next) == "undefined") { /* last in set, ok to remove */
+            return true;
+        } else {
+            if (this.rows[next]) { /* NOT last in set, not ok to remove */
+                return false;
+            } else { /* last in set actually present, ok to remove */
+                return true;
+            }
+        }
+    };
+
+    this.remove_row = function(subfield) {
+        if (this._test_removability(subfield)) {
+            hard_empty(this.rows[subfield].element);
+            dojo.destroy(this.rows[subfield].element);
+            delete this.rows[subfield];
+
+            dojo.byId("chron_add_row").disabled = false;
+        } else {
+            alert(S("not_removable_row"));
+        }
+    };
+
+    this.add_row = function() {
+        var available = this.subfields.filter(
+            function(subfield) { return !Boolean(self.rows[subfield]); }
+        );
+
+        if (available.length) {
+            var subfield = available.shift();
+            if (!available.length)
+                dojo.byId("chron_add_row").disabled = true;
+        } else {
+            /* We shouldn't really be able to get here. */
+            return;
+        }
+
+        this.rows[subfield] =
+            new ChronRow(dojo.clone(this.template), subfield, this);
+
+        dojo.place(this.rows[subfield].element, this.grid, "last");
+    };
+
+    this.toggle = function(ev) {
+        (ev.target.checked ? show : hide)("chron_editor_here");
+    };
+
+    this.compile = function() {
+        return this.subfields.filter(
+            function(subfield) { return Boolean(self.rows[subfield]); }
+        ).reduce(
+            function(result, subfield) {
+                var caption = self.rows[subfield].fields.caption.value;
+                if (!self.rows[subfield].fields.display_in_holding.checked)
+                    caption = "(" + caption + ")";
+                return result.concat([subfield, caption]);
+            }, []
+        );
+    };
+
+    this._init.apply(this, arguments);
+}
+
+function EnumRow() {
+    var self = this;
+
+    this._init = function(template, subfield, manager) {
+        this.subfield = subfield;
+        this.element = dojo.clone(template);
+
+        this.fields = {};
+        ["caption","units_per","units_per_number","continuity","remover"].
+            forEach(
+                function(o) { self.fields[o] = node_by_name(o, self.element); }
+            );
+
+        if (subfield == "a" || subfield == "g") {
+            ["units_per", "continuity"].forEach(
+                function(o) { soft_hide(node_by_name(o, self.element)); }
+            );
+        }
+
+        var caption_id = "enum_caption_" + subfield;
+        var caption_label = node_by_name("caption_label", this.element);
+        dojo.attr(this.fields.caption, "id", caption_id);
+        dojo.attr(caption_label, "control", caption_id);
+        dojo.attr(caption_label, "value", S("enumeration." + subfield) + ":");
+
+        this.remover = this.fields.remover;
+        dojo.attr(
+            this.remover, "onclick", function(){manager.remove_row(subfield);}
+        );
+    };
+
+    this._init.apply(this, arguments);
+};
+
+function EnumEditor() {
+    var self = this;
+
+    this._init = function() {
+        this.normal_rows = {};
+        this.alt_rows = {};
+
+        this.normal_subfields = ["a","b","c","d","e","f"];
+        this.alt_subfields = ["g","h"];
+
+        this._get_template();
+        this.add_normal_row();
+    };
+
+    this._get_template = function() {
+        var temp_template = dojo.byId("enum_row_template");
+        this.grid = temp_template.parentNode;
+        this.template = this.grid.removeChild(temp_template);
+        this.template.removeAttribute("id");
+    };
+
+    this.remove_row = function(subfield) {
+        if (this._test_removability(subfield)) {
+            var add_button = "enum_add_normal_row";
+            var set = this.normal_rows;
+            if (!set[subfield]) {
+                set = this.alt_rows;
+                add_button = "enum_add_alt_row";
+            }
+
+            hard_empty(set[subfield].element);
+            dojo.destroy(set[subfield].element);
+            delete set[subfield];
+            dojo.byId(add_button).disabled = false;
+        } else {
+            alert(S("not_removable_row"));
+        }
+    };
+
+    this._test_removability = function(id) {
+        var set = this.normal_subfields;
+        var rows = this.normal_rows;
+        var start = set.indexOf(id);
+
+        if (start == -1) {
+            set = this.alt_subfields;
+            rows = this.alt_rows;
+            start = set.indexOf(id);
+        }
+
+        if (start < 0) {
+            /* no such field, not OK to remove */
+            return false;
+        } else if (!set[start]) {
+            /* field row not present, not OK to remove */
+            return false;
+        }
+
+        var next = set[start + 1];
+        if (typeof(next) == "undefined") { /* last in set, ok to remove */
+            return true;
+        } else {
+            if (rows[next]) { /* NOT last in set, not ok to remove */
+                return false;
+            } else { /* last in set actually present, ok to remove */
+                return true;
+            }
+        }
+    };
+
+    this.add_normal_row = function() {
+        var available = this.normal_subfields.filter(
+            function(subfield) { return !Boolean(self.normal_rows[subfield]); }
+        );
+        if (available.length) {
+            var subfield = available.shift();
+            if (!available.length) {
+                /* If that was the last available normal row, disable the
+                 * add rows button. */
+                dojo.byId("enum_add_normal_row").disabled = true;
+            }
+        } else {
+            /* We shouldn't really be able to get here. */
+            return;
+        }
+
+        this.normal_rows[subfield] =
+            new EnumRow(dojo.clone(this.template), subfield, this);
+
+        dojo.place(this.normal_rows[subfield].element, this.grid, "last");
+    };
+
+    this.add_alt_row = function() {
+        var available = this.alt_subfields.filter(
+            function(subfield) { return !Boolean(self.alt_rows[subfield]); }
+        );
+        if (available.length) {
+            var subfield = available.shift();
+            if (!available.length) {
+                /* If that was the last available normal row, disable the
+                 * add rows button. */
+                dojo.byId("enum_add_alt_row").disabled = true;
+            }
+        } else {
+            /* We shouldn't really be able to get here. */
+            return;
+        }
+
+        this.alt_rows[subfield] =
+            new EnumRow(dojo.clone(this.template), subfield, this);
+
+        dojo.place(this.alt_rows[subfield].element, this.grid, "last");
+    };
+
+    this.toggle = function(ev) {
+        var func;
+        var use_calendar_change = dojo.byId("use_calendar_change");
+
+        if (ev.target.checked) {
+            func = show;
+            use_calendar_change.disabled = false;
+        } else {
+            use_calendar_change.checked = false;
+            use_calendar_change.doCommand();
+            use_calendar_change.disabled = true;
+            func = hide;
+        }
+
+        func("enum_editor_here");
+    };
+
+    this.compile = function() {
+        var rows = dojo.mixin({}, this.normal_rows, this.alt_rows);
+        var subfields = [].concat(this.normal_subfields, this.alt_subfields);
+
+        return subfields.filter(
+            function(subfield) { return Boolean(rows[subfield]); }
+        ).reduce(
+            function(result, subfield) {
+                var fields = rows[subfield].fields;
+                var pairs = [subfield, fields.caption.value];
+
+                if (subfield != "a" && subfield != "g") {
+                    if (fields.units_per.value == "number") {
+                        if (fields.units_per_number.value) {
+                            pairs = pairs.concat([
+                                "u", fields.units_per_number.value,
+                                "v", fields.continuity.value
+                            ]);
+                        }
+                    } else {
+                        pairs = pairs.concat([
+                            "u", fields.units_per.value,
+                            "v", fields.continuity.value
+                        ]);
+                    }
+                }
+
+                return result.concat(pairs);
+            }, []
+        );
+    };
+
+    this._init.apply(this, arguments);
+}
+
+function Wizard() {
+    var self = this;
+
+    var _step_prefix = "wizard_step_";
+    var _step_regex = new RegExp("^" + _step_prefix + "(.+)$");
+
+    this._init = function(onsubmit) {
+        this._onsubmit = onsubmit;
+
+        this.load();
+        this.reset();
+    };
+
+    this.load = function() {
+        /* The Wizard object will handle simpler parts of the wizard (those
+         * parts with more-or-less static controls) itself, and will
+         * instantiate more specific objects to deal with more dynamic
+         * super-widgets (like the enum and chron editors).
+         */
+        this.steps = dojo.query("[id^='" + _step_prefix + "']").map(
+            function(o) {
+                return dojo.attr(o, "id").match(_step_regex)[1];
+            }
+        );
+
+        this.enum_editor = new EnumEditor();
+        this.chron_editor = new ChronEditor();
+        this.calendar_change_editor = new CalendarChangeEditor();
+
+        this.field_w = dojo.byId("hard_w");
+    };
+
+    this.reset = function() {
+        this.step = 0;
+        this.show_only_step(this.steps[0]);
+        this.step_bounds_check();
+    };
+
+    this.show_step = function(step) { show(_step_prefix + step); }
+    this.hide_step = function(step) { hide(_step_prefix + step); }
+
+    this.step_bounds_check = function() {
+        dojo.byId("wizard_previous_step").disabled = this.step < 1;
+        dojo.byId("wizard_next_step").disabled =
+            this.step >= this.steps.length -1;
+    };
+
+    this.show_only_step = function(to_keep) {
+        this.steps.forEach(
+            function(step) { if (step != to_keep) self.hide_step(step); }
+        );
+        this.show_step(to_keep);
+    };
+
+    this.previous_step = function() {
+        this.show_only_step(this.steps[--(this.step)]);
+        this.step_bounds_check();
+    };
+
+    /* Figure out the what step we're in, and proceed to the next */
+    this.next_step = function() {
+        this.show_only_step(this.steps[++(this.step)]);
+        this.step_bounds_check();
+    };
+
+    this.frequency_type_toggle = function(which) {
+        var other = which == "soft_w" ? "hard_w" : "soft_w";
+
+        dojo.byId(other).disabled = true;
+        dojo.byId(which).disabled = false;
+        dojo.byId(which).focus();
+
+        this.field_w = dojo.byId(which);
+    };
+
+    this.compile = function() {
+        var code = [
+            dojo.byId("ind1").value, dojo.byId("ind2").value,
+            "8", "1" /* TODO find out how to best deal with $8 */
+        ];
+
+        code = code.concat(this.enum_editor.compile());
+        code = code.concat(this.chron_editor.compile());
+
+        code = code.concat("w", this.field_w.value);
+
+        code = code.concat(this.calendar_change_editor.compile());
+
+        return code;
+    };
+
+    this.submit = function() {
+        this._onsubmit(js2JSON(this.compile()));
+        window.close();
+    };
+
+    this._init.apply(this, arguments);
+}
+
+function my_init() {
+    wizard = new Wizard(window.arguments[0]);
+}

Copied: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.xul (from rev 17472, trunk/Open-ILS/xul/staff_client/server/serial/pattern_wizard.xul)
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.xul	                        (rev 0)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard.xul	2010-09-03 16:32:19 UTC (rev 17473)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="/xul/server/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="/xul/server/skin/serial.css" type="text/css"?>
+<!DOCTYPE window PUBLIC "" ""[
+    <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
+]>
+<?xul-overlay href="/xul/server/OpenILS/util_overlay.xul"?>
+<?xul-overlay href="/xul/server/serial/pattern_wizard_overlay.xul"?>
+
+<window id="pattern_wizard_win"
+    onload="try{my_init();font_helper();persist_helper();}catch(E){alert(E);}"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+    <script type="text/javascript">
+        var myPackageDir = "open_ils_staff_client";
+        var IAMXUL = true;
+        var g = {};
+    </script>
+
+    <scripts id="openils_util_scripts" />
+
+    <!-- JSAN is still needed for font_helper stuff, but I'm going to try
+        not to use it otherwise.  -->
+    <script type="text/javascript" src="/xul/server/main/JSAN.js" />
+
+    <messagecatalog id="serialStrings"
+        src="/xul/server/locale/<!--#echo var='locale'-->/serial.properties" />
+
+    <commandset />
+    <box id="pattern_wizard_main" />
+</window>

Copied: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul (from rev 17472, trunk/Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul)
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul	                        (rev 0)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul	2010-09-03 16:32:19 UTC (rev 17473)
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE overlay PUBLIC "" ""[
+    <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
+]>
+<overlay id="pattern_wizard_overlay"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+    <script type="text/javascript" src="/xul/server/serial/common.js" />
+    <script type="text/javascript" src="/xul/server/serial/pattern_wizard.js" />
+
+    <box orient="vertical" id="pattern_wizard_main" flex="1">
+        <caption class="top" label="Pattern Code Wizard" />
+        <vbox flex="1">
+            <hbox align="center" class="padded_bottom">
+                <button id="wizard_previous_step" disabled="true"
+                    icon="go-back" label="Previous"
+                    oncommand="wizard.previous_step();" />
+                <spacer flex="1" />
+                <button id="wizard_next_step" disabled="true"
+                    icon="go-forward" label="Next"
+                    oncommand="wizard.next_step();" />
+            </hbox>
+            <vbox id="wizard_step_captions" class="hideme">
+                <checkbox id="use_enum"
+                    oncommand="wizard.enum_editor.toggle(event);"
+                    label="Use enumerations?" />
+                <vbox id="enum_editor_here" class="hideme">
+                    <description class="step">
+                        "v." and "no." are common first and second level
+                        enumeration captions.
+                    </description>
+                    <grid flex="1">
+                        <columns>
+                            <column />
+                            <column />
+                            <column />
+                            <column />
+                        </columns>
+                        <rows>
+                            <row id="enum_row_headings">
+                                <label value="Enumeration Caption" />
+                                <label value="Units Per Higher Level" />
+                                <label value="Numbering Continuity" />
+                                <label />
+                            </row>
+                            <row id="enum_row_template" align="top">
+                                <vbox>
+                                    <label name="caption_label" />
+                                    <hbox>
+                                        <spacer flex="1" />
+                                        <textbox size="6" name="caption" />
+                                    </hbox>
+                                </vbox>
+                                <radiogroup name="units_per">
+                                    <hbox align="center">
+                                        <radio label="Number" value="number" />
+                                        <textbox name="units_per_number"
+                                            size="6" />
+                                    </hbox>
+                                    <radio label="Varies" value="var" />
+                                    <radio label="Undetermined" value="und" />
+                                </radiogroup>
+                                <menulist name="continuity">
+                                    <menupopup>
+                                        <menuitem value="c" label="Increments continuously" />
+                                        <menuitem value="r" label="Restarts at unit completion" />
+                                    </menupopup>
+                                </menulist>
+                                <button icon="remove" name="remover" label="Remove" />
+                            </row>
+                        </rows>
+                    </grid>
+                    <hbox>
+                        <spacer flex="1" />
+                        <button id="enum_add_normal_row"
+                            icon="add"
+                            label="Add Enumeration" accesskey="E"
+                            oncommand="wizard.enum_editor.add_normal_row();"
+                            />
+                        <spacer flex="1" />
+                        <button id="enum_add_alt_row"
+                            icon="add"
+                            label="Add Alternate Enumeration" accesskey="A"
+                            oncommand="wizard.enum_editor.add_alt_row();"
+                            />
+                        <spacer flex="1" />
+                    </hbox>
+                </vbox>
+            </vbox>
+            <vbox id="wizard_step_calendar_change" class="hideme">
+                <checkbox id="use_calendar_change"
+                    disabled="true"
+                    oncommand="wizard.calendar_change_editor.toggle(event);"
+                    label="Use calendar changes?" />
+                <vbox id="calendar_change_editor_here" class="hideme">
+                    <description class="step">
+                        Identify any points during the year at which the
+                        highest level enumeration caption changes.
+                    </description>
+                    <grid>
+                        <columns>
+                            <column />
+                            <column flex="1" />
+                            <column />
+                        </columns>
+                        <rows>
+                            <row id="calendar_change_row_headings">
+                                <label value="Type" />
+                                <label value="Point" />
+                                <label />
+                            </row>
+                            <row id="calendar_row_template">
+                                <menulist name="type">
+                                    <menupopup>
+                                        <menuitem value="month" label="At start of a month" />
+                                        <menuitem value="season" label="At start of a season" />
+                                        <menuitem value="date" label="On a date" />
+                                    </menupopup>
+                                </menulist>
+                                <hbox align="center">
+                                    <menulist name="month">
+                                        <menupopup>
+                                        </menupopup>
+                                    </menulist>
+                                    <menulist name="season" class="hideme">
+                                        <menupopup>
+                                            <menuitem value="21" label="Spring" />
+                                            <menuitem value="22" label="Summer" />
+                                            <menuitem value="23" label="Autumn" />
+                                            <menuitem value="24" label="Winter" />
+                                        </menupopup>
+                                    </menulist>
+                                    <hbox name="date" class="hideme">
+                                        <menulist name="date_month">
+                                            <menupopup>
+                                            </menupopup>
+                                        </menulist>
+                                        <textbox name="date_day" size="3" />
+                                    </hbox>
+                                </hbox>
+                                <button icon="remove" name="remover" label="Remove" />
+                            </row>
+                        </rows>
+                    </grid>
+                    <hbox pack="center">
+                        <button
+                            id="calendar_change_add_row"
+                            label="Add Calendar Change"
+                            accesskey="C"
+                            oncommand="wizard.calendar_change_editor.add_row();" />
+                    </hbox>
+                </vbox>
+            </vbox>
+            <vbox id="wizard_step_chronology" class="hideme">
+                <checkbox id="use_chron"
+                    oncommand="wizard.chron_editor.toggle(event);"
+                    label="Use chronology captions?" />
+                <vbox id="chron_editor_here" class="hideme">
+                    <description class="step">
+                        Generally, each caption should be a smaller unit of
+                        time than the preceding caption.
+                    </description>
+                    <grid>
+                        <columns>
+                            <column />
+                            <column />
+                            <column flex="1" />
+                            <column />
+                        </columns>
+                        <rows>
+                            <row id="chron_row_headings">
+                                <label />
+                                <label value="Caption" />
+                                <label value="Display in holding field?" />
+                                <label />
+                            </row>
+                            <row id="chron_row_template">
+                                <label name="caption_label" />
+                                <menulist name="caption">
+                                    <menupopup>
+                                        <menuitem label="Year" value="year" />
+                                        <menuitem label="Season" value="season" />
+                                        <menuitem label="Month" value="month" />
+                                        <menuitem label="Week" value="week" />
+                                        <menuitem label="Day" value="day" />
+                                        <menuitem label="Hour" value="hour" />
+                                    </menupopup>
+                                </menulist>
+                                <checkbox name="display_in_holding" />
+                                <button icon="remove" name="remover" label="Remove" />
+                            </row>
+                        </rows>
+                    </grid>
+                    <hbox pack="center">
+                        <button
+                            id="chron_add_row"
+                            label="Add Chronology Caption"
+                            accesskey="C"
+                            oncommand="wizard.chron_editor.add_row();" />
+                    </hbox>
+                </vbox>
+            </vbox>
+            <vbox id="wizard_step_basics" class="hideme">
+                <grid class="padded_bottom">
+                    <columns>
+                        <column />
+                        <column />
+                    </columns>
+                    <rows><!-- TODO hide these inputs if we're doing an 855 -->
+                        <row align="center">
+                            <label align="right" value="Compressibility and Expandability:" />
+                            <menulist id="ind1">
+                                <menupopup>
+                                    <menuitem value="0" label="Cannot compress or expand" />
+                                    <menuitem value="1" label="Can compress but not expand" />
+                                    <menuitem value="2" label="Can compress or expand" />
+                                    <menuitem value="3" label="Unknown" />
+                                </menupopup>
+                            </menulist>
+                        </row>
+                        <row align="center">
+                            <label align="right" value="Caption Evaluation:" />
+                            <menulist id="ind2">
+                                <menupopup>
+                                    <menuitem value="0" label="Captions verified; all levels present" />
+                                    <menuitem value="1" label="Captions verified; all levels may not be present" />
+                                    <menuitem value="2" label="Captions unverified; all levels present" />
+                                    <menuitem value="3" label="Captions unverified; all levels may not be present" />
+                                </menupopup>
+                            </menulist>
+                        </row>
+                    </rows>
+                </grid>
+                <radiogroup
+                    oncommand="wizard.frequency_type_toggle(this.value);">
+                    <grid>
+                        <columns><column /><column /></columns>
+                        <rows>
+                            <row>
+                                <radio
+                                    label="Select fundamental periodicity:"
+                                    accesskey="F" selected="true"
+                                    value="hard_w" />
+                                <menulist id="hard_w">
+                                    <menupopup>
+                                        <menuitem label="Annual" value="a" />
+                                        <menuitem label="Bimonthly" value="b" />
+                                        <menuitem label="Semiweekly" value="c" />
+                                        <menuitem label="Daily" value="d" />
+                                        <menuitem label="Biweekly" value="e" />
+                                        <menuitem label="Semiannual" value="f" />
+                                        <menuitem label="Biennial" value="g" />
+                                        <menuitem label="Triennial" value="h" />
+                                        <menuitem label="Three times a week" value="i" />
+                                        <menuitem label="Three times a month" value="j" />
+                                        <menuitem label="Continuously updated" value="k" />
+                                        <menuitem label="Monthly" value="m" />
+                                        <menuitem label="Quarterly" value="q" />
+                                        <menuitem label="Semimonthly" value="s" />
+                                        <menuitem label="Three times a year" value="t" />
+                                        <menuitem label="Weekly" value="w" />
+                                        <menuitem label="Completely irregular" value="x" />
+                                    </menupopup>
+                                </menulist>
+                            </row>
+                            <row>
+                                <radio
+                                    label="Use number of issues per year:"
+                                    value="soft_w"
+                                    selected="false" accesskey="I" />
+                                <textbox id="soft_w" disabled="true" />
+                            </row>
+                        </rows>
+                    </grid>
+                </radiogroup>
+            </vbox>
+            <vbox id="wizard_step_submit" class="hideme">
+                <description class="step">
+                    Are you ready to create a pattern code from your
+                    selections in this wizard?
+                </description>
+                <hbox pack="center">
+                    <button oncommand="wizard.submit();" icon="accept"
+                        accesskey="P" label="Create Pattern Code" />
+                </hbox>
+            </vbox>
+        </vbox>
+    </box>
+</overlay>

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.js
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.js	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.js	2010-09-03 16:32:19 UTC (rev 17473)
@@ -2,6 +2,7 @@
 // vim:noet:sw=4:ts=4:
 
 JSAN.use('serial.editor_base');
+var pattern_code_key = 'Pattern Code (temporary)';
 
 if (typeof serial == 'undefined') serial = {};
 serial.scap_editor = function (params) {
@@ -98,7 +99,7 @@
                 }
             ],
             [
-                'Pattern Code (temporary)',
+                pattern_code_key,
                 { 
                     render: 'fm.pattern_code() == null ? "" : fm.pattern_code();',
                     input: 'c = function(v){ obj.apply("pattern_code",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.setAttribute("value",obj.editor_values.pattern_code); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
@@ -132,6 +133,24 @@
         obj.editor_base_save('open-ils.serial.caption_and_pattern.batch.update');
     },
 
+    /* Pattern/caption wizard */
+    "pattern_wizard": function() {
+        var obj = this;
+
+        var onsubmit = function(value) {
+            obj.apply("pattern_code", value);
+            obj.summarize(obj.scaps);
+            obj.render();
+        };
+        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+        window.openDialog(
+            xulG.url_prefix("/xul/server/serial/pattern_wizard.xul"),
+            "pattern_wizard",
+            "scrollbars=yes", /* XXX FIXME: scrollbars aren't working. what to do? */
+            onsubmit
+        );
+    },
+
     /******************************************************************************************************/
     'save_attributes' : serial.editor_base.editor_base_save_attributes
 };

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.xul
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.xul	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/serial/scap_editor.xul	2010-09-03 16:32:19 UTC (rev 17473)
@@ -22,6 +22,7 @@
 
 		<hbox id="scap_editor_nav">
 			<spacer flex="1"/>
+			<button id="scap_pattern_wizard" label="&staff.serial.scap_editor.pattern_wizard;" accesskey="&staff.serial.scap_editor.pattern_wizard.accesskey;" oncommand="g.manage_subs.scap_editor.pattern_wizard();" />
 			<button id="scap_save" label="&staff.serial.scap_editor.modify;" hidden="true" accesskey="&staff.serial.scap_editor.modify.accesskey;" oncommand="g.manage_subs.scap_editor.save()" />
 			<!--<button id="cancel" label="&staff.cat.copy_editor.cancel.label;" accesskey="&staff.cat.copy_editor.cancel.accesskey;" oncommand="window.close();"/>-->
 		</hbox>

Modified: branches/rel_2_0/Open-ILS/xul/staff_client/server/skin/serial.css
===================================================================
--- branches/rel_2_0/Open-ILS/xul/staff_client/server/skin/serial.css	2010-09-03 16:30:47 UTC (rev 17472)
+++ branches/rel_2_0/Open-ILS/xul/staff_client/server/skin/serial.css	2010-09-03 16:32:19 UTC (rev 17473)
@@ -1,5 +1,5 @@
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-caption {
+caption.top {
     background-color: #00246b;
     color: #ff6308;
     font-size: 200%;
@@ -10,3 +10,13 @@
 #batch_receive_entry { padding-top: 10px; }
 #entry_submitter { padding: 20px 0; }
 menulist.cn { width: 12em; }
+button[icon="remove"] { min-width: 2.5em; }
+#enum_row_headings label { font-weight: bold; }
+#chron_row_headings label { font-weight: bold; }
+#calendar_change_row_headings label { font-weight: bold; }
+description.step { font-style: italic; font-size: 110%; }
+checkbox:focus:not([label]) .checkbox-label-box {
+    -moz-appearance: none;
+    border: none;
+}
+.padded_bottom { padding-bottom: 10px; }



More information about the open-ils-commits mailing list