[open-ils-commits] ***SPAM*** [GIT] Evergreen ILS branch master updated. 30096667a05670ba6c3a80eb3038be905c66f2d3

Evergreen Git git at git.evergreen-ils.org
Tue Feb 18 12:20:09 EST 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  30096667a05670ba6c3a80eb3038be905c66f2d3 (commit)
      from  3eee581dd7ba3f0c9acb5522cc7c8c32d262184d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 30096667a05670ba6c3a80eb3038be905c66f2d3
Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
Date:   Tue Feb 18 12:15:18 2014 -0500

    LP#1272074 Physical Characteristics Wizard for the MARC Editor (Part II)
    
    These files should have been in the other commit with the above title,
    but I lost them in a rebase effort.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js b/Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
new file mode 100644
index 0000000..daae2b1
--- /dev/null
+++ b/Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
@@ -0,0 +1,523 @@
+if (!dojo._hasResource["openils.widget.PhysCharWizard"]) {
+    dojo._hasResource["openils.widget.PhysCharWizard"] = true;
+
+    dojo.provide("openils.widget.PhysCharWizard");
+    dojo.require("dojo.string");
+    dojo.require("openils.User");
+    dojo.require("openils.Util");
+    dojo.require("openils.PermaCrud");
+    dojo.requireLocalization("openils.widget", "PhysCharWizard");
+
+    (function() {   /* Namespace protection so we can still make little helpers
+                    within our own bubble */
+
+        var _xhtml_ns = "http://www.w3.org/1999/xhtml";
+
+        function _show_button(n, yes) { /* yet another hide/reveal thing */
+            /* This is a re-invented wheel, but I was having trouble
+             * getting my <button>s to react to the disabled property, and
+             * decided to hide/reveal them instead of disable/enable then.
+             * Then I had this need to do it in a consistent way. */
+            n.setAttribute("style", "visibility: " + (yes? "visible":"hidden"));
+        }
+
+        function _get_xul_combobox_value(menulist) {
+            /* XUL comboboxes (<menulist editable="true">) are funny. */
+
+            return menulist.selectedItem ?
+                menulist.selectedItem.value :
+                menulist.label;  /* sic! Even .getAttribute('label') is
+                                    wrong, and anything to do with 'value'
+                                    is also wrong. */
+        }
+
+        /* Within the openils.widget.PhysCharWizard class, methods and
+         * properties that start "_" should be considered private, and others
+         * public.
+         *
+         * The methods whose names end in "_XUL" could be replaced with HTML
+         * versions to make this wizard work as an HTML thing instead of as
+         * a XUL thing.
+         */
+        dojo.declare(
+            "openils.widget.PhysCharWizard", [], {
+                "active": true,
+                "constructor": function(args) {
+                    this._ = openils.widget.PhysCharWizard.localeStrings;
+                    this._cache = openils.widget.PhysCharWizard.cache;
+
+                    /* Reserve a little of the window namespace that we'll need
+                     * (under XUL anyway) */
+                    window._owPCWinstances = window._owPCWinstances || 0;
+                    window._owPCW = window._owPCW || {};
+                    this.instance_num = window._owPCWinstances++;
+                    window._owPCW[this.instance_num] = this;
+                    this.outside_ref =
+                        "window._owPCW[" + this.instance_num + "]";
+
+                    /* Initialize and save misc values, and call build() to
+                     * make and place widgets. */
+                    this.onapply = args.onapply;
+
+                    this.step = 'a';
+                    this.more_back = false;
+                    this.more_forward = true;
+                    this.value = this.original_value = args.node.value;
+
+                    this.pcrud = new openils.PermaCrud(
+                        {"authtoken": ses ? ses() : openils.User.authtoken}
+                    );
+
+                    this.build(args.node);
+
+                    this._load_all_types(   /* and then: */
+                        dojo.hitch(this, function() { this.move(0); })
+                    );
+                },
+                "build": function(where) {
+                    this.original_node = where;
+                    var p = this.container_node = where.parentNode;
+                    p.removeChild(where);
+
+                    this._build_XUL();
+                },
+                "update_question": function(label, values) {
+                    this._update_question_XUL(label, values);
+                },
+                "update_value_label": function() {
+                    this._update_value_label_XUL(
+                        this._get_step_slot(), this.value
+                    );
+                },
+                "update_pagers": function() {
+                    _show_button(this.back_button, this.more_back);
+                    _show_button(this.forward_button, this.more_forward);
+                },
+                "apply": function(callback) {
+                    this.active = false;
+
+                    this.move(
+                        0, dojo.hitch(this, function() {
+                            this.onapply(this.value);
+                            if (typeof callback == "function")
+                                callback();
+                        })
+                    );
+                },
+                "cancel": function() {
+                    this.active = false;
+                    this.container_node.removeChild(this.wizard_root_node);
+                    this.container_node.appendChild(this.original_node);
+                },
+                "_default_after_00": function() {
+                    /* This method assumes that the things it looks for in
+                     * the cache are freshly put there. */
+                    var working_ptype = this.value.substr(0, 1);
+                    var sf_list = this._cache.subfields[working_ptype];
+                    if (!sf_list)
+                        throw new Error(this._.BAD_WORKING_PTYPE);
+
+                    this.value = working_ptype;
+                    for (var i = 0; i < sf_list.length; i++) {
+                        var s = sf_list[i];
+                        var gap = s.start_pos() - this.value.length;
+                        if (gap > 0) {
+                            for (var j = 0; j < gap; j++)
+                                this.value += " ";  /* XXX or '#' ? */
+                        } else if (gap < 0) {
+                            throw new Error(
+                                dojo.string.substitute(
+                                    this._.BACKWARDS_SUBFIELD_PROGRESSION,
+                                    [working_ptype]
+                                )
+                            );
+                        }
+
+                        for (var j = 0; j < s.length(); j++)
+                            this.value += "|";
+                    }
+                },
+                "move": function(offset, callback) {
+                    /* When we move the wizard, we need to accomplish five
+                     * things:
+                     *  1) Disable both pager buttons - sic
+                     *  2) Update the appopriate _slot of the working _value_
+                     *  with the value from the user input control.
+                     *  ---- sync above here ^ --------- async below here v ----
+                     *  3) Determine what the next _step_ will be and set it
+                     *  4) Replace the question and the dropdown with appro-
+                     *  priate data from the new _step_
+                     *  5) Reenable appropriate pager buttons
+                     *  6) (optional) fire any callback
+                     */
+
+                    /* Step 1 */
+                    _show_button(this.back_button, false);
+                    _show_button(this.forward_button, false);
+
+                    /* Step 2. No sweat so far. Skip if there is no
+                     * user control yet (initializing whole wizard still). */
+                    var a_changed = false;
+                    if (this.step_user_control) {
+                        a_changed = this.update_value_slot(
+                                this._get_step_slot(),
+                                this.get_step_value_from_control()
+                            ) && this.step == 'a';
+                    }
+
+                    /* Step 3 depends on knowing a) our working_ptype, which
+                     * may have just changed if step was 'a' and b) all the
+                     * subfields for that ptype, which we may have to
+                     * retrieve asynchronously. */
+                    this._get_subfields_for_type(
+                        this.value.substr(0, 1), /* working_ptype */
+                        /* and then: */ dojo.hitch(this, function() {
+
+                            /* Step 2.9 (small) */
+                            if (a_changed) this._default_after_00();
+
+                            /* Step 3 proper: */
+                            this._move_step(offset);
+
+                            /* Step 4: For the call to update_question, we had
+                             * better have values loaded for our current step.
+                             */
+                            this._get_values_for_step(
+                                this.step,
+                                /* and then: */ dojo.hitch(this, function(l, v){
+                                    /* Step 4 proper: */
+                                    this.update_value_label();
+                                    this.update_question(l, v);
+
+                                    /* Step 5 */
+                                    this.update_pagers();
+
+                                    if (typeof callback == "function") {
+                                        callback();
+                                    }
+                                })
+                            );
+                        })
+                    );
+                },
+                "get_step_value_from_control": function() {
+                    return _get_xul_combobox_value(this.step_user_control);
+                },
+                "get_step_value": function() {
+                    return String.prototype.substr.apply(
+                        this.value, this._get_step_slot()
+                    );
+                },
+                "update_value_slot": function(slot, value) {
+                    /* Return true if this.value changes */
+
+                    if (!value.length) {
+                        /* Prevent erasing positions when backing up. */
+                        for (var i = 0; i < slot[1]; i++)
+                            value += '|';
+                    }
+
+                    var old_value = this.value;
+                    var before = this.value.substr(0, slot[0]);
+                    var after = this.value.substr(slot[0] + slot[1]);
+
+                    this.value = before + value.substr(0, slot[1]) + after;
+                    return (this.value != old_value);
+                },
+                "_load_all_types": function(callback) {
+                    /* It's easiest to have these always ready, and it's not
+                     * a large dataset. */
+
+                    if (this._cache.types.length)  /* maybe we already do */
+                        callback();
+
+                    this.pcrud.retrieveAll(
+                        "cmpctm", {
+                            "oncomplete": dojo.hitch(this, function(r) {
+                                if (r = openils.Util.readResponse(r)) {
+                                    this._cache.types = r.map(
+                                        function(o) {
+                                            return [o.ptype_key(), o.label()];
+                                        }
+                                    );
+                                    callback();
+                                } else {
+                                    throw new Error(this._.DATA_ERROR_007);
+                                }
+                            })
+                        }
+                    );
+                },
+                "_get_subfields_for_type": function(working_ptype, callback) {
+                    if (this._cache.subfields[working_ptype]) {
+                        callback(this._cache.subfields[working_ptype]);
+                    } else {
+                        this.pcrud.search(
+                            "cmpcsm", {"ptype_key": working_ptype}, {
+                                "order_by": {"cmpcsm": "subfield"},
+                                "oncomplete": dojo.hitch(this, function(r) {
+                                    if (r = openils.Util.readResponse(r)) {
+                                        this._cache.subfields[working_ptype]= r;
+                                        callback(r);
+                                    } else {
+                                        throw new Error(this._.DATA_ERROR_007);
+                                    }
+                                })
+                            }
+                        );
+                    }
+                },
+                "_get_values_for_step": function(step, callback) {
+                    /* Values are cached by subfield ID, so we find the
+                     * current subfield ID using the step and the
+                     * working_ptype. */
+
+                    if (this.step == 'a') {
+                        callback(this._.A_LABEL, this._cache.types);
+                        return;
+                    }
+
+                    var step = this.step;   /* for use w/in closure */
+                    var working_ptype = this.value.substr(0, 1);
+                    var subfields =
+                        this._cache.subfields[working_ptype].filter(
+                            function(s) { return s.subfield() == step; }
+                        );
+
+                    if (subfields.length != 1) {
+                        throw new Error(this._.BAD_SUBFIELD_DATA);
+                        return;
+                    }
+
+                    var subfield = subfields[0];
+                    if (this._cache.values[subfield.id()]) {
+                        callback(
+                            subfield.label(),
+                            this._cache.values[subfield.id()]
+                        );
+                    } else {
+                        this.pcrud.search(
+                            "cmpcvm", {"ptype_subfield": subfield.id()}, {
+                                "order_by": {"cmpcvm": "value"},
+                                "onresponse": dojo.hitch(this, function(r) {
+                                    if (r = openils.Util.readResponse(r)) {
+                                        this._cache.values[subfield.id()] =
+                                            r = r.map(
+                                                function(v) {
+                                                    return [v.value(),v.label()]
+                                                }
+                                            );
+                                        callback(subfield.label(), r);
+                                    } else {
+                                        throw new Error(this._.DATA_ERROR_007);
+                                    }
+                                })
+                            }
+                        );
+                    }
+                },
+                "_get_step_slot": function() {
+                    /* We should never need to know the slot for our step
+                     * until *after* we have the subfields for that step
+                     * loaded. That allows us to keep this function sync
+                     * (i.e., it returns instead of using a callback).  */
+
+                    if (this.step == 'a') {
+                        return [0, 1];
+                    } else {
+                        var step = this.step;   /* to use w/in closure */
+                        var working_ptype = this.value.substr(0, 1);
+                        var matches =
+                            this._cache.subfields[working_ptype].filter(
+                                function(s) { return s.subfield() == step; }
+                            );
+
+                        if (matches.length == 1)
+                            return [matches[0].start_pos(),matches[0].length()];
+                        else
+                            throw new Error(this._.BAD_SUBFIELD_DATA);
+                    }
+                },
+                "_move_step": function(offset) {
+                    /* This method is/should only be called when we know we
+                     * have the list of subfields for our working_ptype cached.
+                     *
+                     * We have two jobs in this method:
+                     *  1) Set this.step to something new.
+                     *  2) Update this.more_forward and this.more_back (bools)
+                     */
+                    var working_ptype = this.value.substr(0, 1);
+                    var found = -1;
+                    var sf_list = this._cache.subfields[working_ptype];
+
+                    for (var i = 0; i < sf_list.length; i++) {
+                        if (sf_list[i].subfield() == this.step) {
+                            found = i;
+                            break;
+                        }
+                    }
+
+                    var idx = found + offset;
+                    if (sf_list[idx]) {
+                        this.step = sf_list[idx].subfield();
+                        this.more_forward = Boolean(sf_list[idx + 1]);
+                        this.more_back = Boolean(idx >= 0);
+                    } else if (idx == -1) { /* 'a' */
+                        this.step = 'a';
+                        this.more_back = false;
+                        this.more_forward = true; /* or something's broke */
+                    } else {
+                        throw new Error(this._.FELL_OFF_STEPS);
+                    }
+                },
+                "_update_question_XUL": function(step_label, value_list) {
+                    var qh = this.question_holder;
+
+                    while (qh.firstChild) qh.removeChild(qh.firstChild);
+
+                    /* Add question label */
+                    var label = document.createElement("label");
+                    label.setAttribute("value", step_label + "?");
+                    label.setAttribute("style", "min-width: 16em;");
+                    qh.appendChild(label);
+
+                    /* Create combobox (in XUL this a <menulist editable="true">
+                     * with <menupopup> underneath and several <menuitem>s under
+                     * that). */
+                    var ml = this.step_user_control =
+                        document.createElement("menulist");
+                    ml.setAttribute("editable", "true");
+                    var mp = document.createElement("menupopup");
+                    ml.appendChild(mp);
+
+                    var starting_value = this.get_step_value();
+                    var found_starting_value = false;
+
+                    value_list.forEach(
+                        function(v) {
+                            var mi = document.createElement("menuitem");
+                            mi.setAttribute("label", v[0] + ": " + v[1]);
+                            mi.setAttribute("value", v[0]);
+
+                            if (v[0] == starting_value) {
+                                mi.setAttribute("selected", "true");
+                                found_starting_value = true;
+                            }
+
+                            mp.appendChild(mi);
+                        }
+                    );
+
+                    if (!found_starting_value) {
+                        /* Starting value wasn't one of the menuitems, but
+                         * we can force it: */
+                        ml.setAttribute("label", starting_value);
+                    }
+                    qh.appendChild(ml);
+                },
+                "_update_value_label_XUL": function(step_win, value) {
+                    var before = value.substr(0, step_win[0]);
+                    var within = value.substr(step_win[0], step_win[1]);
+                    var after = value.substr(step_win[0] + step_win[1]);
+
+                    var div = this.value_label;
+                    while (div.firstChild)
+                        div.removeChild(div.firstChild);
+
+                    div.appendChild(document.createTextNode(before));
+
+                    var el = document.createElementNS(_xhtml_ns,"xhtml:strong");
+                    el.appendChild(document.createTextNode(within));
+                    div.appendChild(el);
+
+                    div.appendChild(document.createTextNode(after));
+                },
+                "_gen_XUL_oncommand": function(methstr) {
+                    return "try { " + this.outside_ref +
+                        "." + methstr + " } catch (E) { alert('" +
+                        this.outside_ref + ": ' + E) }";
+                },
+                "_build_XUL": function() {
+                    var vbox = this.container_node.appendChild(
+                        document.createElement("vbox")
+                    );
+
+                    var top_hbox =
+                        vbox.appendChild(document.createElement("hbox"));
+
+                    this.question_holder =
+                        vbox.appendChild(document.createElement("hbox"));
+                    this.question_holder.setAttribute("align", "center");
+
+                    var bottom_hbox =
+                        vbox.appendChild(document.createElement("hbox"));
+
+                    this.value_label = top_hbox.appendChild(
+                        document.createElementNS(_xhtml_ns, "xhtml:div")
+                    );
+
+                    /* These em's must be measured in terms of the body
+                     * font-size, not the font-size local to these elements?
+                     * Or is that how em's always work? */
+                    this.value_label.setAttribute(
+                        "style", "min-width: 16em; white-space: pre;"
+                    );
+
+                    /* From here to the end of the method we're just building
+                     * and placing the wizard's four buttons. */
+                    var button;
+
+                    button = document.createElement("button");
+                    button.setAttribute("label", this._.OK);
+                    button.setAttribute("icon", "apply");
+                    button.setAttribute(
+                        "oncommand", this._gen_XUL_oncommand("apply()")
+                    );
+                    top_hbox.appendChild(button);
+
+                    button = document.createElement("button");
+                    button.setAttribute("label", this._.CANCEL);
+                    button.setAttribute("icon", "cancel");
+                    button.setAttribute(
+                        "oncommand", this._gen_XUL_oncommand("cancel()")
+                    );
+                    top_hbox.appendChild(button);
+
+                    this.back_button = button =
+                        document.createElement("button");
+                    button.setAttribute("label", this._.BACK);
+                    button.setAttribute("icon", "go-back");
+                    button.setAttribute(
+                        "oncommand", this._gen_XUL_oncommand("move(-1)")
+                    );
+                    button.disabled = true;
+                    bottom_hbox.appendChild(button);
+
+                    this.forward_button = button =
+                        document.createElement("button");
+                    button.setAttribute("label", this._.FORWARD);
+                    button.setAttribute("icon", "go-forward");
+                    button.setAttribute(
+                        "oncommand", this._gen_XUL_oncommand("move(1)")
+                    );
+                    button.disabled = true;
+                    bottom_hbox.appendChild(button);
+
+                    /* Save reference to root node of wizard for easy
+                     * removal when finished. */
+                    this.wizard_root_node = vbox;
+                }
+            }
+        );
+    })();
+
+    /* Class-wide cache; all instance objects share this */
+    openils.widget.PhysCharWizard.cache = {
+        "subfields": {},    /* by type */
+        "values": {},       /* by subfield ID */
+        "types": []
+    };
+
+    openils.widget.PhysCharWizard.localeStrings =
+        dojo.i18n.getLocalization("openils.widget", "PhysCharWizard");
+}
diff --git a/Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js b/Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js
new file mode 100644
index 0000000..c3462fe
--- /dev/null
+++ b/Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js
@@ -0,0 +1,15 @@
+{
+    "OK": "OK",
+    "CANCEL": "Cancel",
+    "BACK": "Previous",
+    "FORWARD": "Next",
+    "A_LABEL": "Category of Material",
+    "ERROR_SUBFIELDS_NOT_CACHED": "Subfields not cached for type ${0}!",
+    "NO_WORKING_PTYPE": "no 00/a is set; no working_ptype",
+    "DATA_ERROR_007": "Error retrieving 007 data from system. Try logging out and back in?",
+    "BAD_SUBFIELD_DATA": "Failed to find exactly one row in the subfield map for the current type and step.",
+    "FELL_OFF_STEPS": "Can't go any further that way.",
+    "BAD_WORKING_PTYPE": "Invalid 00/a or corrupt cmpcsm table.",
+    "BACKWARDS_SUBFIELD_PROGRESSION": "Subfields in cmpcsm for ptype ${0} go backwards!? This is probably a corrupt cmpcsm table.",
+    "INACTIVE": "Attempted to apply an inactive wizard"
+}

-----------------------------------------------------------------------

Summary of changes:
 .../web/js/dojo/openils/widget/PhysCharWizard.js   |  523 ++++++++++++++++++++
 .../js/dojo/openils/widget/nls/PhysCharWizard.js   |   15 +
 2 files changed, 538 insertions(+), 0 deletions(-)
 create mode 100644 Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
 create mode 100644 Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list