From 6c32ca2e574f57e2eb57bc29c75b3ff506651a9e Mon Sep 17 00:00:00 2001
From: senator <lebbeous@esilibrary.com>
Date: Thu, 14 Apr 2011 18:14:32 -0400
Subject: [PATCH] lots of things here, but nearly last big UI todo is...

to implement openils.vandelay.TreeDndSource._is_replaceable() and then
make the changes to itemCreator
---
 .../web/js/dojo/openils/vandelay/TreeDndSource.js  |  28 ++++-
 .../web/js/dojo/openils/vandelay/TreeStoreModel.js |   1 +
 .../web/js/dojo/openils/vandelay/nls/match_set.js  |   6 +-
 Open-ILS/web/js/ui/default/vandelay/match_set.js   | 125 ++++++++-------------
 .../templates/default/vandelay/match_set_tree.tt2  |  24 +++-
 5 files changed, 95 insertions(+), 89 deletions(-)

diff --git a/Open-ILS/web/js/dojo/openils/vandelay/TreeDndSource.js b/Open-ILS/web/js/dojo/openils/vandelay/TreeDndSource.js
index aa5f2f4632..8ccd836aeb 100644
--- a/Open-ILS/web/js/dojo/openils/vandelay/TreeDndSource.js
+++ b/Open-ILS/web/js/dojo/openils/vandelay/TreeDndSource.js
@@ -7,6 +7,13 @@ dojo.require("dijit._tree.dndSource");
  */
 dojo.declare(
     "openils.vandelay.TreeDndSource", dijit._tree.dndSource, {
+        "_is_replaceable": function(src_item, target_item) {
+            /* An OP can replace anything, but non-OPs can only replace other
+             * non-OPs
+             */
+            console.log("src item: " + src_item + " target item: " + target_item);
+            return true;    /* XXX TODO FINISHME */
+        },
         "constructor": function() {
             /* Given a tree object, there seems to be no way to access its
              * dndController, which seems to be the only thing that knows
@@ -19,18 +26,29 @@ dojo.declare(
             window._tree_dnd_controllers.push(this);
         },
         "checkItemAcceptance": function(target, source, position) {
-            return (
-                source._ready && (
+            if (!source._ready || source == this) return;
+
+            if (this.tree.model._replace_mode) {
+                return (
+                    position == "over" && this._is_replaceable(
+                        source.getAllNodes()[0].match_point,
+                        dijit.getEnclosingWidget(target).item.match_point
+                    )
+                );
+            } else {
+                return (
                     position != "over" ||
                     this.tree.model.mayHaveChildren(
                         dijit.getEnclosingWidget(target).item
                     )
-                )
-            );
+                );
+            }
             /* code in match_set.js makes sure that source._ready gets set true
              * only when we want the item to be draggable */
         },
-        "itemCreator": function(nodes) {
+        "itemCreator": function(nodes, somethingelse) {
+            console.log("gew: " + dijit.getEnclosingWidget(somethingelse).item.name);
+            console.log("dojo.dnd.manager.copy: " + dojo.dnd.manager.copy);
             var default_items = this.inherited(arguments);
             for (var i = 0; i < default_items.length; i++)
                 default_items[i].match_point = nodes[i].match_point;
diff --git a/Open-ILS/web/js/dojo/openils/vandelay/TreeStoreModel.js b/Open-ILS/web/js/dojo/openils/vandelay/TreeStoreModel.js
index 61d28214e4..2a35b70b46 100644
--- a/Open-ILS/web/js/dojo/openils/vandelay/TreeStoreModel.js
+++ b/Open-ILS/web/js/dojo/openils/vandelay/TreeStoreModel.js
@@ -19,6 +19,7 @@ function _simple_item(model, item) {
 
 dojo.declare(
     "openils.vandelay.TreeStoreModel", dijit.tree.TreeStoreModel, {
+        "_replace_mode": 0,
         "getSimpleTree": function(item, oncomplete, result) {
             var self = this;
             if (!result) result = {};
diff --git a/Open-ILS/web/js/dojo/openils/vandelay/nls/match_set.js b/Open-ILS/web/js/dojo/openils/vandelay/nls/match_set.js
index 1b9f01bca3..ceb72bb5e7 100644
--- a/Open-ILS/web/js/dojo/openils/vandelay/nls/match_set.js
+++ b/Open-ILS/web/js/dojo/openils/vandelay/nls/match_set.js
@@ -1,3 +1,7 @@
 {
-    "DEFINE_MP": "Define this match point using the above fields, then drag me to the tree on the right."
+    "DEFINE_MP": "Define this match point using the above fields, then drag me to the tree on the right.",
+    "LEAVE_ROOT_ALONE": "You cannot delete the root node of a tree (but you can replace it).",
+    "EXACTLY_ONE": "First select exactly one node from the tree on the right side of the screen.",
+    "EXIT_REPLACE_MODE": "Exit Replace Mode",
+    "ENTER_REPLACE_MODE": "Enter Replace Mode"
 }
diff --git a/Open-ILS/web/js/ui/default/vandelay/match_set.js b/Open-ILS/web/js/ui/default/vandelay/match_set.js
index 4b7dd90e13..f9fa8ecdb0 100644
--- a/Open-ILS/web/js/ui/default/vandelay/match_set.js
+++ b/Open-ILS/web/js/ui/default/vandelay/match_set.js
@@ -1,7 +1,6 @@
 dojo.require("dijit.Tree");
 dojo.require("dijit.form.Button");
 dojo.require("dojo.data.ItemFileWriteStore");
-//dojo.require("openils.vandelay.DndSource");
 dojo.require("dojo.dnd.Source");
 dojo.require("openils.vandelay.TreeDndSource");
 dojo.require("openils.vandelay.TreeStoreModel");
@@ -122,47 +121,25 @@ function NodeEditor() {
     this.clear = function() {
         this.dnd_source.selectAll().deleteSelectedNodes();
         dojo.empty(this.node_editor_container);
+        this.dnd_source._ready = false;
     };
 
-    this.update_draggable = function(draggable) {
-        var s = "";
-        draggable.match_point = new vmsp();
-        var had_op = false;
-        dojo.query("[fmfield]", this.node_editor_container).forEach(
-            function(control) {
-                var used_svf = null;
-                var field = dojo.attr(control, "fmfield");
-                var value = _simple_value_getter(control);
-                draggable.match_point[field](value);
-
-                if (field == "subfield")
-                    s += " \u2021";
-                if (field == "svf")
-                    used_svf = value;
-                if (field == "quality")
-                    return;
-                if (field == "bool_op")
-                    had_op = true;
-                if (field == "negate") {
-                    if (value) {
-                        if (had_op)
-                            s = "<strong>N</strong>" + s;
-                        else
-                            s = "<strong>NOT</strong> " + s;
-                    }
-                } else {
-                    s += value;
-                }
+    this.build_vmsp = function() {
+        var match_point = new vmsp();
+        var controls = dojo.query("[fmfield]", this.node_editor_container);
+        for (var i = 0; i < controls.length; i++) {
+            var field = dojo.attr(controls[i], "fmfield");
+            var value = _simple_value_getter(controls[i]);
+            match_point[field](value);
+        }
+        return match_point;
+    };
 
-                if (used_svf !== null) {
-                    var our_crad = _find_crad_by_name(used_svf);
-                    /* XXX i18n, use fmtted strings */
-                    s += " / " + our_crad.label() + "<br /><em>" +
-                        (our_crad.description() || "") + "</em><br />";
-                }
-            }
+    this.update_draggable = function(draggable) {
+        draggable.match_point = this.build_vmsp();
+        dojo.attr(
+            draggable, "innerHTML", render_vmsp_label(draggable.match_point)
         );
-        dojo.attr(draggable, "innerHTML", s);
         this.dnd_source._ready = true;
     };
 
@@ -210,7 +187,6 @@ function NodeEditor() {
         dojo.place(table, this.node_editor_container, "only");
         /* XXX around here attach other data structures to the node */
         this.dnd_source.insertNodes(false, [draggable]);
-        this.dnd_source._ready = false;
     };
 
     this._init.apply(this, arguments);
@@ -218,24 +194,39 @@ function NodeEditor() {
 
 /* XXX replace later with code that will suit this function's purpose
  * as well as that of update_draggable. */
-function display_name_from_point(point) {
+function render_vmsp_label(point) {
     /* quick and dirty */
     if (point.bool_op()) {
-        return (point.negate() == "t" ? "N" : "") + point.bool_op();
+        return (openils.Util.isTrue(point.negate()) ? "N" : "") +
+            point.bool_op();
     } else if (point.svf()) {
-        return (point.negate() == "t" ? "NOT " : "") + point.svf();
+        return (openils.Util.isTrue(point.negate()) ? "NOT " : "") +
+            point.svf() + " / " + _find_crad_by_name(point.svf()).label();
     } else {
-        return (point.negate() == "t" ? "NOT " : "") + point.tag() +
-            "\u2021" + point.subfield();
+        return (openils.Util.isTrue(point.negate()) ? "NOT " : "") +
+            point.tag() + " \u2021" + point.subfield();
     }
 }
 
-function delete_selected_from_tree() {
+function replace_mode() {
+    tree.model._replace_mode ^= 1;
+    dojo.attr(
+        "replacer", "innerHTML",
+        localeStrings[
+            (tree.model._replace_mode ? "EXIT" : "ENTER") + "_REPLACE_MODE"
+        ]
+    );
+}
+
+function delete_selected_in_tree() {
     /* relies on the fact that we only have one tree that would have
      * registered a dnd controller. */
     _tree_dnd_controllers[0].getSelectedItems().forEach(
         function(item) {
-            tree.model.store.deleteItem(item);
+            if (item === tree.model.root)
+                alert(localeStrings.LEAVE_ROOT_ALONE);
+            else
+                tree.model.store.deleteItem(item);
         }
     );
 }
@@ -264,7 +255,7 @@ function dojoize_match_set_tree(point, refgen) {
     point.children([]);
     var item = {
         "id": (root ? "root" : refgen),
-        "name": display_name_from_point(point),
+        "name": render_vmsp_label(point),
         "match_point": point.clone(),
         "children": []
     };
@@ -292,7 +283,7 @@ function render_match_set_description(match_set) {
     dojo.byId("vms-mtype").innerHTML = match_set.mtype();
 }
 
-function init_test() {
+function my_init() {
     progress_dialog.show(true);
 
     dojo.requireLocalization("openils.vandelay", "match_set");
@@ -315,19 +306,6 @@ function init_test() {
         [openils.User.authtoken, CGI.param("match_set")]
     );
 
-//        {
-//            "identifier": "id", "label": "name", "items": [
-//                {
-//                    "id": "root", "name": "AND",
-//                    "children": [
-//                        {"_reference": "leaf0"}, {"_reference": "leaf1"}
-//                    ]
-//                },
-//                {"id": "leaf0", "name": "nonsense test"},
-//                {"id": "leaf1", "name": "more nonsense"}
-//            ]
-//        }
-
     var store = new dojo.data.ItemFileWriteStore({
         "data": {
             "identifier": "id",
@@ -336,14 +314,14 @@ function init_test() {
         }
     });
 
-    var treeModel = new openils.vandelay.TreeStoreModel({
-        store: store, "query": {"id": "root"}
+    var tree_model = new openils.vandelay.TreeStoreModel({
+        "store": store, "query": {"id": "root"}
     });
 
     var src = new dojo.dnd.Source("src-here");
     tree = new dijit.Tree(
         {
-            "model": treeModel,
+            "model": tree_model,
             "dndController": openils.vandelay.TreeDndSource,
             "dragThreshold": 8,
             "betweenThreshold": 5,
@@ -356,22 +334,15 @@ function init_test() {
     dojo.connect(
         src, "onDndDrop", null,
         function(source, nodes, copy, target) {
-            if (source == this) {
-                var model = target.tree.model;
-                model.getRoot(
-                    function(root) {
-                        model.getSimpleTree(
-                            root, function(results) { alert(js2JSON(results)); }
-                        );
-                    }
-                );
+            /* XXX because of the... interesting... characteristics of DnD
+             * design in dojo/dijit (at least as of 1.3), this callback will
+             * fire both for our working node dndSource and for the tree!
+             */
+            if (source == this)
                 node_editor.clear();  /* because otherwise this acts like a copy! */
-            } else {
-                alert("XXX [src] nodes length is " + nodes.length); /* XXX DEBUG */
-            }
         }
     );
     progress_dialog.hide();
 }
 
-openils.Util.addOnLoad(init_test);
+openils.Util.addOnLoad(my_init);
diff --git a/Open-ILS/web/templates/default/vandelay/match_set_tree.tt2 b/Open-ILS/web/templates/default/vandelay/match_set_tree.tt2
index 6796406321..06f1679b95 100644
--- a/Open-ILS/web/templates/default/vandelay/match_set_tree.tt2
+++ b/Open-ILS/web/templates/default/vandelay/match_set_tree.tt2
@@ -2,14 +2,16 @@
 [% ctx.page_title = 'Vandelay Match Set Editor' %]
 <style type="text/css">
     h1 { margin: 1ex 0; }
-    .outer { clear: both; }
-    #vmsp-buttons button { margin: 0 0.5em; }
+    .outer { clear: both; margin-bottom: 1ex; }
+    button { margin: 0 0.5em; }
     #tree-here { margin-bottom: 1.5em; }
     #vms-table { padding-bottom: 2ex; }
     #vms-table th { text-align: right; }
     #vms-table td { padding-left: 1em; }
     #src-pane { float: left; width: 49%; }
     #tree-pane { float: right; width: 50%; }
+    #submit-row { clear: both; text-align: center; padding-top: 1.5ex; }
+    #submit-row hr { margin: 1ex 0; }
     .node-editor { margin-bottom: 1.5ex; }
     .node-editor td { padding: 0.5ex; }
     li { background-color: #ddd; }
@@ -61,7 +63,7 @@
     <div><!-- XXX TODO: consider a read-only display here of the query as built
         so far from the treet --></div>
     <div id="vmsp-buttons">
-        New
+        Add new
         <button onclick="node_editor.add('svf');">Single-Value-Field</button>
         <button onclick="node_editor.add('tag');">MARC Tag and Subfield</button>
         <button onclick="node_editor.add('bool_op');">Boolean Operator</button>
@@ -69,6 +71,7 @@
 </div>
 <div class="outer" style="margin-top: 2ex;">
     <div id="src-pane">
+        <div><big>Working Match Point</big></div>
         <div>
             <form id="node-editor-container" onsubmit="return false;"></form>
         </div>
@@ -78,11 +81,20 @@
     <div id="tree-pane">
         <div><big>Your Expression</big></div>
         <div id="tree-here"></div>
-        <button id="deleter" onclick="delete_selected_from_tree()">
-            Deleted Selected Node
-        </button>
+        <div>
+            <button id="deleter" onclick="delete_selected_in_tree()">
+                Delete Selected Node
+            </button>
+            <button id="replacer" onclick="replace_mode()">
+                Enter Replace Mode
+            </button>
+        </div>
     </div>
 </div>
+<div id="submit-row">
+    <hr />
+    <button onclick="save_tree()">Save Changes</button>
+</div>
 <div jsId="progress_dialog" dojoType="openils.widget.ProgressDialog"></div>
 <script type="text/javascript"
     src="[% ctx.media_prefix %]/js/ui/default/vandelay/match_set.js"></script>
-- 
2.11.0