1. #1
    Sencha Premium Member
    Join Date
    Jun 2011
    Location
    Toronto
    Posts
    74
    Vote Rating
    10
    roger.spall will become famous soon enough

      0  

    Default Tri-state tree

    Tri-state tree


    I guess it will take time for the 3.3 extemsions to catch up with ExtJs 4.0.1...

    But I would still like to know if anyone can point me to an ExtJS 4 tri-state tree?

    Thanks,

    Roger

  2. #2
    Sencha Premium Member
    Join Date
    Jun 2011
    Location
    Toronto
    Posts
    74
    Vote Rating
    10
    roger.spall will become famous soon enough

      0  

    Default Solution - critiques / feedback required...

    Solution - critiques / feedback required...


    I have included my solution below and would appreciate any feedback / suggestions / comments from others...

    USAGE:
    Code:
     var permissionsTree = Ext.create('Ext.tree.Panel', {
      title : 'Permissions',
      region : 'east',
      width: '100%',
      hideHeaders : true,
      rootVisible : false,
      animate : false,
      store : functionStore,
      viewConfig : {
       plugins : [ tristate ],
       listeners : {
        'beforetristate' : confirmPermissionsModified,
        'tristate' : permissionsModified
       }
      },
      columns : [ {
       xtype : 'tristatetreecolumn',
       flex : 2,
       sortable : true,
       dataIndex : 'name'
      } ], buttons:[{text:"Reset", disabled: true,id:'reset', handler: resetPermissions},{text:"Save", disabled: true,id:'save', handler: savePermissions}]
     });
    
    EXTENSION IMPLEMENTATION:

    Code:
     
    Ext.define('tristate.Plugin', {
     init : function(view) {
      view.updateParent = function(node) {
       if (node != null) {
        var tristate = -1;
        node.eachChild(function(rec) {
         var siblingTristrate = rec.get('tristate');
         if (tristate == -1) {
          tristate = siblingTristrate;
         } else {
          if (siblingTristrate != tristate) {
           tristate = 2;
           return false;
          }
         }
        });
        if (tristate != -1) {
         node.set('tristate', tristate);
        }
        this.updateParent(node.parentNode);
       }
      };
      view.onCheckboxChange = function(e, t) {
       var item = e.getTarget(this.getItemSelector(), this.getTargetEl()), record, value, newValue;
       if (item) {
        record = this.getRecord(item);
        value = record.get('tristate');
        newValue = value == 0 ? 1 : 0;
        var shouldContinue=this.fireEvent('beforetristate', record, newValue);
        if (shouldContinue){
         var affectedRecords=[];
         record.cascadeBy(function(rec) {
          rec.set('tristate', newValue);
          affectedRecords[affectedRecords.length]=rec;
         });
         record.set('tristate', newValue);
         this.updateParent(record.parentNode);
         this.fireEvent('tristate', record, newValue, affectedRecords);
        }
       }
      };
      view.setTristate = function(record, value) {
       record.cascadeBy(function(rec) {
        rec.set('tristate', value);
       });
       record.set('tristate', value);
       this.updateParent(record.parentNode);
      };
      view.setAllTristate = function(status) {
       this.getStore().each(function(rec) {
        rec.cascadeBy(function(rec) {
         rec.set('tristate', status);
        });
       }, true);
      };
      view.getChecked = function() {
       this.getChecked(false);
      };
      view.getChecked = function(partialMeansChecked) {
       var checked = [];
       this.node.cascadeBy(function(rec) {
        var ts = rec.get('tristate');
        if (ts > 0 && (partialMeansChecked || ts == 1)) {
         checked.push(rec);
        }
       });
       return checked;
      };
      view.getCheckedLeafs = function() {
       var checked = [];
       this.node.cascadeBy(function(rec) {
        if (rec.isLeaf() && rec.get('tristate') > 0) {
         checked.push(rec);
        }
       });
       return checked;
      };
     }
    });
    Ext.define('tristate.Column', {
     extend : 'Ext.grid.column.Column',
     alias : 'widget.tristatetreecolumn',
     initComponent : function() {
      var origRenderer = this.renderer || this.defaultRenderer, origScope = this.scope || window;
      this.renderer = function(value, metaData, record, rowIdx, colIdx, store, view) {
       var buf = [], format = Ext.String.format, depth = record.getDepth(), treePrefix = Ext.baseCSSPrefix + 'tree-', elbowPrefix = treePrefix + 'elbow-', expanderCls = treePrefix + 'expander', imgText = '<img src="{1}" class="{0}" />', checkboxText = '<input type="button" role="checkbox" class="{0}" {1} />', formattedValue = origRenderer.apply(origScope, arguments), href = record
         .get('href'), target = record.get('hrefTarget'), cls = record.get('cls');
       while (record) {
        if (!record.isRoot() || (record.isRoot() && view.rootVisible)) {
         if (record.getDepth() === depth) {
          buf.unshift(format(imgText, treePrefix + 'icon ' + treePrefix + 'icon' + (record.get('icon') ? '-inline ' : (record.isLeaf() ? '-leaf ' : '-parent ')) + (record.get('iconCls') || ''), record.get('icon') || Ext.BLANK_IMAGE_URL));
          var tristate = record.get('tristate');
          if (tristate != null) {
           buf.unshift(format(checkboxText, (treePrefix + 'checkbox') + (tristate == 1 ? ' ' + treePrefix + 'checkbox-checked' : (tristate == 2 ? ' ' + treePrefix + 'checkbox-partial-checked' : '')), record.get('checked') ? 'aria-checked="true"' : ''));
           if (tristate > 0) {
            metaData.tdCls += (' ' + Ext.baseCSSPrefix + 'tree-checked');
           }
          }
          if (record.isLast()) {
           if (record.isLeaf() || (record.isLoaded() && !record.hasChildNodes())) {
            buf.unshift(format(imgText, (elbowPrefix + 'end'), Ext.BLANK_IMAGE_URL));
           } else {
            buf.unshift(format(imgText, (elbowPrefix + 'end-plus ' + expanderCls), Ext.BLANK_IMAGE_URL));
           }
          } else {
           if (record.isLeaf() || (record.isLoaded() && !record.hasChildNodes())) {
            buf.unshift(format(imgText, (treePrefix + 'elbow'), Ext.BLANK_IMAGE_URL));
           } else {
            buf.unshift(format(imgText, (elbowPrefix + 'plus ' + expanderCls), Ext.BLANK_IMAGE_URL));
           }
          }
         } else {
          if (record.isLast() || record.getDepth() === 0) {
           buf.unshift(format(imgText, (elbowPrefix + 'empty'), Ext.BLANK_IMAGE_URL));
          } else if (record.getDepth() !== 0) {
           buf.unshift(format(imgText, (elbowPrefix + 'line'), Ext.BLANK_IMAGE_URL));
          }
         }
        }
        record = record.parentNode;
       }
       if (href) {
        formattedValue = format('<a href="{0}" target="{1}">{2}</a>', href, target, formattedValue);
       }
       if (cls) {
        metaData.tdCls += ' ' + cls;
       }
       return buf.join("") + formattedValue;
      };
      this.callParent(arguments);
     },
     defaultRenderer : function(value) {
      return value;
     }
    });
    

  3. #3
    Sencha User beavx420's Avatar
    Join Date
    May 2007
    Location
    New Jersey
    Posts
    32
    Vote Rating
    1
    beavx420 is on a distinguished road

      0  

    Default


    Roger... can you wrap your post in code tags, so the forums will format it correctly? Thanks!!

  4. #4
    Sencha User
    Join Date
    Apr 2009
    Posts
    48
    Vote Rating
    0
    morfeusz is on a distinguished road

      0  

    Default


    Can it be used for simply form`s checkBox?

  5. #5
    Sencha Premium Member
    Join Date
    Jun 2011
    Location
    Toronto
    Posts
    74
    Vote Rating
    10
    roger.spall will become famous soon enough

      0  

    Default


    No, it is strictly intended for grid trees

  6. #6
    Sencha User
    Join Date
    Mar 2010
    Posts
    51
    Vote Rating
    2
    koblass is on a distinguished road

      0  

    Default Do you have a running example ?

    Do you have a running example ?


    Hi,

    I've tried your code without any success...
    Do you have a running example ?

    Best
    Daniel

  7. #7
    Sencha User
    Join Date
    Nov 2010
    Posts
    12
    Vote Rating
    0
    x10 is on a distinguished road

      0  

    Default


    Does it work? I have also tried the code without any success.

  8. #8
    Sencha Premium Member
    Join Date
    Jun 2011
    Location
    Toronto
    Posts
    74
    Vote Rating
    10
    roger.spall will become famous soon enough

      0  

    Default


    It definitely works and is in production at a client:

    Code:
    Ext.define('common.admin.DealerUserPermissionsTreePanel', {
                   extend : 'Ext.tree.Panel',
                   requires : [ "common.TristatePlugin" ],
                   title : 'Permissions',
                   width : '100%',
                   height: '100%',
                   hideHeaders : true,
                   rootVisible : false,
                   constructor : function(config) {
                   Ext.define('FunctionModel', {
                                  extend : 'Ext.data.Model',
                                  fields : [ 'oid', 'name' ]
                   });
                  
                   this.functionStore = Ext.create('Ext.data.TreeStore', {
                                  model : 'FunctionModel',
                                  sorters : [ {
                                                 property : 'name',
                                                 direction : 'ASC'
                                  } ],
                                  proxy : {
                                                 type : 'memory'
                                  },
                                  folderSort : true
                   });
                   var tristate = Ext.create('common.TristatePlugin');
                   this.callParent([ {
                                  store : this.functionStore,
                                  viewConfig : {
                                                 plugins : [ tristate ],
                                                 listeners : {
                                                                'beforetristate' : {
                                                                               fn : this.confirmPermissionsModified,
                                                                               scope : this
                                                                },
                                                                'tristate' : {
                                                                               fn : this.permissionsModified,
                                                                               scope : this
                                                                }
                                                 }
                                  },
                                  columns : [ {
                                                 xtype : 'tristatetreecolumn',
                                                 flex : 2,
                                                 sortable : true,
                                                 dataIndex : 'name'
                                  } ],
                                  buttons : [ {
                                                 text : "Save",
                                                 disabled : true,
                                                 scope : this,
                                                 id : 'save',
                                                 handler : this.savePermissions
                                  },
                                  {
                                                 text : "Reset",
                                                 disabled : true,
                                                 scope : this,
                                                 id : 'reset',
                                                 handler : this.resetPermissions
                                  }
                                  ]                             
                                 
                   }]);
                   this.loadFunctions();
                   },
                   resetPermissions : function() {
                                  this.loadPermissions(this.userOid,this.userId);
                   },
                   savePermissions : function() {
                                  var functions = this.getView().getCheckedLeafs();
                                  var permissions = [];
                                  for ( var i = 0; i < functions.length; i++) {
                                                 var oid = functions[i].get("oid");
                                                 if (Ext.Array.indexOf(permissions, oid) == -1) {
                                                                permissions[permissions.length] = oid;
                                                 }
                                  }
                                  Ext.Ajax.request({
                                                 url : getDataRequestURL('userPermissions', 'setPermissions'),
                                                 params : {
                                                                userOid : this.userOid,
                                                                permissions : permissions
                                                 },
                                                 scope : this,
                                                 success : this.successfulSave,
                                                 failure : this.failedSave
                                  });
                   },
                   successfulSave : function(response, request) {
                                  this.setModified(false);
                                  Ext.Msg.alert('Success','Saved');
                   },
                   failedSave : function(response, request) {
                                  Ext.Msg.alert('Failed','Failed to save: "' + response.status + " - " + response.statusText + '"');
                   },
                   loadPermissions : function(userOid, userId) {
                                  this.userOid = userOid;
                                  this.userId = userId;
                                  Ext.Ajax.request({
                                                 url : getDataRequestURL('userPermissions', 'getPermissions'),
                                                 params : {
                                                                userOid : userOid
                                                 },
                                                 scope : this,
                                                 success : this.setPermissions,
                                                 failure : function(response, request) {
                                                                                              Ext.Msg.alert('Failed', response.responseText);
                                                                                 }
                                  });
                   },
                   setPermissions : function(response, request) {
                                  if (response.status == 200) {
                                                 var security = Ext.decode(response.responseText);
                                                 this.setTitle("Permissions for user '" + this.userId+ "'");
                                                 this.setCurrentUserPermissions(security.permissions);
                                                 this.setModified(false);
                                  } else {
                                                 Ext.Msg.alert('Failed','Failed to Set Threads from server response');
                                  }
                   },
                   setCurrentUserPermissions : function(permissions) {
                                  var view = this.getView();
                                  view.setAllTristate(0);
                                  permissions.sort();
                                  var root = this.functionStore.getRootNode();
                                  root.cascadeBy(function(rec) {
                                                 if (rec.isLeaf()) {
                                                                var oid = rec.get("oid");
                                                                var pos = Ext.Array.indexOf(permissions, oid);
                                                                if (pos > -1) {
                                                                               rec.set("tristate", 1);
                                                                               view.updateParent(rec);
                                                                }
                                                 }
                                  });
                   },
                   loadFunctions : function(){
                                  //this.getEl().mask('Loading data...');                       
                                  Ext.Ajax.request({
                                                 url : getDataRequestURL('userPermissions', 'getFunctions'),
                                                 scope : this,
                                                 success : this.setFunctions
                                  });
                                 
                   },
                   setFunctions : function(response, request) {
                                  //this.getEl().unmask();
                                  if (response.status == 200) {
                                                 var result = Ext.decode(response.responseText);
                                                 var root = this.functionStore.getRootNode();
                                                 root.removeAll();
                                                 for ( var i = 0; i < result.items.length; i++) {
                                                                this.buildNode(root, result.items[i]);
                                                 }
                                                 this.modified = false;                                     
                                  } else {
                                                 alert("Failed to Set Functions from server response");
                                  }
                   },
                   buildNode : function(root, items) {
                                  if (items[0].length) {
                                                 var parent = root.appendChild({
                                                                name : items[items.length - 1],
                                                                leaf : false,
                                                                tristate : 0
                                                 });
                                                 for ( var i = 0; i < items.length - 1; i++) {
                                                                this.buildNode(parent, items[i]);
                                                 }
                                  } else {
                                                 root.appendChild({
                                                                oid : items[0],
                                                                name : items[1],
                                                                leaf : true,
                                                                tristate : 0
                                                 });
                                  }
                   },
                   confirmPermissionsModified : function(record, value) {
                                  if (!this.userOid){
                                                 showError("Must Select a User first");
                                                 return false;
                                  }
                   },
                   permissionsModified : function(record, value, affected) {
                                  var affectedIds = [];
                                  var affectedOids = [];
                                  for ( var i = 0; i < affected.length; i++) {
                                                 var rec = affected[i];
                                                 if (rec.isLeaf()) {
                                                                affectedIds[affectedIds.length] = rec.id;
                                                                affectedOids[affectedOids.length] = rec.get("oid");
                                                 }
                                  }
                                  affectedIds.sort();
                                  affectedOids.sort();
                                  var view = this.getView();
                                  this.functionStore.getRootNode().cascadeBy(function(rec) {
                                                 if (Ext.Array.indexOf(affectedOids, rec.get("oid")) > -1 && Ext.Array.indexOf(affectedIds, rec.id) == -1) {
                                                                view.setTristate(rec, value);
                                                 }
                                  });
                                  this.setModified(true);
                   },
                   setModified : function(modified) {
                                  this.query("#save")[0].setDisabled(!modified);
                                  this.query("#reset")[0].setDisabled(!modified);
                   }
                  
    });

  9. #9
    Sencha User
    Join Date
    Nov 2010
    Posts
    12
    Vote Rating
    0
    x10 is on a distinguished road

      0  

    Default


    Thanks Roger. It works, but not 'definitely'.
    1. I have splitted your 'extension code' from 2nd post into 2 files/classes.
    2. I have correctly namespaced them (and registered into my Ext.Loader 'paths' config)
    3. I had to define field 'tristate' in my Model of TreeStore. It was not working without it.
    4. I have disabled the test 'shouldContinue', because i don't have any listener for 'beforetristate'. IMO the cascade should be always recalculated. (?)
    5. Now it is working, but the style for tristate==2 ('checkbox-partial-checked') is never being rendered. I see only standard on/off checkboxes. (?)

    ? Is your code in 2nd post still valid ?

  10. #10
    Sencha User
    Join Date
    Nov 2010
    Posts
    12
    Vote Rating
    0
    x10 is on a distinguished road

      0  

    Default


    Quote Originally Posted by x10 View Post
    5. Now it is working, but the style for tristate==2 ('checkbox-partial-checked') is never being rendered. I see only standard on/off checkboxes. (?)
    SOLVED:
    Code:
    .x-tree-checkbox-partial-checked {
        background-position:0 -26px;
    }

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..." hd porno faketaxi