From bd4dfcae6ef6d442b128e82023c779aaa1a414a2 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 10 Nov 2011 16:16:38 +0400 Subject: [PATCH] enable checking of child checkboxes --- lib/CheckBoxTree.js | 120 ++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/lib/CheckBoxTree.js b/lib/CheckBoxTree.js index fb532801c..3e4081909 100644 --- a/lib/CheckBoxTree.js +++ b/lib/CheckBoxTree.js @@ -9,10 +9,10 @@ dojo.provide("lib.CheckBoxStoreModel"); dojo.require("dijit.Tree"); dojo.require("dijit.form.CheckBox"); -dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, +dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, { // checkboxAll: Boolean - // If true, every node in the tree will receive a checkbox regardless if the 'checkbox' attribute + // If true, every node in the tree will receive a checkbox regardless if the 'checkbox' attribute // is specified in the dojo.data. checkboxAll: true, @@ -24,13 +24,13 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // checkboxRoot: Boolean // If true, the root node will receive a checkbox eventhough it's not a true entry in the store. // This attribute is independent of the showRoot attribute of the tree itself. If the tree - // attribute 'showRoot' is set to false to checkbox for the root will not show either. + // attribute 'showRoot' is set to false to checkbox for the root will not show either. checkboxRoot: false, // checkboxStrict: Boolean - // If true, a strict parent-child checkbox relation is maintained. For example, if all children + // If true, a strict parent-child checkbox relation is maintained. For example, if all children // are checked the parent will automatically be checked or if any of the children are unchecked - // the parent will be unchecked. + // the parent will be unchecked. checkboxStrict: true, // checkboxIdent: String @@ -38,17 +38,17 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // state. Example: { name:'Egypt', type:'country', checkbox: true } // If a dojo.data.item has no 'checkbox' attribute specified it will depend on the attribute // 'checkboxAll' if one will be created automatically and if so what the initial state will be as - // specified by 'checkboxState'. + // specified by 'checkboxState'. checkboxIdent: "checkbox", updateCheckbox: function(/*dojo.data.Item*/ storeItem, /*Boolean*/ newState ) { // summary: - // Update the checkbox state (true/false) for the item and the associated parent and - // child checkboxes if any. + // Update the checkbox state (true/false) for the item and the associated parent and + // child checkboxes if any. // description: - // Update a single checkbox state (true/false) for the item and the associated parent + // Update a single checkbox state (true/false) for the item and the associated parent // and child checkboxes if any. This function is called from the tree if a user checked - // or unchecked a checkbox on the tree. The parent and child tree nodes are updated to + // or unchecked a checkbox on the tree. The parent and child tree nodes are updated to // maintain consistency if 'checkboxStrict' is set to true. // storeItem: // The item in the dojo.data.store whos checkbox state needs updating. @@ -57,11 +57,12 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // example: // | model.updateCheckboxState(item, true); // + this._setCheckboxState( storeItem, newState ); - if( this.checkboxStrict ) { + //if( this.checkboxStrict ) { I don't need all this 1-1 stuff, only parent -> child (fox) this._updateChildCheckbox( storeItem, newState ); - this._updateParentCheckbox( storeItem, newState ); - } + //this._updateParentCheckbox( storeItem, newState ); + //} }, setAllChecked: function(checked) { var items = this.store._arrayOfAllItems; @@ -77,7 +78,7 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, var result = []; for (var i = 0; i < items.length; i++) { - if (this.store.getValue(items[i], 'checkbox')) + if (this.store.getValue(items[i], 'checkbox')) result.push(items[i]); } @@ -102,9 +103,9 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // The item in the dojo.data.store whos checkbox state is returned. // example: // | var currState = model.getCheckboxState(item); - // + // var currState = undefined; - + // Special handling required for the 'fake' root entry (the root is NOT a dojo.data.item). // this stuff is only relevant for Forest store -fox /* if ( storeItem == this.root ) { @@ -138,14 +139,14 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // Set/update the checkbox state on the dojo.data store. // description: // Set/update the checkbox state on the dojo.data.store. Retreive the current - // state of the checkbox and validate if an update is required, this will keep + // state of the checkbox and validate if an update is required, this will keep // update events to a minimum. On completion a 'onCheckboxChange' event is - // triggered. - // If the current state is undefined (ie: no checkbox attribute specified for - // this dojo.data.item) the 'checkboxAll' attribute is checked to see if one + // triggered. + // If the current state is undefined (ie: no checkbox attribute specified for + // this dojo.data.item) the 'checkboxAll' attribute is checked to see if one // needs to be created. In case of the root the 'checkboxRoot' attribute is checked. - // NOTE: the store.setValue function will create the 'checkbox' attribute for the - // item if none exists. + // NOTE: the store.setValue function will create the 'checkbox' attribute for the + // item if none exists. // storeItem: // The item in the dojo.data.store whos checkbox state is updated. // newState: @@ -154,7 +155,7 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // | model.setCheckboxState(item, true); // var stateChanged = true; - + if( storeItem != this.root ) { var currState = this.store.getValue(storeItem, this.checkboxIdent); if( currState != newState && ( currState !== undefined || this.checkboxAll ) ) { @@ -174,13 +175,13 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, } return stateChanged; }, - + _updateChildCheckbox: function(/*dojo.data.Item*/ parentItem, /*Boolean*/ newState ) { // summary: // Set all child checkboxes to true/false depending on the parent checkbox state. // description: - // If a parent checkbox changes state, all child and grandchild checkboxes will be - // updated to reflect the change. For example, if the parent state is set to true, + // If a parent checkbox changes state, all child and grandchild checkboxes will be + // updated to reflect the change. For example, if the parent state is set to true, // all child and grandchild checkboxes will receive that same 'true' state. // If a child checkbox changes state and has multiple parent, all of its parents // need to be re-evaluated. @@ -189,11 +190,12 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // newState: // The new state of the checkbox: true or false // + if( this.mayHaveChildren( parentItem )) { this.getChildren( parentItem, dojo.hitch( this, function( children ) { dojo.forEach( children, function(child) { - if( this._setCheckboxState(child, newState) ) { + if( this._setCheckboxState(child, newState) ) { var parents = this._getParentsItem(child); if( parents.length > 1 ) { this._updateParentCheckbox( child, newState ); @@ -206,7 +208,7 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, }), function(err) { console.error(this, ": updating child checkboxes: ", err); - } + } ); } }, @@ -217,7 +219,7 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // description: // Update the parent checkbox state depending on the state of all child checkboxes. // The parent checkbox automatically changes state if ALL child checkboxes are true - // or false. If, as a result, the parent checkbox changes state, we will check if + // or false. If, as a result, the parent checkbox changes state, we will check if // its parent needs to be updated as well all the way upto the root. // storeItem: // The dojo.data.item whos parent checkboxes require updating. @@ -229,11 +231,11 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, if( newState ) { // new state = true (checked) this.getChildren( parentItem, dojo.hitch( this, function(siblings) { - var allChecked = true; + var allChecked = true; dojo.some( siblings, function(sibling) { siblState = this.getCheckboxState(sibling); if( siblState !== undefined && allChecked ) - allChecked = siblState; + allChecked = siblState; return !(allChecked); }, this ); if( allChecked ) { @@ -252,14 +254,14 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, } }, this ); }, - + _getParentsItem: function(/*dojo.data.Item*/ storeItem ) { // summary: - // Get the parent(s) of a dojo.data item. + // Get the parent(s) of a dojo.data item. // description: // Get the parent(s) of a dojo.data item. The '_reverseRefMap' entry of the item is - // used to identify the parent(s). A child will have a parent reference if the parent - // specified the '_reference' attribute. + // used to identify the parent(s). A child will have a parent reference if the parent + // specified the '_reference' attribute. // For example: children:[{_reference:'Mexico'}, {_reference:'Canada'}, ... // storeItem: // The dojo.data.item whos parent(s) will be returned. @@ -283,9 +285,9 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, // Validate/normalize the parent(s) checkbox data in the dojo.data store. // description: // Validate/normalize the parent-child checkbox relationship if the attribute - // 'checkboxStrict' is set to true. This function is called as part of the post + // 'checkboxStrict' is set to true. This function is called as part of the post // creation of the Tree instance. All parent checkboxes are set to the appropriate - // state according to the actual state(s) of their children. + // state according to the actual state(s) of their children. // This will potentionally overwrite whatever was specified for the parent in the // dojo.data store. This will garantee the tree is in a consistent state after startup. // storeItem: @@ -308,7 +310,7 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, } childState = this.getCheckboxState( child ); if( childState !== undefined && allChecked ) - allChecked = childState; + allChecked = childState; }, this); if ( this._setCheckboxState( storeItem, allChecked) ) { @@ -317,19 +319,19 @@ dojo.declare( "lib.CheckBoxStoreModel", dijit.tree.TreeStoreModel, }), function(err) { console.error(this, ": validating checkbox data: ", err); - } + } ); }, onCheckboxChange: function(/*dojo.data.Item*/ storeItem ) { // summary: - // Callback whenever a checkbox state has changed state, so that + // Callback whenever a checkbox state has changed state, so that // the Tree can update the checkbox. This callback is generally - // triggered by the '_setCheckboxState' function. + // triggered by the '_setCheckboxState' function. // tags: // callback } - + }); dojo.declare( "lib._CheckBoxTreeNode", dijit._TreeNode, @@ -344,11 +346,11 @@ dojo.declare( "lib._CheckBoxTreeNode", dijit._TreeNode, // description: // Create a checkbox on the CheckBoxTreeNode. The checkbox is ONLY created if a // valid reference was found in the dojo.data store or the attribute 'checkboxAll' - // is set to true. If the current state is 'undefined' no reference was found and + // is set to true. If the current state is 'undefined' no reference was found and // 'checkboxAll' is set to false. // Note: the attribute 'checkboxAll' is validated by the getCheckboxState function // therefore no need to do that here. (see getCheckboxState for details). - // + // var currState = this.tree.model.getCheckboxState( this.item ); if( currState !== undefined ) { this._checkbox = new dijit.form.CheckBox(); @@ -358,7 +360,7 @@ dojo.declare( "lib._CheckBoxTreeNode", dijit._TreeNode, dojo.place(this._checkbox.domNode, this.expandoNode, 'after'); } }, - + postCreate: function() { // summary: // Handle the creation of the checkbox after the CheckBoxTreeNode has been instanciated. @@ -372,21 +374,21 @@ dojo.declare( "lib._CheckBoxTreeNode", dijit._TreeNode, dojo.declare( "lib.CheckBoxTree", dijit.Tree, { - + onNodeChecked: function(/*dojo.data.Item*/ storeItem, /*treeNode*/ treeNode) { // summary: // Callback when a checkbox tree node is checked // tags: // callback }, - + onNodeUnchecked: function(/*dojo.data.Item*/ storeItem, /* treeNode */ treeNode) { // summary: // Callback when a checkbox tree node is unchecked // tags: // callback }, - + _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e) { // summary: // Translates click events into commands for the controller to process @@ -394,7 +396,7 @@ dojo.declare( "lib.CheckBoxTree", dijit.Tree, // the _onClick function is called whenever a 'click' is detected. This // instance of _onClick only handles the click events associated with // the checkbox whos DOM name is INPUT. - // + // var domElement = e.target; // Only handle checkbox clicks here @@ -404,8 +406,8 @@ dojo.declare( "lib.CheckBoxTree", dijit.Tree, this._publish("execute", { item: nodeWidget.item, node: nodeWidget} ); // Go tell the model to update the checkbox state - - this.model.updateCheckbox( nodeWidget.item, nodeWidget._checkbox.checked ); + + this.model.updateCheckbox( nodeWidget.item, nodeWidget._checkbox.checked ); // Generate some additional events //this.onClick( nodeWidget.item, nodeWidget, e ); if(nodeWidget._checkbox.checked) { @@ -415,19 +417,19 @@ dojo.declare( "lib.CheckBoxTree", dijit.Tree, } this.focusNode(nodeWidget); }, - + _onCheckboxChange: function(/*dojo.data.Item*/ storeItem ) { // summary: // Processes notification of a change to a checkbox state (triggered by the model). // description: - // Whenever the model changes the state of a checkbox in the dojo.data.store it will - // trigger the 'onCheckboxChange' event allowing the Tree to make the same changes + // Whenever the model changes the state of a checkbox in the dojo.data.store it will + // trigger the 'onCheckboxChange' event allowing the Tree to make the same changes // on the tree Node. There are several conditions why a tree node or checkbox does not // exists: // a) The node has not been created yet (the user has not expanded the tree node yet). // b) The checkbox may be null if condition (a) exists or no 'checkbox' attribute was - // specified for the associated dojo.data.item and the attribute 'checkboxAll' is - // set to false. + // specified for the associated dojo.data.item and the attribute 'checkboxAll' is + // set to false. // tags: // callback var model = this.model, @@ -443,13 +445,13 @@ dojo.declare( "lib.CheckBoxTree", dijit.Tree, } }, this ); } - }, + }, postCreate: function() { // summary: - // Handle any specifics related to the tree and model after the instanciation of the Tree. + // Handle any specifics related to the tree and model after the instanciation of the Tree. // description: - // Validate if we have a 'write' store first. Subscribe to the 'onCheckboxChange' event + // Validate if we have a 'write' store first. Subscribe to the 'onCheckboxChange' event // (triggered by the model) and kickoff the initial checkbox data validation. // var store = this.model.store;