neyric/wireit

View on GitHub
sandbox/grouping/js/Grouper.js

Summary

Maintainability
A
3 hrs
Test Coverage
(function() {

/**
 * @class Grouper
 */    
Y.Grouper = function (layer, baseConfigFunction) {
    
    this.layer = layer;
    this.baseConfigFunction = baseConfigFunction;
    this.containers = [];
    this.groups = [];
    this.setupWidget(Y.one("groupConfig"));
    
    //If a container is removed from the layer then remove it from the currently selected groups
    layer.on('eventRemoveContainer', function(eventName, containers) { 
        this.removeContainer(containers[0]);
   }, this, true);
    
    //If a container is added to the layer then we want to listen to the focus event so we can show group information
    layer.on('eventAddContainer', function(eventName, container) {
        var display = this.display;
        container[0].on('eventFocus', function(eventName, containers)  { 
            var container = containers[0];
            if (Y.Lang.isValue(container.group)) {
                this.showGroup(container.group);
            }
            else {
                this.deselectGroup();
                this.hideGroupConfigure();
            }
        }, this, true);

   }, this, true);
        
    this.rubberband = new Y.RubberBand(this);
    
    this.rubberband.style = {};
    this.rubberband.style.position = "absolute";
    
};



Y.Grouper.prototype = {

    /**
     * setupWidget
     */
   setupWidget: function(displayDiv) {
    
        this.display = {};
        this.display.mainDiv = displayDiv;
        
        this.display.buttonsElement = Y.WireIt.cn("div");
        displayDiv.appendChild(this.display.buttonsElement);
        
            var collapseButton = Y.WireIt.cn("button", {}, {}, "Collapse");
        collapseButton.id = "groupConfigCollapseButton";
        this.display.buttonsElement.appendChild(collapseButton);
        Y.one('#groupConfigCollapseButton').on('click', this.groupCollapse, this, true);
        
        var groupSelect = Y.WireIt.cn("select");
        this.display.groupSelect = groupSelect;
        groupSelect.id = "groupConfigGroupSelect";
        this.display.buttonsElement.appendChild(groupSelect);
        
        Y.one('#groupConfigGroupSelect').on('change', function () { this.selectGroup.call(this, groupSelect); } , this, true);
        
        var ungroupButton = Y.WireIt.cn("button", {}, {}, "Ungroup");
        ungroupButton .id = "groupUngroupButton";
        this.display.buttonsElement.appendChild(ungroupButton);
        Y.one('#groupUngroupButton').on('click', this.unGroup, this, true);
        
        var body = Y.WireIt.cn("div");
        displayDiv.appendChild(body);
        
        var list = Y.WireIt.cn("table", {id: "groupPanelBodyList"});
        this.display.list = list;
        body.appendChild(list);
        
        var row = Y.WireIt.cn("tr");
        this.display.listHeadRow = row;
        
        list.appendChild(row);
        row.appendChild(Y.WireIt.cn("th", {}, {}, "Name"));
        row.appendChild(Y.WireIt.cn("th", {}, {}, "Visible"));
        row.appendChild(Y.WireIt.cn("th", {}, {}, "New name"));
        row.appendChild(Y.WireIt.cn("th", {}, {}, "Show"));

        this.hideGroupConfigure();
    },
    
    /**
     * setDisplay
     */
   setDisplay: function (rows) {
        this.display.list.innerHTML = "";
        this.display.list.appendChild(this.display.listHeadRow);
    
        for (var rI in rows) {
            this.display.list.appendChild(rows[rI]);
        }
   },
   
    /**
     * groupCollapse
     */
   groupCollapse: function() {
        if (Y.Lang.isValue(this.selectedGroup)) {
            this.selectedGroup.collapse();
        }
   },
    
    /**
     * selectGroup
     */
   selectGroup: function(select) {
        var index = select.selectedIndex;
        if (index >= 0 && Y.Lang.isArray(this.selectedGroups) && index < this.selectedGroups.length) {
            var group = this.selectedGroups[index];
            this.showGroupConfigure(group);
        }
        else {
           alert("index wrong (" + index + ")");
        }
   },
    
    /**
     * unGroup
     */
   unGroup: function() {
        if (Y.Lang.isValue(this.selectedGroup)) {
            var selGroup = this.selectedGroup;
            this.deselectGroup();
            selGroup.unGroup();
        }
   },
    
   /**
      * setGroupOptions
     */
    setGroupOptions: function() {
        var containerUIMap = this.display.containerUIMap;
        var groupUIMap = this.display.groupUIMap;
        var group = this.selectedGroup;
    
        var checkedOverrides = group.getAndCheckOverrides(containerUIMap, groupUIMap);
    
        if (checkedOverrides.valid) {
            group.setGroupOptions(checkedOverrides.overrides);
        }
        else {
            alert("Validation error, " + checkedOverrides.error.message);
        }
    },
   
      /**
       * addContainer
       */
    addContainer: function(container) {
    
        if (Y.Lang.isValue(container.group)) {
           var group = Y.GroupUtils.getOuterGroup(container.group);
           this.addGroup(group);
        }
        else if (this.containers.indexOf(container) == -1) {
            this.containers.push(container);        
            container.addedToGroup();
        }
    },
    
     /**
      * removeContainer
      */
    removeContainer: function(container, index) {
        if (!Y.Lang.isValue(index)) {
            index = this.containers.indexOf(container);
        }
        
        if (index != -1) {
            this.containers.splice(index, 1);
            //this.group.removeContainer(container);
            container.removedFromGroup();
        }
        /*else
            alert("not here");*/
    },
    
     /**
      * addGroup
      */
    addGroup: function(group) {
    
        if (this.groups.indexOf(group) == -1) {
            this.groups.push(group);
            var groupSelect = function(g) { Y.GroupUtils.applyToContainers(g, true, function(c) { c.addedToGroup(); }); };
        
            groupSelect(group);
        
            group.on('groupEmptied', function() { this.removeGroup(group); }, this, true);
            group.on('containerAdded', function(eventName, containers) { containers[0].addedToGroup(); }, this, true);
            group.on('groupAdded', function(eventName, groups) { groupSelect(groups[0]); }, this, true);
        
            group.on('containerRemoved', function(eventName, containers) { this.addContainer(containers[0]); }, this, true);
            group.on('groupRemoved', function(eventName, groups) { this.addGroup(groups[0]); }, this, true);
        }
   },

    /**
     * removeGroup
     */
   removeGroup: function(group, index) {
        
        if (!Y.Lang.isValue(index)) {
            index = this.groups.indexOf(group);
        }
    
        if (index != -1) {
            this.groups.splice(index, 1);
            var containers = [];
            Y.GroupUtils.addAllContainers(group, containers);
        
            for (var cI in containers) {
                containers[cI].removedFromGroup();
            }
        }
   },

    /**
     * toggle
     */
   toggle: function(container) {
        if (Y.Lang.isValue(container.group)) {
            var group = Y.GroupUtils.getOuterGroup(container.group);
            var groupIndex = this.groups.indexOf(group);
        
            if (groupIndex == -1)
                this.addGroup(group);
            else
                this.removeGroup(group, groupIndex);
        }
        else {
            var index = this.containers.indexOf(container);
            if (index == -1)
                this.addContainer(container);
            else
                this.removeContainer(container, index);
        }
   },
   
     /**
     * makeGroup
     */
   makeGroup: function() {
        
        if (this.containers.length > 0 || this.groups.length > 0) {
            var group = new Y.Group(this, this.layer);
            var tempGroups = [];
            var tempContainers = [];
        
            for (var cI in this.containers) {
                var c = this.containers[cI];
                group.addContainer(c);
                tempContainers.push(c);
            }
        
            for (var gI in this.groups) {
                var g = this.groups[gI];
                group.addGroup(g);
                this.layer.removeGroup(g);
                tempGroups.push(g);
            }
        
            for (var tcI in tempContainers)
                this.removeContainer(tempContainers[tcI]);
            for (var tgI in tempGroups)
                this.removeGroup(tempGroups[tgI]);
        
            this.layer.groups.push(group);
            group.on('groupEmptied', function() { this.layer.removeGroup.call(this.layer, group); }, this, true);        

            this.showGroup(group, true);
        }
   },
    
    /**
     * showGroup
     */
   showGroup: function(group, forceThisGroup) {
        
        var g;
        if (forceThisGroup)
            g = group;
        else
            g = Y.GroupUtils.getOuterGroup(group);
        
        this.showGroupConfigure.call(this, g);
        this.setupSelectedGroups(group);
   },
   
     /**
      * setupSelectedGroups
      */
   setupSelectedGroups: function(bottomGroup) {
        var selectedGroups = [];
        this.selectedGroups = selectedGroups;
    
        var display = this.display;
        display.groupSelect.innerHTML = "";
        var selectedGroup = this.selectedGroup;
    
        Y.GroupUtils.getOuterGroup(bottomGroup, function(current) {
            var option = Y.WireIt.cn("option", {value: "N" + selectedGroups.length}, {}, "N" + selectedGroups.length);
            selectedGroups.push(current);
        
            display.groupSelect.appendChild(option);
        
            if (selectedGroup == current)
                option.selected = true;
            }
        );
   },
    
    /**
     * showGroupConfigure
     */
   showGroupConfigure: function(group, map) {
        
        if (!Y.Lang.isValue(group) || Y.Lang.isValue(group.groupContainer)) {
            hideGroupConfigure(); //TODO: you should be able to modify group mappings while collapsed
        }
        else {
            var self = this;
            var ui = group.generateUI(map, function() { self.setGroupOptions.call(self); });
            this.setDisplay(ui.listRows);
    
            this.setSelectedGroup(group);
            this.display.containerUIMap = ui.containerUIMap;
            this.display.groupUIMap = ui.groupUIMap;
    
            group.on('stateChanged', function() {
                this.deselectGroup();
                this.hideGroupConfigure();
            }, this, true);
    
            this.display.mainDiv.style.display = "block"; //TODO: safter visibility toggle?
        }
   },
   
     /**
      * hideGroupConfigure
     */
   hideGroupConfigure: function() {
        this.display.mainDiv.style.display = "none";//safter visibility toggle?
   },
    
    /**
     * setSelectedGroup
     */
   setSelectedGroup: function(group) {
        this.deselectGroup();
        this.selectedGroup = group;
        Y.GroupUtils.applyToContainers(this.selectedGroup, true, function(c) { c.highlight(); });
   },
    
    /**
     * deselectGroup
     */
   deselectGroup: function() {
        
        if (Y.Lang.isValue(this.selectedGroup))
            Y.GroupUtils.applyToContainers(this.selectedGroup, true, function(c) { c.dehighlight(); });
        
        this.selectedGroup = null;
   },
    
    /**
     * rubberbandSelect
     */
   rubberbandSelect: function() {
        
        for (var cI in this.layer.containers) {
            var c = this.layer.containers[cI];
        
            var checkPoints = this.getContainerCorners(c);
            var inside = true;
        
            for (var i in checkPoints)
                inside &= this.rubberband.pointIsInside(checkPoints[i].x, checkPoints[i].y);
        
            if (inside) {
                this.addContainer(c);
            }
        }
    
   },
   
     /**
     * getContainerCorners
      */
   getContainerCorners: function(container) {
        var top = container.el.offsetTop;
        var bottom = top+container.el.offsetHeight;
    
        var left = container.el.offsetLeft;
        var right = left+container.el.offsetWidth;
    
        return [
            {x : left, y: top},
            {x : left, y: bottom},
            {x : right, y: top},
            {x : right, y: bottom}
        ];
   }

};


})();