Commits

Luke Plant  committed dd83289

Added grouping controls for connections matrix

  • Participants
  • Parent commits a3caf03

Comments (0)

Files changed (3)

File static/connections.js

 $(document).ready(function () {
 
     var $tbl = $("#connections");
-
-    function mirrorChange(x, y, val) {
-        connectionsMatrix.setDataAtCell(y, x, val, "mirrorChange");
-    }
+    var leftGroup = null;
+    var topGroup = null;
+    var groups = {left: [],
+                  top: []};
+    var groupSuffices = ["left", "top"];
 
     function afterChange (changes, source) {
         if (source == "edit" || source == "autofill") {
-            for (i in changes) {
+            var newChanges = [];
+            for (var i in changes) {
                 var change = changes[i];
-                mirrorChange(change[0], change[1], change[3]);
+                var r = change[0];
+                var c = change[1];
+                var val = change[3];
+
+                // Mirror
+                newChanges.push([c, r, val]);
+
+                // Groups
+                var inTopGroup = groups.top.indexOf(c) != -1;
+                var inLeftGroup = groups.left.indexOf(r) != -1;
+                if (inTopGroup || inLeftGroup) {
+                    // Propagate to group
+                    var cols, rows;
+                    if (inTopGroup) {
+                        cols = groups.top;
+                    } else {
+                        cols = [c];
+                    }
+                    if (inLeftGroup) {
+                        rows = groups.left;
+                    } else {
+                        rows = [r];
+                    }
+                    for (var a in rows) {
+                        for (var b in cols) {
+                            var r2 = rows[a];
+                            var c2 = cols[b];
+                            if (!((r == r2 && c == c2) ||
+                                  (r2 == c2)))
+                            {
+                                newChanges.push([r2, c2, val])
+                                newChanges.push([c2, r2, val])
+                            }
+                        }
+                    }
+                }
             }
+            connectionsMatrix.setDataAtCell(newChanges, "mirrorChanges");
+        }
+    }
+
+    function enableAddToGroupBtn (suffix) {
+        $("#add-to-group-" + suffix).removeAttr("disabled");
+    }
+
+    function enableRemoveFromGroupBtn (suffix) {
+        $("#remove-from-group-" + suffix).removeAttr("disabled");
+    }
+
+    function disableAddToGroupBtn (suffix) {
+        $("#add-to-group-" + suffix).attr("disabled", "disabled");
+    }
+
+    function disableRemoveFromGroupBtn (suffix) {
+        $("#remove-from-group-" + suffix).attr("disabled", "disabled");
+    }
+
+    function enableGroupExistsBtns (suffix) {
+        $("#clear-group-" + suffix).removeAttr("disabled");
+        $("#mirror-group-" + suffix).removeAttr("disabled");
+    }
+
+    function disableGroupExistsBtns (suffix) {
+        $("#clear-group-" + suffix).attr("disabled", "disabled");
+        $("#mirror-group-" + suffix).attr("disabled", "disabled");
+    }
+
+    function updateGroupExistControls (suffix) {
+        var group = groups[suffix];
+        if (group.length == 0) {
+            disableGroupExistsBtns(suffix);
+        } else {
+            enableGroupExistsBtns(suffix)
+        }
+    }
+
+    function afterSelectionEnd (r, c, r2, c2) {
+        if (r == 0 && r2 == 0 && c != 0 && c2 != 0) {
+            enableAddToGroupBtn("top");
+            enableRemoveFromGroupBtn("top");
+        } else {
+            disableAddToGroupBtn("top");
+            disableRemoveFromGroupBtn("top")
+        }
+        if (c == 0 && c2 == 0 && r != 0 && r2 != 0) {
+            enableAddToGroupBtn("left");
+            enableRemoveFromGroupBtn("left");
+        } else {
+            disableAddToGroupBtn("left");
+            disableRemoveFromGroupBtn("left");
+        }
+    }
+
+    function cellRenderer (instance, td, row, col, prop, value, cellProperties) {
+        Handsontable.TextCell.renderer.apply(this, arguments);
+        if (groups.left.indexOf(row) != -1 ||
+            groups.top.indexOf(col) != -1) {
+            td.style.background = "#eee";
+        } else {
+            td.style.background = "#fff";
         }
     }
 
         data: [[""]],
         rowHeaders: false,
         colHeaders: false,
+        height: 600,
         fixedRowsTop: 1,
         fixedColumnsLeft: 1,
         cells: function (row, col, prop) {
             if (row == 0 || col == 0 || row == col) {
                 cellProperties.readOnly = true;
             }
+            cellProperties.renderer = cellRenderer;
             return cellProperties;
         },
         afterChange: afterChange,
+        afterSelectionEnd: afterSelectionEnd,
+        outsideClickDeselects: false,
         contextMenu: false
     });
 
         updateMatrixFromRaw();
     });
 
+    function makeGroupUnique (group) {
+        // Has to edit the array in place, not return a new one.
+        var seen = [];
+        var i = 0;
+        while (i < group.length) {
+            item = group[i];
+            if (seen.indexOf(item) == -1) {
+                seen.push(item);
+                i++;
+            } else {
+                group.splice(i, 1);
+            }
+        }
+    }
+
+
+    function makeAddToGroup (suffix) {
+        var addToGroup = function (ev) {
+            group = groups[suffix];
+            s = connectionsMatrix.getSelected();
+            // s = [startRow, startCol, endRow, endCol]
+            if (suffix == "left") {
+                for (var i = s[0]; i <= s[2]; i++) {
+                    group.push(i);
+                }
+            } else {
+                for (var i = s[1]; i <= s[3]; i++) {
+                    group.push(i);
+                }
+            }
+            makeGroupUnique(group);
+            updateGroupExistControls(suffix);
+            connectionsMatrix.render();
+        };
+        return addToGroup;
+    }
+
+    function makeRemoveFromGroup (suffix) {
+        var removeFromGroup = function (ev) {
+            group = groups[suffix];
+            s = connectionsMatrix.getSelected();
+            // s = [startRow, startCol, endRow, endCol]
+            if (suffix == "left") {
+                for (var i = s[0]; i <= s[2]; i++) {
+                    group.splice(group.indexOf(i), 1);
+                }
+            } else {
+                for (var i = s[1]; i <= s[3]; i++) {
+                    group.splice(group.indexOf(i), 1);
+                }
+            }
+            updateGroupExistControls(suffix);
+            connectionsMatrix.render();
+        };
+        return removeFromGroup;
+    }
+
+    function makeClearGroup (suffix) {
+        var clearGroup = function (ev) {
+            group = groups[suffix];
+            group.splice(0);
+            updateGroupExistControls(suffix);
+            connectionsMatrix.render();
+        }
+        return clearGroup;
+    }
+
+    function makeMirrorGroup (suffix) {
+        var mirrorGroup = function (ev) {
+            group = groups[suffix];
+            otherSuffix = suffix == "left" ? "top" : "left";
+            groups[otherSuffix] = group.slice();
+            updateGroupExistControls(suffix);
+            updateGroupExistControls(otherSuffix);
+            connectionsMatrix.render();
+        }
+        return mirrorGroup;
+    }
+
+    for (var i in groupSuffices) {
+        suffix = groupSuffices[i];
+        $("#add-to-group-" + suffix).click(makeAddToGroup(suffix));
+        $("#remove-from-group-" + suffix).click(makeRemoveFromGroup(suffix));
+        $("#clear-group-" + suffix).click(makeClearGroup(suffix));
+        $("#mirror-group-" + suffix).click(makeMirrorGroup(suffix));
+    }
+
+    disableAddToGroupBtn("left");
+    disableRemoveFromGroupBtn("left");
+    disableAddToGroupBtn("top");
+    disableRemoveFromGroupBtn("top");
+
+    disableGroupExistsBtns("left");
+    disableGroupExistsBtns("top");
+
 });
 

File static/style.css

 .plans-container {
     overflow-y: auto;
 }
+
+#connections-controls {
+    width: 100%;
+    border: 1px solid black;
+}
+#connections-controls td {
+    vertical-align: top;
+}

File templates/index.html

     </ul>
 
     <div id="connections-matrix-controls">
-      <p><input type="submit" id="show-raw-connections" value="Show raw connections data"></p>
-      <h3>Matrix</h3>
-      <div id="connections" class="handsontable"></div>
+      <h3>Matrix <input type="submit" id="show-raw-connections" value="Show raw connections data"></h3>
+      <p>Using the matrix:</p>
+
+      <ul>
+        <li>The matrix is symmetrical. Edit one half and the other will be filled in automatically.</li>
+        <li>If you create a group, then values for all the people in the group will be edited together. Groups can be selected down the left, across the top, or both.</li>
+        <li>To enter that a group of people all know each other:
+          <ul>
+            <li>Clear any group on the left</li>
+            <li>Add all the people in the group on left</li>
+            <li>Choose 'mirror group' on the left to create the same group across the top</li>
+            <li>Edit one connection between two people, and all will be updated</li>
+          </ul>
+        </li>
+      </ul>
+
+      <table id="connections-controls">
+        <tr>
+          <td></td>
+          <td>Groups:
+            <input type="submit" value="Clear group" id="clear-group-top">
+            <input type="submit" value="Add to group" id="add-to-group-top">
+            <input type="submit" value="Remove from group" id="remove-from-group-top">
+            <input type="submit" value="Mirror group" id="mirror-group-top">
+          </td>
+        </tr>
+        <tr>
+          <td>Groups:<br/>
+            <input type="submit" value="Clear group" id="clear-group-left"><br/>
+            <input type="submit" value="Add to group" id="add-to-group-left"><br/>
+            <input type="submit" value="Remove from group" id="remove-from-group-left"><br/>
+            <input type="submit" value="Mirror group" id="mirror-group-left">
+          </td>
+          <td>
+            <div id="connections" class="handsontable"></div>
+          </td>
+        </tr>
+      </table>
     </div>
 
     <div id="connections-raw-controls" style="display: none;">
-      <p><input type="submit" id="hide-raw-connections" value="Hide raw data"></p>
-      <h3>Data</h3>
+      <h3>Data <input type="submit" id="hide-raw-connections" value="Hide raw data"></h3>
       <textarea id="connections-raw" rows="20" cols="50">
       </textarea>
       <p><input type="submit" id="update-matrix" value="Update matrix"></p>