<commit_before>({
    init : function(component) {
        //Retrieving hierarchy settings
        this.getHierarchySettings(component);
        // since we can't call this.processTabs(component, 'afflTabBtn') from here
        // well process the tabs manually here.
        $A.util.addClass(component.find("afflTab"), "slds-active");

        $A.util.addClass(component.find("afflTabContent"), "slds-show");
        $A.util.addClass(component.find("relTabContent"), "slds-hide");
        $A.util.addClass(component.find("addrTabContent"), "slds-hide");
        $A.util.addClass(component.find("coursesTabContent"), "slds-hide");
        $A.util.addClass(component.find("courseConTabContent"), "slds-hide");
        $A.util.addClass(component.find("systemTabContent"), "slds-hide");
    },

    getHierarchySettings : function(component) {
        var prefix = component.get("v.namespacePrefix");
        var action = component.get("c.getSettings");
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var settings = response.getReturnValue();
                var settingsNoPrefix = this.removePrefixHierarchySettings(settings, prefix);
                component.set("v.hierarchySettings", settingsNoPrefix);
                //Even though this property is only used but the CMP_System component, we set it here
                //because this method is called after the init method of that component.
                component.set("v.accRecTypeId", settingsNoPrefix.Account_Processor__c);
                component.set("v.householdRecTypeId", settingsNoPrefix.Household_Addresses_RecType__c);
                component.set("v.adminAccRecTypeId", settingsNoPrefix.Administrative_Account_Record_Type__c);
                component.set("v.studentRecTypeId", settingsNoPrefix.Student_RecType__c);
                component.set("v.facultyRecTypeId", settingsNoPrefix.Faculty_RecType__c);
                component.set("v.affiliationRoleMapValue",settingsNoPrefix.Affl_ProgEnroll_Role_Map__c);
                component.set("v.affiliationStatusMapValue",settingsNoPrefix.Affl_ProgEnroll_Status_Map__c);
                component.set("v.affiliationStatusDeleteMapValue",settingsNoPrefix.Affl_ProgEnroll_Del_Status__c);

                component.set("v.adminNameFormat", settingsNoPrefix.Admin_Account_Naming_Format__c);
                component.set("v.hhNameFormat", settingsNoPrefix.Household_Account_Naming_Format__c);
                component.set("v.adminOtherDisplay",this.getOtherDisplay(component, settingsNoPrefix.Admin_Account_Naming_Format__c));
                component.set("v.hhOtherDisplay",this.getOtherDisplay(component, settingsNoPrefix.Household_Account_Naming_Format__c));

                //Get account record types
                this.getAccountRecordTypes(component, settingsNoPrefix.Accounts_to_Delete__c,
                        settingsNoPrefix.Accounts_Addresses_Enabled__c, settingsNoPrefix.Account_Processor__c,
                        settingsNoPrefix.Household_Addresses_RecType__c, settingsNoPrefix.Administrative_Account_Record_Type__c);
                // Get Affiliation Role Picklist
                this.getAffiliationRolePicklistEntries(component,settingsNoPrefix.Affl_ProgEnroll_Role_Map__c);
                // Get Affiliation Status Picklist
                this.getAffiliationStatusPicklistEntries(component,settingsNoPrefix.Affl_ProgEnroll_Status_Map__c,settingsNoPrefix.Affl_ProgEnroll_Del_Status__c);
                // Get Course Connection Record Types
                this.getCourseConnectionRecordTypes(component, settingsNoPrefix.Student_RecType__c,
                        settingsNoPrefix.Faculty_RecType__c);
            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    //We are calling this method here instead of in STG_CMP_SystemHelper because if we do so, the action
    //getAccountRecordTypes in STG_CMP_SystemHelper gets called before the action getHierarchySettings in
    //this helper. And we need the Account Processor value from HierarchySettings.
    getAccountRecordTypes : function(component, accsToDelete, accsMultiAddr, accTypeId, householdTypeId, adminTypeId) {
        //Get all available account record types
        var action = component.get("c.getRecTypesMapByName");
        action.setParams({ "objectName" : 'Account'});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var recTypesObj = response.getReturnValue();
                var accRecTypes = [];
                for(var property in recTypesObj) {
                    if (recTypesObj.hasOwnProperty(property)) {
                        accRecTypes.push({name: property, id: recTypesObj[property]});
                        //Find the name of the account record type that matches the stored ID.
                        //We check if one string is contained in the other because in one case we have
                        //the 15 digit id, and in the other the 18 digit one.
                        if(recTypesObj[property].indexOf(accTypeId) > -1) {
                            component.set("v.accRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(householdTypeId) > -1) {
                            component.set("v.householdRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(adminTypeId) > -1) {
                            component.set("v.adminAccRecTypeName", property);
                        }
                    }
                }
                component.set("v.accRecTypes", accRecTypes);

                //Get record types of accounts that can be deleted if all their children have been deleted. We need to call this
                //method here because this logic is called after the init method in STG_CMP_AddrController.
                var accTypesToDeleteSelected = this.getRecTypesSelected(component, accsToDelete, accRecTypes);
                component.set("v.accTypesToDeleteSelected", accTypesToDeleteSelected);

                //Get record types of accounts that have multi-address support enabled. We need to call this method here because this
                //logic is called after the init method in STG_CMP_AddrController.
                var accTypesAddrSelected = this.getRecTypesSelected(component, accsMultiAddr, accRecTypes);
                component.set("v.accTypesAddrSelected", accTypesAddrSelected);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getAffiliationRolePicklistEntries : function(component, roleValue) {
        //Get all active affiliation role picklist entries
        var action = component.get("c.getPicklistActiveValuesMap");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Affiliation__c';
        var fieldName = prefix + 'Role__c';

        action.setParams({ "objectName" : objectName,"fieldName" : fieldName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var picklistValues = response.getReturnValue();
                var affiliationRolePicklistEntries = [];

                for(var property in picklistValues) {
                    if (picklistValues.hasOwnProperty(property)) {
                        affiliationRolePicklistEntries.push({picklistLabel: property, picklistValue : picklistValues[property]});

                        if(property.indexOf(roleValue) > -1) {
                            component.set("v.affiliationRoleMapLabel", property);
                        }
                    }
                }

                component.set("v.affiliationRolePicklistEntries", affiliationRolePicklistEntries);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getAffiliationStatusPicklistEntries : function(component, statusValue, deleteValue) {
        //Get all active affiliation status picklist entries
        var action = component.get("c.getPicklistActiveValuesMap");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Affiliation__c';
        var fieldName = prefix + 'Status__c';

        action.setParams({ "objectName" : objectName,"fieldName" : fieldName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var picklistValues = response.getReturnValue();
                var affiliationStatusPicklistEntries = [];

                for(var property in picklistValues) {

                    if (picklistValues.hasOwnProperty(property)) {
                        affiliationStatusPicklistEntries.push({picklistLabel: property, picklistValue: picklistValues[property]});

                        if(property.indexOf(statusValue) > -1) {
                            component.set("v.affiliationStatusMapLabel", property);
                        }

                        if(property.indexOf(deleteValue) > -1) {
                            component.set("v.affiliationStatusDeleteMapLabel", property);
                        }

                    }
                }

                component.set("v.affiliationStatusPicklistEntries", affiliationStatusPicklistEntries);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getCourseConnectionRecordTypes : function(component, studentTypeId, facultyTypeId) {
        //Get all available course connection record types
        var action = component.get("c.getRecTypesMapByName");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Course_Enrollment__c';
        action.setParams({ "objectName" : objectName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var recTypesObj = response.getReturnValue();
                var courseConnectionRecTypes = [];
                for(var property in recTypesObj) {
                    if (recTypesObj.hasOwnProperty(property)) {
                        courseConnectionRecTypes.push({name: property, id: recTypesObj[property]});
                        if(recTypesObj[property].indexOf(studentTypeId) > -1) {
                            component.set("v.studentRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(facultyTypeId) > -1) {
                            component.set("v.facultyRecTypeName", property);
                        }
                    }
                }
                component.set("v.courseConnectionRecTypes", courseConnectionRecTypes);

            } else if(response.getState() === "ERROR") {
              this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    //We want to compare the list of all available Account Record Types with the list of those that have been
    //marked as having enabled in the setting. The setting stores a semi-colon separated list of record type IDs.
    getRecTypesSelected : function(component, setting, recTypes) {
        var settingArray = this.getTokenized(setting);
        var recTypesSelected = [];
        for(var i = 0; i < recTypes.length; i += 1) {
            var recTypeSelected = {};
            recTypeSelected.name = recTypes[i].name;
            recTypeSelected.id = recTypes[i].id;
            recTypeSelected.selected = false; //we set it to false initially
            for(var j = 0; j < settingArray.length; j += 1) {
                if(recTypes[i].id === settingArray[j]) {
                    recTypeSelected.selected = true;
                }
            }
            recTypesSelected.push(recTypeSelected);
        }
        return recTypesSelected;
    },

    saveSettings : function(component) {
        var prefix = component.get("v.namespacePrefix");
        var saveAction = component.get("c.saveHierarchySettings");
        var hierarchySettings = this.addPrefixHierarchySettings(component.get("v.hierarchySettings"), prefix);
        saveAction.setParams({"hierarchySettings" : hierarchySettings});
        saveAction.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                component.set("v.isView", true);
                var tst = component.find("successToast");
                $A.util.removeClass(tst, "slds-hide");
                $A.util.addClass(tst, "slds-show");

                //show manual toast
                window.setTimeout(
                    $A.getCallback(function() {
                        $A.util.removeClass(tst, "slds-show");
                        $A.util.addClass(tst, "slds-hide");
                    }), 3750
                );

            } else if(response.getState() === "ERROR") {
                component.set("v.isView", false);
                this.displayError(response);
            }
        });
        $A.enqueueAction(saveAction);
    },

    closeToast: function(component) {
        var tst = component.find("successToast");
        $A.util.removeClass(tst, "slds-show");
        $A.util.addClass(tst, "slds-hide");
    },

    resetSettings : function(component) {
        this.getHierarchySettings(component);
    },

    tabNavClick : function(component, event) {
        this.processTabs(component, event.getSource().getLocalId() );
    },

    processTabs : function(component, btnId) {
        // Since this method uses querySelector we can't use this method until the DOM is initialized.

        let tabNav = component.find('tabs').getElement().querySelector('ul.slds-tabs--default__nav');
        let contId =  btnId.replace('Btn', 'Content'); // content to show Id
        let tabId  =  btnId.replace('Btn', ''); // clicked tab
        let tabItem  = component.find(tabId);
        let contItem = component.find(contId);
        let matches = tabNav.querySelectorAll('li.slds-tabs__item');

        // Process all Tabs and content
        matches.forEach(function(element) {

            // Link Aura to DOM via GlobalId
            let selectedTab = element.dataset.auraRenderedBy == tabItem.getGlobalId() || false;

            // link this is the clicked element make active, otherwise remove the class
            element.classList.toggle('slds-active', selectedTab );

            // Process Content Tabs
            if( selectedTab ) {
                // Since this is the elected tab, we show that content
                $A.util.removeClass(contItem, "slds-hide");
                $A.util.addClass(contItem, "slds-show");
            } else {
                let tmpComp = component.find(element.getAttribute('id')+'Content');
                // Since we are in a loop we can hide all the other items except those we selected
                $A.util.removeClass(tmpComp, "slds-show");
                $A.util.addClass(tmpComp, "slds-hide");
            }

        });
    },

    getOtherDisplay : function(component, value) {
        var prefix = component.get("v.namespacePrefix");
        var label = '';
        label = $A.get("$Label.c.acctNamingOther");
        if (value === label) {
            return true;
        }else{
            return false;
        }
    }

})
<commit_msg> fixing conflicts<commit_after>({
    init : function(component) {
        //Retrieving hierarchy settings
        this.getHierarchySettings(component);

        // since we can't call this.processTabs(component, 'afflTabBtn') from here
        // well process the tabs manually here.
        $A.util.addClass(component.find("afflTab"), "slds-active");

        $A.util.addClass(component.find("afflTabContent"), "slds-show");
        $A.util.addClass(component.find("relTabContent"), "slds-hide");
        $A.util.addClass(component.find("addrTabContent"), "slds-hide");
        $A.util.addClass(component.find("coursesTabContent"), "slds-hide");
        $A.util.addClass(component.find("courseConTabContent"), "slds-hide");
        $A.util.addClass(component.find("systemTabContent"), "slds-hide");
    },

    getHierarchySettings : function(component) {
        var prefix = component.get("v.namespacePrefix");
        var action = component.get("c.getSettings");
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var settings = response.getReturnValue();
                var settingsNoPrefix = this.removePrefixHierarchySettings(settings, prefix);
                component.set("v.hierarchySettings", settingsNoPrefix);
                //Even though this property is only used but the CMP_System component, we set it here
                //because this method is called after the init method of that component.
                component.set("v.accRecTypeId", settingsNoPrefix.Account_Processor__c);
                component.set("v.householdRecTypeId", settingsNoPrefix.Household_Addresses_RecType__c);
                component.set("v.adminAccRecTypeId", settingsNoPrefix.Administrative_Account_Record_Type__c);
                component.set("v.studentRecTypeId", settingsNoPrefix.Student_RecType__c);
                component.set("v.facultyRecTypeId", settingsNoPrefix.Faculty_RecType__c);
                component.set("v.affiliationRoleMapValue", settingsNoPrefix.Affl_ProgEnroll_Role_Map__c);
                component.set("v.affiliationStatusMapValue", settingsNoPrefix.Affl_ProgEnroll_Status_Map__c);
                component.set("v.affiliationStatusDeleteMapValue", settingsNoPrefix.Affl_ProgEnroll_Del_Status__c);
                component.set("v.defaultContactLanguageFluencyValue", settingsNoPrefix.Default_Contact_Language_Fluency__c);

                component.set("v.adminNameFormat", settingsNoPrefix.Admin_Account_Naming_Format__c);
                component.set("v.hhNameFormat", settingsNoPrefix.Household_Account_Naming_Format__c);
                component.set("v.adminOtherDisplay", this.getOtherDisplay(component, settingsNoPrefix.Admin_Account_Naming_Format__c));
		        component.set("v.hhOtherDisplay", this.getOtherDisplay(component, settingsNoPrefix.Household_Account_Naming_Format__c));

                //Get account record types
                this.getAccountRecordTypes(component, settingsNoPrefix.Accounts_to_Delete__c,
                        settingsNoPrefix.Accounts_Addresses_Enabled__c, settingsNoPrefix.Account_Processor__c,
                        settingsNoPrefix.Household_Addresses_RecType__c, settingsNoPrefix.Administrative_Account_Record_Type__c);
                // Get Affiliation Role Picklist
                this.getAffiliationRolePicklistEntries(component, settingsNoPrefix.Affl_ProgEnroll_Role_Map__c);
                // Get Affiliation Status Picklist
                this.getAffiliationStatusPicklistEntries(component, settingsNoPrefix.Affl_ProgEnroll_Status_Map__c, settingsNoPrefix.Affl_ProgEnroll_Del_Status__c);
                // Get Course Connection Record Types
                this.getCourseConnectionRecordTypes(component, settingsNoPrefix.Student_RecType__c,
                        settingsNoPrefix.Faculty_RecType__c);
                // Get Contact Language Fluency Picklist
                this.getFluencyPicklistEntries(component, settingsNoPrefix.Default_Contact_Language_Fluency__c);
            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    //We are calling this method here instead of in STG_CMP_SystemHelper because if we do so, the action
    //getAccountRecordTypes in STG_CMP_SystemHelper gets called before the action getHierarchySettings in
    //this helper. And we need the Account Processor value from HierarchySettings.
    getAccountRecordTypes : function(component, accsToDelete, accsMultiAddr, accTypeId, householdTypeId, adminTypeId) {
        //Get all available account record types
        var action = component.get("c.getRecTypesMapByName");
        action.setParams({ "objectName" : 'Account'});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var recTypesObj = response.getReturnValue();
                var accRecTypes = [];
                for(var property in recTypesObj) {
                    if (recTypesObj.hasOwnProperty(property)) {
                        accRecTypes.push({name: property, id: recTypesObj[property]});
                        //Find the name of the account record type that matches the stored ID.
                        //We check if one string is contained in the other because in one case we have
                        //the 15 digit id, and in the other the 18 digit one.
                        if(recTypesObj[property].indexOf(accTypeId) > -1) {
                            component.set("v.accRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(householdTypeId) > -1) {
                            component.set("v.householdRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(adminTypeId) > -1) {
                            component.set("v.adminAccRecTypeName", property);
                        }
                    }
                }
                component.set("v.accRecTypes", accRecTypes);

                //Get record types of accounts that can be deleted if all their children have been deleted. We need to call this
                //method here because this logic is called after the init method in STG_CMP_AddrController.
                var accTypesToDeleteSelected = this.getRecTypesSelected(component, accsToDelete, accRecTypes);
                component.set("v.accTypesToDeleteSelected", accTypesToDeleteSelected);

                //Get record types of accounts that have multi-address support enabled. We need to call this method here because this
                //logic is called after the init method in STG_CMP_AddrController.
                var accTypesAddrSelected = this.getRecTypesSelected(component, accsMultiAddr, accRecTypes);
                component.set("v.accTypesAddrSelected", accTypesAddrSelected);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getAffiliationRolePicklistEntries : function(component, roleValue) {
        //Get all active affiliation role picklist entries
        var action = component.get("c.getPicklistActiveValuesMap");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Affiliation__c';
        var fieldName = prefix + 'Role__c';

        action.setParams({ "objectName" : objectName,"fieldName" : fieldName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var picklistValues = response.getReturnValue();
                var affiliationRolePicklistEntries = [];

                for(var property in picklistValues) {
                    if (picklistValues.hasOwnProperty(property)) {
                        affiliationRolePicklistEntries.push({picklistLabel: property, picklistValue : picklistValues[property]});

                        if(property.indexOf(roleValue) > -1) {
                            component.set("v.affiliationRoleMapLabel", property);
                        }
                    }
                }

                component.set("v.affiliationRolePicklistEntries", affiliationRolePicklistEntries);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getAffiliationStatusPicklistEntries : function(component, statusValue, deleteValue) {
        //Get all active affiliation status picklist entries
        var action = component.get("c.getPicklistActiveValuesMap");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Affiliation__c';
        var fieldName = prefix + 'Status__c';

        action.setParams({ "objectName" : objectName,"fieldName" : fieldName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var picklistValues = response.getReturnValue();
                var affiliationStatusPicklistEntries = [];

                for(var property in picklistValues) {

                    if (picklistValues.hasOwnProperty(property)) {
                        affiliationStatusPicklistEntries.push({picklistLabel: property, picklistValue: picklistValues[property]});

                        if(property.indexOf(statusValue) > -1) {
                            component.set("v.affiliationStatusMapLabel", property);
                        }

                        if(property.indexOf(deleteValue) > -1) {
                            component.set("v.affiliationStatusDeleteMapLabel", property);
                        }

                    }
                }

                component.set("v.affiliationStatusPicklistEntries", affiliationStatusPicklistEntries);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getCourseConnectionRecordTypes : function(component, studentTypeId, facultyTypeId) {
        //Get all available course connection record types
        var action = component.get("c.getRecTypesMapByName");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Course_Enrollment__c';
        action.setParams({ "objectName" : objectName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var recTypesObj = response.getReturnValue();
                var courseConnectionRecTypes = [];
                for(var property in recTypesObj) {
                    if (recTypesObj.hasOwnProperty(property)) {
                        courseConnectionRecTypes.push({name: property, id: recTypesObj[property]});
                        if(recTypesObj[property].indexOf(studentTypeId) > -1) {
                            component.set("v.studentRecTypeName", property);
                        }
                        if(recTypesObj[property].indexOf(facultyTypeId) > -1) {
                            component.set("v.facultyRecTypeName", property);
                        }
                    }
                }
                component.set("v.courseConnectionRecTypes", courseConnectionRecTypes);

            } else if(response.getState() === "ERROR") {
              this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    getFluencyPicklistEntries : function(component, fluencyValue) {
        //Get all active Contact Language Fluency picklist entries
        var action = component.get("c.getPicklistActiveValuesMap");
        var prefix = component.get("v.namespacePrefix");
        var objectName = prefix + 'Contact_Language__c';
        var fieldName = prefix + 'Fluency__c';

        action.setParams({ "objectName" : objectName,"fieldName" : fieldName});
        action.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                var picklistValues = response.getReturnValue();
                var fluencyPicklistEntries = [];

                for(var property in picklistValues) {
                    if (picklistValues.hasOwnProperty(property)) {
                        fluencyPicklistEntries.push({picklistLabel: property, picklistValue : picklistValues[property]});

                        if(property.indexOf(fluencyValue) > -1) {
                            component.set("v.defaultContactLanguageFluencyLabel", property);
                        }
                    }
                }

                component.set("v.fluencyPicklistEntries", fluencyPicklistEntries);

            } else if(response.getState() === "ERROR") {
                this.displayError(response);
            }
        });
        $A.enqueueAction(action);
    },

    //We want to compare the list of all available Account Record Types with the list of those that have been
    //marked as having enabled in the setting. The setting stores a semi-colon separated list of record type IDs.
    getRecTypesSelected : function(component, setting, recTypes) {
        var settingArray = this.getTokenized(setting);
        var recTypesSelected = [];
        for(var i = 0; i < recTypes.length; i += 1) {
            var recTypeSelected = {};
            recTypeSelected.name = recTypes[i].name;
            recTypeSelected.id = recTypes[i].id;
            recTypeSelected.selected = false; //we set it to false initially
            for(var j = 0; j < settingArray.length; j += 1) {
                if(recTypes[i].id === settingArray[j]) {
                    recTypeSelected.selected = true;
                }
            }
            recTypesSelected.push(recTypeSelected);
        }
        return recTypesSelected;
    },

    saveSettings : function(component) {
        var prefix = component.get("v.namespacePrefix");
        var saveAction = component.get("c.saveHierarchySettings");
        var hierarchySettings = this.addPrefixHierarchySettings(component.get("v.hierarchySettings"), prefix);
        saveAction.setParams({"hierarchySettings" : hierarchySettings});
        saveAction.setCallback(this, function(response) {
            if(response.getState() === "SUCCESS") {
                component.set("v.isView", true);
                var tst = component.find("successToast");
                $A.util.removeClass(tst, "slds-hide");
                $A.util.addClass(tst, "slds-show");

                //show manual toast
                window.setTimeout(
                    $A.getCallback(function() {
                        $A.util.removeClass(tst, "slds-show");
                        $A.util.addClass(tst, "slds-hide");
                    }), 3750
                );

            } else if(response.getState() === "ERROR") {
                component.set("v.isView", false);
                this.displayError(response);
            }
        });
        $A.enqueueAction(saveAction);
    },

    closeToast: function(component) {
        var tst = component.find("successToast");
        $A.util.removeClass(tst, "slds-show");
        $A.util.addClass(tst, "slds-hide");
    },

    resetSettings : function(component) {
        this.getHierarchySettings(component);
    },

    tabNavClick : function(component, event) {
        this.processTabs(component, event.getSource().getLocalId() );
    },

    processTabs : function(component, btnId) {
        // Since this method uses querySelector we can't use this method until the DOM is initialized.

        let tabNav = component.find('tabs').getElement().querySelector('ul.slds-tabs--default__nav');
        let contId =  btnId.replace('Btn', 'Content'); // content to show Id
        let tabId  =  btnId.replace('Btn', ''); // clicked tab
        let tabItem  = component.find(tabId);
        let contItem = component.find(contId);
        let matches = tabNav.querySelectorAll('li.slds-tabs__item');

        // Process all Tabs and content
        matches.forEach(function(element) {

            // Link Aura to DOM via GlobalId
            let selectedTab = element.dataset.auraRenderedBy == tabItem.getGlobalId() || false;

            // link this is the clicked element make active, otherwise remove the class
            element.classList.toggle('slds-active', selectedTab );

            // Process Content Tabs
            if( selectedTab ) {
                // Since this is the elected tab, we show that content
                $A.util.removeClass(contItem, "slds-hide");
                $A.util.addClass(contItem, "slds-show");
            } else {
                let tmpComp = component.find(element.getAttribute('id')+'Content');
                // Since we are in a loop we can hide all the other items except those we selected
                $A.util.removeClass(tmpComp, "slds-show");
                $A.util.addClass(tmpComp, "slds-hide");
            }

        });
    },

    getOtherDisplay : function(component, value) {
        var prefix = component.get("v.namespacePrefix");
        var label = '';
        label = $A.get("$Label.c.acctNamingOther");
        if (value === label) {
            return true;
        }else{
            return false;
        }
    }

})
<|endoftext|>


<commit_before>'use strict';

function Visibility() {

    // States.
    this.currently_visible = true;
    // If this variable is set to to 'true' then calls to 'display_all_attachments_recursively' will not affect this Visibility object.
    this.manual_visibility = false;

    this.is_visible = function() {
        return this.currently_visible;
    };

    this.set_to_visible = function() {
        this.currently_visible = true;
        // Thanks to : https://stackoverflow.com/questions/42609602/how-to-hide-and-show-an-object-on-scene-in-three-js
        this.object3D.visible = true;
        this.object3D.traverse (function(child) {
            if (child instanceof THREE.Mesh) {
                child.visible = true;
            }
        });
    };

    this.set_to_invisible = function() {
        this.currently_visible = false;
        // Thanks to : https://stackoverflow.com/questions/42609602/how-to-hide-and-show-an-object-on-scene-in-three-js
        this.object3D.visible = false;
        this.object3D.traverse (function(child) {
            if (child instanceof THREE.Mesh) {
                child.visible = false;
            }
        });
    };

    /*__   ___  __          __   ___  __          ___ ___       __              ___      ___  __
     |__) |__  /  \ |  | | |__) |__  /__`     /\   |   |   /\  /  ` |__|  |\/| |__  |\ |  |  /__`
     |  \ |___ \__X \__/ | |  \ |___ .__/    /~~\  |   |  /~~\ \__, |  |  |  | |___ | \|  |  .__/ */

    this.display_self_and_all_child_attachments_recursively = function() {
        this.set_to_visible();
        var all_attachments = this._get_all_attachments_recursively();
        for (var a = 0; a < all_attachments.length; a++) {
            if (!all_attachments[a].manual_visibility) {
                all_attachments[a].set_to_visible();
            }
        }
    };

    this.hide_self_and_all_child_attachments_recursively = function() {
        this.set_to_invisible();
        var all_attachments = this._get_all_attachments_recursively();
        for (var a = 0; a < all_attachments.length; a++) {
            if (!all_attachments[a].manual_visibility) {
                all_attachments[a].set_to_invisible();
            }
        }
    };

    this.display_all_child_attachments_with_name = function(n) {
        for (var a = 0; a < this.attachments.length; a++) {
            if (this.attachments[a].relative_name === n) {
                this.attachments[a].set_to_visible();
            }
        }
    };

    this.hide_all_child_attachments_with_name = function(n) {
        for (var a = 0; a < this.attachments.length; a++) {
            if (this.attachments[a].relative_name === n) {
                this.attachments[a].set_to_visible();
            }
        }
    };

}
<commit_msg>broad refactoring 75<commit_after>'use strict';

function Visibility() {

    // States.
    this.currently_visible = true;
    // If this variable is set to to 'true' then calls to 'display_all_attachments_recursively' will not affect this Visibility object.
    this.manual_visibility = false;

    this.is_visible = function() {
        return this.currently_visible;
    };

    this.set_to_visible = function() {
        this.currently_visible = true;
        // Thanks to : https://stackoverflow.com/questions/42609602/how-to-hide-and-show-an-object-on-scene-in-three-js
        this.object3D.visible = true;
        this.object3D.traverse (function(child) {
            if (child instanceof THREE.Mesh) {
                child.visible = true;
            }
        });
    };

    this.set_to_invisible = function() {
        this.currently_visible = false;
        // Thanks to : https://stackoverflow.com/questions/42609602/how-to-hide-and-show-an-object-on-scene-in-three-js
        this.object3D.visible = false;
        this.object3D.traverse (function(child) {
            if (child instanceof THREE.Mesh) {
                child.visible = false;
            }
        });
    };

    /*__   ___  __          __   ___  __          ___ ___       __              ___      ___  __
     |__) |__  /  \ |  | | |__) |__  /__`     /\   |   |   /\  /  ` |__|  |\/| |__  |\ |  |  /__`
     |  \ |___ \__X \__/ | |  \ |___ .__/    /~~\  |   |  /~~\ \__, |  |  |  | |___ | \|  |  .__/ */

    this.display_self_and_all_child_attachments_recursively = function() {
        this.set_to_visible();
        var all_attachments = this._get_all_attachments_recursively();
        for (var a = 0; a < all_attachments.length; a++) {
            if (!all_attachments[a].manual_visibility) {
                all_attachments[a].set_to_visible();
            }
        }
    };

    this.hide_self_and_all_child_attachments_recursively = function() {
        this.set_to_invisible();
        var all_attachments = this._get_all_attachments_recursively();
        for (var a = 0; a < all_attachments.length; a++) {
            if (!all_attachments[a].manual_visibility) {
                all_attachments[a].set_to_invisible();
            }
        }
    };

    this.display_all_child_attachments_with_name = function(n) {
        for (var a = 0; a < this.attachments.length; a++) {
            if (this.attachments[a].relative_name === n) {
                this.attachments[a].set_to_visible();
            }
        }
    };

    this.hide_all_child_attachments_with_name = function(n) {
        for (var a = 0; a < this.attachments.length; a++) {
            if (this.attachments[a].relative_name === n) {
                this.attachments[a].set_to_invisible();
            }
        }
    };

}
<|endoftext|>


<commit_before>var get = Ember.get, set = Ember.set;

var adapter, store, ajaxUrl, ajaxType, ajaxHash;
var Person, person, people;
var Role, role, roles;
var Group, group;
var Task, task;

module("Django Tastypie Adapter", {
  setup: function() {
    ajaxUrl = undefined;
    ajaxType = undefined;
    ajaxHash = undefined;

    adapter = DS.DjangoTastypieAdapter.create({
      ajax: function(url, type, hash) {
        var success = hash.success, self = this;

        ajaxUrl = this.getTastypieUrl(url);
        ajaxType = type;
        ajaxHash = hash;

        if (success) {
          hash.success = function(json, type) {
            if (!!type) {
              json = self._deurlifyData(type, json);
            }
            success.call(self, json);
          };
        }
      },

    });

    store = DS.Store.create({
      adapter: adapter,
      revision: 6
    });

    Person = DS.Model.extend({
      name: DS.attr('string')
    });

    Person.toString = function() {
      return "App.Person";
    };

    Group = DS.Model.extend({
      name: DS.attr('string'),
      people: DS.hasMany(Person)
    });

    Group.toString = function() {
      return "App.Group";
    };

    Role = DS.Model.extend({
      name: DS.attr('string'),
      primaryKey: '_id'
    });

    Role.toString = function() {
      return "App.Role";
    };

    Task = DS.Model.extend({
      name: DS.attr('string'),
      owner: DS.belongsTo(Person)
    });

    Task.toString = function() {
      return "App.Task";
    };
  },

  teardown: function() {
    adapter.destroy();
    store.destroy();

    if (person) { person.destroy(); }
  }
});

var expectUrl = function(url, desc) {
  equal(ajaxUrl, url, "the URL is " + desc);
};

var expectType = function(type) {
  equal(type, ajaxType, "the HTTP method is " + type);
};

var expectData = function(hash) {
  deepEqual(hash, ajaxHash.data, "the hash was passed along");
};

var expectState = function(state, value, p) {
  p = p || person;

  if (value === undefined) { value = true; }

  var flag = "is" + state.charAt(0).toUpperCase() + state.substr(1);
  equal(get(p, flag), value, "the person is " + (value === false ? "not " : "") + state);
};

var expectStates = function(state, value) {
  people.forEach(function(person) {
    expectState(state, value, person);
  });
};

test("creating a person makes a POST to /person, with the data hash", function() {
  set(adapter, 'bulkCommit', false);

  person = store.createRecord(Person, { name: "Tom Dale" });

  expectState('new');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/", "the collection is the same as the model name");
  expectType("POST");
  expectData(JSON.stringify({ name: "Tom Dale" }));

  ajaxHash.success({ id: 1, name: "Tom Dale" });
  expectState('saving', false);

  equal(person, store.find(Person, 1), "it is now possible to retrieve the person by the ID supplied");
});

test("updating a person makes a PUT to /people/:id with the data hash", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Yehuda Katz" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  set(person, 'name', "Brohuda Brokatz");

  expectState('dirty');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("PUT");

  ajaxHash.success({ id: 1, name: "Brohuda Brokatz" });
  expectState('saving', false);

  equal(person, store.find(Person, 1), "the same person is retrieved by the same ID");
  equal(get(person, 'name'), "Brohuda Brokatz", "the hash should be updated");
});

test("updates are not required to return data", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Yehuda Katz" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  set(person, 'name', "Brohuda Brokatz");

  expectState('dirty');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("PUT");

  ajaxHash.success();
  expectState('saving', false);

  equal(person, store.find(Person, 1), "the same person is retrieved by the same ID");
  equal(get(person, 'name'), "Brohuda Brokatz", "the data is preserved");
});

test("updating a record with custom primaryKey", function() {
  set(adapter, 'bulkCommit', false);
  store.load(Role, { _id: 1, name: "Developer" });

  role = store.find(Role, 1);

  set(role, 'name', "Manager");
  store.commit();

  expectUrl("api/v1/role/1/", "the plural of the model name with its ID");
  ajaxHash.success({ role: { _id: 1, name: "Manager" } });
});

test("deleting a person makes a DELETE to /people/:id", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Tom Dale" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  person.deleteRecord();

  expectState('dirty');
  expectState('deleted');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("DELETE");

  ajaxHash.success();
  expectState('deleted');
});

test("deleting a record with custom primaryKey", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Role, { _id: 1, name: "Developer" });

  role = store.find(Role, 1);

  role.deleteRecord();

  store.commit();

  expectUrl("api/v1/role/1/", "the plural of the model name with its ID");
  ajaxHash.success();
});

test("finding all people makes a GET to api/v1/person/", function() {
  people = store.find(Person);

  expectUrl("api/v1/person/", "the plural of the model name");

  expectType("GET");

  ajaxHash.success({"objects": [{ id: 1, name: "Yehuda Katz" }]});

  person = people.objectAt(0);

  expectState('loaded');
  expectState('dirty', false);

  equal(person, store.find(Person, 1), "the record is now in the store, and can be looked up by ID without another Ajax request");
});

test("finding a person by ID makes a GET to api/v1/person/:id", function() {
  person = store.find(Person, 1);

  expectState('loaded', false);
  expectUrl("api/v1/person/1/", "the plural of the model name with the ID requested");
  expectType("GET");

  ajaxHash.success({ id: 1, name: "Yehuda Katz" });

  expectState('loaded');
  expectState('dirty', false);

  equal(person, store.find(Person, 1), "the record is now in the store, and can be looked up by ID without another Ajax request");
});

test("finding many people by a list of IDs", function() {
  store.load(Group, { id: 1, people: [ 1, 2, 3 ] });

  var group = store.find(Group, 1);

  equal(ajaxUrl, undefined, "no Ajax calls have been made yet");

  var people = get(group, 'people');

  equal(get(people, 'length'), 3, "there are three people in the association already");

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), false, "the person is being loaded");
  });

  expectUrl("api/v1/person/set/1;2;3/");
  expectType("GET");

  ajaxHash.success({"objects":
    [
      { id: 1, name: "Rein Heinrichs" },
      { id: 2, name: "Tom Dale" },
      { id: 3, name: "Yehuda Katz" }
    ]}
  );

  var rein = people.objectAt(0);
  equal(get(rein, 'name'), "Rein Heinrichs");
  equal(get(rein, 'id'), 1);

  var tom = people.objectAt(1);
  equal(get(tom, 'name'), "Tom Dale");
  equal(get(tom, 'id'), 2);

  var yehuda = people.objectAt(2);
  equal(get(yehuda, 'name'), "Yehuda Katz");
  equal(get(yehuda, 'id'), 3);

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), true, "the person is being loaded");
  });
});

test("finding people by a query", function() {
  var people = store.find(Person, { page: 1 });

  equal(get(people, 'length'), 0, "there are no people yet, as the query has not returned");

  expectUrl("api/v1/person/", "the collection at the plural of the model name");
  expectType("GET");
  expectData({ page: 1 });

  ajaxHash.success({
    objects: [
      { id: 1, name: "Rein Heinrichs" },
      { id: 2, name: "Tom Dale" },
      { id: 3, name: "Yehuda Katz" }
    ]
  });

  equal(get(people, 'length'), 3, "the people are now loaded");

  var rein = people.objectAt(0);
  equal(get(rein, 'name'), "Rein Heinrichs");
  equal(get(rein, 'id'), 1);

  var tom = people.objectAt(1);
  equal(get(tom, 'name'), "Tom Dale");
  equal(get(tom, 'id'), 2);

  var yehuda = people.objectAt(2);
  equal(get(yehuda, 'name'), "Yehuda Katz");
  equal(get(yehuda, 'id'), 3);

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), true, "the person is being loaded");
  });
});

test("if you specify a server domain then it is prepended onto all URLs", function() {
  set(adapter, 'serverDomain', 'http://localhost:8000/');
  person = store.find(Person, 1);
  expectUrl("http://localhost:8000/api/v1/person/1/", "the namespace, followed by by the plural of the model name and the id")

  store.load(Person, { id: 1 });
});

test("creating an item with a belongsTo relationship urlifies the Resource URI (custom key)", function() {

  Task = DS.Model.extend({
    name: DS.attr('string'),
    owner: DS.belongsTo(Person, {key: 'owner'})
  });

  Task.toString = function() {
    return "App.Task";
  };

  store.load(Person, {id: 1, name: "Maurice Moss"});
  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  task = store.createRecord(Task, {id: 1, name: "Get a bike!", owner: person});

  expectState('new', true, task);
  store.commit();
  expectState('saving', true, task);

  expectUrl('api/v1/task/', 'create URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}));

  ajaxHash.success({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}, Task);

});

test("creating an item and adding hasMany relationships parses the Resource URI (custom key)", function() {

  Group = DS.Model.extend({
    name: DS.attr('string'),
    people: DS.hasMany(Person, {key: 'people'})
  });

  Group.toString = function() {
    return "App.Group";
  };

  store.load(Person, {id: 1, name: "Maurice Moss"});
  store.load(Person, {id: 2, name: "Roy"});

  var moss = store.find(Person, 1);
  var roy = store.find(Person, 2);

  group = store.createRecord(Group, {id: 1, name: "Team"});

  expectState('new', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/', 'create Group URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Team", people: [] }));

  ajaxHash.success({ id: 1, name: "Team", people: [] });

  group = store.find(Group, 1);

  group.get('people').pushObject(moss);
  group.get('people').pushObject(roy);

  // Many to many state must be manually changed
  expectState('dirty', false, group);
  group.get('stateManager').goToState('updated');
  expectState('dirty', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/1/', 'modify Group URL');
  expectType("PUT");
  expectData(JSON.stringify({ id: 1, name: "Team", people: ['/api/v1/person/1/', '/api/v1/person/2/'] }));
});

test("creating an item with a belongsTo relationship urlifies the Resource URI (default key)", function() {
  store.load(Person, {id: 1, name: "Maurice Moss"});
  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  task = store.createRecord(Task, {id: 1, name: "Get a bike!", owner: person});

  expectState('new', true, task);
  store.commit();
  expectState('saving', true, task);

  expectUrl('api/v1/task/', 'create URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Get a bike!", owner_id: "/api/v1/person/1/"}));

  ajaxHash.success({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}, Task);

});

test("creating an item and adding hasMany relationships parses the Resource URI (default key)", function() {

  store.load(Person, {id: 1, name: "Maurice Moss"});
  store.load(Person, {id: 2, name: "Roy"});

  var moss = store.find(Person, 1);
  var roy = store.find(Person, 2);

  group = store.createRecord(Group, {id: 1, name: "Team"});

  expectState('new', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/', 'create Group URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Team", people: [] }));

  ajaxHash.success({ id: 1, name: "Team", people: [] });

  group = store.find(Group, 1);

  group.get('people').pushObject(moss);
  group.get('people').pushObject(roy);

  // Many to many state must be manually changed
  expectState('dirty', false, group);
  group.get('stateManager').goToState('updated');
  expectState('dirty', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/1/', 'modify Group URL');
  expectType("PUT");
  expectData(JSON.stringify({ id: 1, name: "Team", people: ['/api/v1/person/1/', '/api/v1/person/2/'] }));
});
<commit_msg>Commenting tests also commentedd in RESTAdapter<commit_after>var get = Ember.get, set = Ember.set;

var adapter, store, ajaxUrl, ajaxType, ajaxHash;
var Person, person, people;
var Role, role, roles;
var Group, group;
var Task, task;

module("Django Tastypie Adapter", {
  setup: function() {
    ajaxUrl = undefined;
    ajaxType = undefined;
    ajaxHash = undefined;

    adapter = DS.DjangoTastypieAdapter.create({
      ajax: function(url, type, hash) {
        var success = hash.success, self = this;

        ajaxUrl = this.getTastypieUrl(url);
        ajaxType = type;
        ajaxHash = hash;

        if (success) {
          hash.success = function(json, type) {
            if (!!type) {
              json = self._deurlifyData(type, json);
            }
            success.call(self, json);
          };
        }
      },

    });

    store = DS.Store.create({
      adapter: adapter,
      revision: 6
    });

    Person = DS.Model.extend({
      name: DS.attr('string')
    });

    Person.toString = function() {
      return "App.Person";
    };

    Group = DS.Model.extend({
      name: DS.attr('string'),
      people: DS.hasMany(Person)
    });

    Group.toString = function() {
      return "App.Group";
    };

    Role = DS.Model.extend({
      name: DS.attr('string'),
      primaryKey: '_id'
    });

    Role.toString = function() {
      return "App.Role";
    };

    Task = DS.Model.extend({
      name: DS.attr('string'),
      owner: DS.belongsTo(Person)
    });

    Task.toString = function() {
      return "App.Task";
    };
  },

  teardown: function() {
    adapter.destroy();
    store.destroy();

    if (person) { person.destroy(); }
  }
});

var expectUrl = function(url, desc) {
  equal(ajaxUrl, url, "the URL is " + desc);
};

var expectType = function(type) {
  equal(type, ajaxType, "the HTTP method is " + type);
};

var expectData = function(hash) {
  deepEqual(hash, ajaxHash.data, "the hash was passed along");
};

var expectState = function(state, value, p) {
  p = p || person;

  if (value === undefined) { value = true; }

  var flag = "is" + state.charAt(0).toUpperCase() + state.substr(1);
  equal(get(p, flag), value, "the person is " + (value === false ? "not " : "") + state);
};

var expectStates = function(state, value) {
  people.forEach(function(person) {
    expectState(state, value, person);
  });
};

test("creating a person makes a POST to /person, with the data hash", function() {
  set(adapter, 'bulkCommit', false);

  person = store.createRecord(Person, { name: "Tom Dale" });

  expectState('new');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/", "the collection is the same as the model name");
  expectType("POST");
  expectData(JSON.stringify({ name: "Tom Dale" }));

  ajaxHash.success({ id: 1, name: "Tom Dale" });
  expectState('saving', false);

  equal(person, store.find(Person, 1), "it is now possible to retrieve the person by the ID supplied");
});

test("updating a person makes a PUT to /people/:id with the data hash", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Yehuda Katz" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  set(person, 'name', "Brohuda Brokatz");

  expectState('dirty');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("PUT");

  ajaxHash.success({ id: 1, name: "Brohuda Brokatz" });
  expectState('saving', false);

  equal(person, store.find(Person, 1), "the same person is retrieved by the same ID");
  equal(get(person, 'name'), "Brohuda Brokatz", "the hash should be updated");
});

test("updates are not required to return data", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Yehuda Katz" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  set(person, 'name', "Brohuda Brokatz");

  expectState('dirty');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("PUT");

  ajaxHash.success();
  expectState('saving', false);

  equal(person, store.find(Person, 1), "the same person is retrieved by the same ID");
  equal(get(person, 'name'), "Brohuda Brokatz", "the data is preserved");
});

/* COMMENTED IN EMBER DATA
test("updating a record with custom primaryKey", function() {debugger;
  set(adapter, 'bulkCommit', false);
  store.load(Role, { _id: 1, name: "Developer" });

  role = store.find(Role, 1);

  set(role, 'name', "Manager");
  store.commit();

  expectUrl("api/v1/role/1/", "the plural of the model name with its ID");
  ajaxHash.success({ role: { _id: 1, name: "Manager" } });
});*/

test("deleting a person makes a DELETE to /people/:id", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Person, { id: 1, name: "Tom Dale" });

  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  person.deleteRecord();

  expectState('dirty');
  expectState('deleted');
  store.commit();
  expectState('saving');

  expectUrl("api/v1/person/1/", "the plural of the model name with its ID");
  expectType("DELETE");

  ajaxHash.success();
  expectState('deleted');
});

/* COMMENTED IN EMBER DATA
test("deleting a record with custom primaryKey", function() {
  set(adapter, 'bulkCommit', false);

  store.load(Role, { _id: 1, name: "Developer" });

  role = store.find(Role, 1);

  role.deleteRecord();

  store.commit();

  expectUrl("api/v1/role/1/", "the plural of the model name with its ID");
  ajaxHash.success();
});*/

test("finding all people makes a GET to api/v1/person/", function() {
  people = store.find(Person);

  expectUrl("api/v1/person/", "the plural of the model name");

  expectType("GET");

  ajaxHash.success({"objects": [{ id: 1, name: "Yehuda Katz" }]});

  person = people.objectAt(0);

  expectState('loaded');
  expectState('dirty', false);

  equal(person, store.find(Person, 1), "the record is now in the store, and can be looked up by ID without another Ajax request");
});

test("finding a person by ID makes a GET to api/v1/person/:id", function() {
  person = store.find(Person, 1);

  expectState('loaded', false);
  expectUrl("api/v1/person/1/", "the plural of the model name with the ID requested");
  expectType("GET");

  ajaxHash.success({ id: 1, name: "Yehuda Katz" });

  expectState('loaded');
  expectState('dirty', false);

  equal(person, store.find(Person, 1), "the record is now in the store, and can be looked up by ID without another Ajax request");
});

test("finding many people by a list of IDs", function() {
  store.load(Group, { id: 1, people: [ 1, 2, 3 ] });

  var group = store.find(Group, 1);

  equal(ajaxUrl, undefined, "no Ajax calls have been made yet");

  var people = get(group, 'people');

  equal(get(people, 'length'), 3, "there are three people in the association already");

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), false, "the person is being loaded");
  });

  expectUrl("api/v1/person/set/1;2;3/");
  expectType("GET");

  ajaxHash.success({"objects":
    [
      { id: 1, name: "Rein Heinrichs" },
      { id: 2, name: "Tom Dale" },
      { id: 3, name: "Yehuda Katz" }
    ]}
  );

  var rein = people.objectAt(0);
  equal(get(rein, 'name'), "Rein Heinrichs");
  equal(get(rein, 'id'), 1);

  var tom = people.objectAt(1);
  equal(get(tom, 'name'), "Tom Dale");
  equal(get(tom, 'id'), 2);

  var yehuda = people.objectAt(2);
  equal(get(yehuda, 'name'), "Yehuda Katz");
  equal(get(yehuda, 'id'), 3);

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), true, "the person is being loaded");
  });
});

test("finding people by a query", function() {
  var people = store.find(Person, { page: 1 });

  equal(get(people, 'length'), 0, "there are no people yet, as the query has not returned");

  expectUrl("api/v1/person/", "the collection at the plural of the model name");
  expectType("GET");
  expectData({ page: 1 });

  ajaxHash.success({
    objects: [
      { id: 1, name: "Rein Heinrichs" },
      { id: 2, name: "Tom Dale" },
      { id: 3, name: "Yehuda Katz" }
    ]
  });

  equal(get(people, 'length'), 3, "the people are now loaded");

  var rein = people.objectAt(0);
  equal(get(rein, 'name'), "Rein Heinrichs");
  equal(get(rein, 'id'), 1);

  var tom = people.objectAt(1);
  equal(get(tom, 'name'), "Tom Dale");
  equal(get(tom, 'id'), 2);

  var yehuda = people.objectAt(2);
  equal(get(yehuda, 'name'), "Yehuda Katz");
  equal(get(yehuda, 'id'), 3);

  people.forEach(function(person) {
    equal(get(person, 'isLoaded'), true, "the person is being loaded");
  });
});

test("if you specify a server domain then it is prepended onto all URLs", function() {
  set(adapter, 'serverDomain', 'http://localhost:8000/');
  person = store.find(Person, 1);
  expectUrl("http://localhost:8000/api/v1/person/1/", "the namespace, followed by by the plural of the model name and the id")

  store.load(Person, { id: 1 });
});

test("creating an item with a belongsTo relationship urlifies the Resource URI (custom key)", function() {

  Task = DS.Model.extend({
    name: DS.attr('string'),
    owner: DS.belongsTo(Person, {key: 'owner'})
  });

  Task.toString = function() {
    return "App.Task";
  };

  store.load(Person, {id: 1, name: "Maurice Moss"});
  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  task = store.createRecord(Task, {id: 1, name: "Get a bike!", owner: person});

  expectState('new', true, task);
  store.commit();
  expectState('saving', true, task);

  expectUrl('api/v1/task/', 'create URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}));

  ajaxHash.success({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}, Task);

});

test("creating an item and adding hasMany relationships parses the Resource URI (custom key)", function() {

  Group = DS.Model.extend({
    name: DS.attr('string'),
    people: DS.hasMany(Person, {key: 'people'})
  });

  Group.toString = function() {
    return "App.Group";
  };

  store.load(Person, {id: 1, name: "Maurice Moss"});
  store.load(Person, {id: 2, name: "Roy"});

  var moss = store.find(Person, 1);
  var roy = store.find(Person, 2);

  group = store.createRecord(Group, {id: 1, name: "Team"});

  expectState('new', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/', 'create Group URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Team", people: [] }));

  ajaxHash.success({ id: 1, name: "Team", people: [] });

  group = store.find(Group, 1);

  group.get('people').pushObject(moss);
  group.get('people').pushObject(roy);

  // Many to many state must be manually changed
  expectState('dirty', false, group);
  group.get('stateManager').goToState('updated');
  expectState('dirty', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/1/', 'modify Group URL');
  expectType("PUT");
  expectData(JSON.stringify({ id: 1, name: "Team", people: ['/api/v1/person/1/', '/api/v1/person/2/'] }));
});

test("creating an item with a belongsTo relationship urlifies the Resource URI (default key)", function() {
  store.load(Person, {id: 1, name: "Maurice Moss"});
  person = store.find(Person, 1);

  expectState('new', false);
  expectState('loaded');
  expectState('dirty', false);

  task = store.createRecord(Task, {id: 1, name: "Get a bike!", owner: person});

  expectState('new', true, task);
  store.commit();
  expectState('saving', true, task);

  expectUrl('api/v1/task/', 'create URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Get a bike!", owner_id: "/api/v1/person/1/"}));

  ajaxHash.success({ id: 1, name: "Get a bike!", owner: "/api/v1/person/1/"}, Task);

});

test("creating an item and adding hasMany relationships parses the Resource URI (default key)", function() {

  store.load(Person, {id: 1, name: "Maurice Moss"});
  store.load(Person, {id: 2, name: "Roy"});

  var moss = store.find(Person, 1);
  var roy = store.find(Person, 2);

  group = store.createRecord(Group, {id: 1, name: "Team"});

  expectState('new', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/', 'create Group URL');
  expectType("POST");
  expectData(JSON.stringify({ id: 1, name: "Team", people: [] }));

  ajaxHash.success({ id: 1, name: "Team", people: [] });

  group = store.find(Group, 1);

  group.get('people').pushObject(moss);
  group.get('people').pushObject(roy);

  // Many to many state must be manually changed
  expectState('dirty', false, group);
  group.get('stateManager').goToState('updated');
  expectState('dirty', true, group);
  store.commit();
  expectState('saving', true, group);

  expectUrl('api/v1/group/1/', 'modify Group URL');
  expectType("PUT");
  expectData(JSON.stringify({ id: 1, name: "Team", people: ['/api/v1/person/1/', '/api/v1/person/2/'] }));
});
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

// ************************************************************************************************
// Shorcuts and Services

const Cc = Components.classes;
const Ci = Components.interfaces;

const traceService = Cc["@joehewitt.com/firebug-trace-service;1"].getService(Ci.nsIObserverService);
const hiddenWindow = Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci.nsIAppShellService).hiddenDOMWindow;

const PrefService = Cc["@mozilla.org/preferences-service;1"];
const prefs = PrefService.getService(Ci.nsIPrefBranch2);
const prefService = PrefService.getService(Ci.nsIPrefService);

var gFindBar;

const reDBG = /extensions\.([^\.]*)\.(DBG_.*)/;
const reDBG_FBS = /DBG_FBS_(.*)/;
const reEndings = /\r\n|\r|\n/;

// The lib.js isn't included in this window so, define the global here.
// It'll be initialized from window parameters (see initialize method).
var FBL;

// ************************************************************************************************
// Trace Window Implementation

var TraceConsole =
{
    modules: [],

    initialize: function()
    {
        var args = window.arguments[0];
        FBL = args.FBL;
        Firebug = args.Firebug;

        // Get pref domain is used for message filtering. Only logs that belong
        // to this pref-domain will be displayed.
        this.prefDomain = args.prefDomain;
        window.title = FBL.$STR("title.Tracing") + ": " + this.prefDomain;

        // Initialize root node of the trace-console window.
        var consoleFrame = document.getElementById("consoleFrame");
        this.consoleNode = consoleFrame.contentDocument.getElementById("panelNode-traceConsole");
        this.logs = Firebug.TraceModule.CommonBaseUI.initializeContent(this.consoleNode, this.prefDomain);

        // Register listeners and observers
        traceService.addObserver(this, "firebug-trace-on-message", false);

        gFindBar = document.getElementById("FindToolbar");

        // Notify listeners
        Firebug.TraceModule.onLoadConsole(window, this.consoleNode);
        this.registerModule(Firebug.TraceModule);

        // Make sure the UI is localized.
        this.internationalizeUI();
    },

    internationalizeUI: function()
    {
        var buttons = ["clearConsole", "findConsole", "separateConsole",
            "restartFirefox", "closeFirefox", "saveToFile"];

        for (var i=0; i<buttons.length; i++)
        {
            var element = document.getElementById(buttons[i]);
            FBL.internationalize(element, "label");
            FBL.internationalize(element, "tooltiptext");
        }
    },

    shutdown: function()
    {
        traceService.removeObserver(this, "firebug-trace-on-message");

        // Notify listeners
        for (var i=0; i<this.modules.length; ++i)
            this.modules[i].onUnloadConsole(window);
    },

    registerModule: function(traceModule)
    {
        this.modules.push(traceModule);
    },

    unregisterModule: function(module)
    {
        for (var i=0; i<this.modules.length; ++i) {
            if (this.modules[i] == module) {
                this.modules.splice(i, 1);
                break;
            }
        }
    },

    // nsIObserver
    observe: function(subject, topic, data)
    {
        if (topic == "firebug-trace-on-message")
        {
            // Display messages only with "firebug.extensions" type.
            var messageInfo = subject.wrappedJSObject;

            // If the message type isn't specified, use Firebug's pref domain as the default.
            if (!messageInfo.type)
                messageInfo.type = "extensions.firebug";

            if (messageInfo.type != this.prefDomain)
                return;

            this.dump(new Firebug.TraceModule.TraceMessage(
                messageInfo.type, data, messageInfo.obj, messageInfo.scope));

            return true;
        }
    },

    // Message dump
    dump: function(message)
    {
        // Notify listeners
        for (var i=0; i<this.modules.length; ++i)
            this.modules[i].onDump(message);

        Firebug.TraceModule.dump(message, this.logs.firstChild);
    },

    dumpSeparator: function()
    {
        Firebug.TraceModule.MessageTemplate.dumpSeparator(
            this.logs.firstChild);
    },

    // Trace console toolbar commands
    onClearConsole: function()
    {
        var tbody = this.logs.firstChild;
        while (tbody.firstChild)
            tbody.removeChild(tbody.lastChild);
    },

    onSeparateConsole: function()
    {
        Firebug.TraceModule.MessageTemplate.dumpSeparator(this.logs.firstChild);
    },

    onSaveToFile: function()
    {
        try
        {
            var nsIFilePicker = Ci.nsIFilePicker;
            var fp = Cc["@mozilla.org/filepicker;1"].getService(nsIFilePicker);
            fp.init(window, null, nsIFilePicker.modeSave);
            fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
            fp.filterIndex = 1;
            fp.defaultString = "firebug-tracing-logs.txt";

            var rv = fp.show();
            if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace)
            {
                var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
                    .createInstance(Ci.nsIFileOutputStream);
                foStream.init(fp.file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate

                var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
                var currLocale = Firebug.getPref("general.useragent", "locale");

                // Store head info.
                var head = "Firebug: " + Firebug.version + "\n" +
                    appInfo.name + ": " + appInfo.version + ", " +
                    appInfo.platformVersion + ", " +
                    appInfo.appBuildID + ", " + currLocale + "\n" +
                    "Export Date: " + (new Date()).toGMTString() +
                    "\n==========================================\n\n";
                foStream.write(head, head.length);

                // Iterate over all logs and store it into a file.
                var tbody = this.logs.firstChild;
                for (var row = tbody.firstChild; row; row = row.nextSibling)
                    this.saveMessage(row.repObject, foStream);

                foStream.close();
            }
        }
        catch (err)
        {
            alert(err.toString());
        }
    },

    saveMessage: function(message, stream)
    {
        var text = message.text;
        text = text ? text.replace(reEndings, "") : "---";
        if (message.type)
            text = "[" + message.type + "] " + text;
        text = (message.index + 1) + ". " + text + "\n"
        stream.write(text, text.length);
        this.saveStackTrace(message, stream);
    },

    saveStackTrace: function(message, stream)
    {
        var stack = message.stack;
        for (var i=0; stack && i<stack.length; i++) {
            var frame = stack[i];
            var text = "      " + frame.fileName + " (" + frame.lineNumber + ")\n";
            stream.write(text, text.length);
        }

        var end = "\n";
        stream.write(end, end.length);
    },

    onRestartFirefox: function()
    {
        Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).
            quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
    },

    onExitFirefox: function()
    {
        goQuitApplication();
    }
};

// ************************************************************************************************
<commit_msg>avoid deprecated window.title<commit_after>/* See license.txt for terms of usage */

// ************************************************************************************************
// Shorcuts and Services

const Cc = Components.classes;
const Ci = Components.interfaces;

const traceService = Cc["@joehewitt.com/firebug-trace-service;1"].getService(Ci.nsIObserverService);
const hiddenWindow = Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci.nsIAppShellService).hiddenDOMWindow;

const PrefService = Cc["@mozilla.org/preferences-service;1"];
const prefs = PrefService.getService(Ci.nsIPrefBranch2);
const prefService = PrefService.getService(Ci.nsIPrefService);

var gFindBar;

const reDBG = /extensions\.([^\.]*)\.(DBG_.*)/;
const reDBG_FBS = /DBG_FBS_(.*)/;
const reEndings = /\r\n|\r|\n/;

// The lib.js isn't included in this window so, define the global here.
// It'll be initialized from window parameters (see initialize method).
var FBL;

// ************************************************************************************************
// Trace Window Implementation

var TraceConsole =
{
    modules: [],

    initialize: function()
    {
        var args = window.arguments[0];
        FBL = args.FBL;
        Firebug = args.Firebug;

        // Get pref domain is used for message filtering. Only logs that belong
        // to this pref-domain will be displayed.
        this.prefDomain = args.prefDomain;
        document.title = FBL.$STR("title.Tracing") + ": " + this.prefDomain;

        // Initialize root node of the trace-console window.
        var consoleFrame = document.getElementById("consoleFrame");
        this.consoleNode = consoleFrame.contentDocument.getElementById("panelNode-traceConsole");
        this.logs = Firebug.TraceModule.CommonBaseUI.initializeContent(this.consoleNode, this.prefDomain);

        // Register listeners and observers
        traceService.addObserver(this, "firebug-trace-on-message", false);

        gFindBar = document.getElementById("FindToolbar");

        // Notify listeners
        Firebug.TraceModule.onLoadConsole(window, this.consoleNode);
        this.registerModule(Firebug.TraceModule);

        // Make sure the UI is localized.
        this.internationalizeUI();
    },

    internationalizeUI: function()
    {
        var buttons = ["clearConsole", "findConsole", "separateConsole",
            "restartFirefox", "closeFirefox", "saveToFile"];

        for (var i=0; i<buttons.length; i++)
        {
            var element = document.getElementById(buttons[i]);
            FBL.internationalize(element, "label");
            FBL.internationalize(element, "tooltiptext");
        }
    },

    shutdown: function()
    {
        traceService.removeObserver(this, "firebug-trace-on-message");

        // Notify listeners
        for (var i=0; i<this.modules.length; ++i)
            this.modules[i].onUnloadConsole(window);
    },

    registerModule: function(traceModule)
    {
        this.modules.push(traceModule);
    },

    unregisterModule: function(module)
    {
        for (var i=0; i<this.modules.length; ++i) {
            if (this.modules[i] == module) {
                this.modules.splice(i, 1);
                break;
            }
        }
    },

    // nsIObserver
    observe: function(subject, topic, data)
    {
        if (topic == "firebug-trace-on-message")
        {
            // Display messages only with "firebug.extensions" type.
            var messageInfo = subject.wrappedJSObject;

            // If the message type isn't specified, use Firebug's pref domain as the default.
            if (!messageInfo.type)
                messageInfo.type = "extensions.firebug";

            if (messageInfo.type != this.prefDomain)
                return;

            this.dump(new Firebug.TraceModule.TraceMessage(
                messageInfo.type, data, messageInfo.obj, messageInfo.scope));

            return true;
        }
    },

    // Message dump
    dump: function(message)
    {
        // Notify listeners
        for (var i=0; i<this.modules.length; ++i)
            this.modules[i].onDump(message);

        Firebug.TraceModule.dump(message, this.logs.firstChild);
    },

    dumpSeparator: function()
    {
        Firebug.TraceModule.MessageTemplate.dumpSeparator(
            this.logs.firstChild);
    },

    // Trace console toolbar commands
    onClearConsole: function()
    {
        var tbody = this.logs.firstChild;
        while (tbody.firstChild)
            tbody.removeChild(tbody.lastChild);
    },

    onSeparateConsole: function()
    {
        Firebug.TraceModule.MessageTemplate.dumpSeparator(this.logs.firstChild);
    },

    onSaveToFile: function()
    {
        try
        {
            var nsIFilePicker = Ci.nsIFilePicker;
            var fp = Cc["@mozilla.org/filepicker;1"].getService(nsIFilePicker);
            fp.init(window, null, nsIFilePicker.modeSave);
            fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
            fp.filterIndex = 1;
            fp.defaultString = "firebug-tracing-logs.txt";

            var rv = fp.show();
            if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace)
            {
                var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
                    .createInstance(Ci.nsIFileOutputStream);
                foStream.init(fp.file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate

                var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
                var currLocale = Firebug.getPref("general.useragent", "locale");

                // Store head info.
                var head = "Firebug: " + Firebug.version + "\n" +
                    appInfo.name + ": " + appInfo.version + ", " +
                    appInfo.platformVersion + ", " +
                    appInfo.appBuildID + ", " + currLocale + "\n" +
                    "Export Date: " + (new Date()).toGMTString() +
                    "\n==========================================\n\n";
                foStream.write(head, head.length);

                // Iterate over all logs and store it into a file.
                var tbody = this.logs.firstChild;
                for (var row = tbody.firstChild; row; row = row.nextSibling)
                    this.saveMessage(row.repObject, foStream);

                foStream.close();
            }
        }
        catch (err)
        {
            alert(err.toString());
        }
    },

    saveMessage: function(message, stream)
    {
        var text = message.text;
        text = text ? text.replace(reEndings, "") : "---";
        if (message.type)
            text = "[" + message.type + "] " + text;
        text = (message.index + 1) + ". " + text + "\n"
        stream.write(text, text.length);
        this.saveStackTrace(message, stream);
    },

    saveStackTrace: function(message, stream)
    {
        var stack = message.stack;
        for (var i=0; stack && i<stack.length; i++) {
            var frame = stack[i];
            var text = "      " + frame.fileName + " (" + frame.lineNumber + ")\n";
            stream.write(text, text.length);
        }

        var end = "\n";
        stream.write(end, end.length);
    },

    onRestartFirefox: function()
    {
        Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).
            quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
    },

    onExitFirefox: function()
    {
        goQuitApplication();
    }
};

// ************************************************************************************************
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 by CoNarrative
 */
/**
 * @class glu.List
 * An observable list of values or objects as a much lighter alternative to a store
 * The objects / values are not processed in any way (i.e. are not converted into Records or Models)
 * Notifications are raised when the list itself is manipulated.
 *
 */
glu.List = glu.extend(Object, {
    constructor:function (config) {
        config = config || {};
        this.autoParent = false;
        this.autoDetach = false;
        glu.deepApply(this, config);
        this.length = 0;
        this._private = this._private || {};
        this._private.objs = [];
        new glu.GraphObservable({vm:this});
        config.items = config.items || config.data || [];
        for (var i = 0; i < config.items.length; i++) {
            var item = config.items[i];
            this.add(item, true);
        }
        delete this.items;
    },
    /**
     * Adds an item to the list
     * @param obj
     * @param silent
     */
    add:function (obj, silent, isTransfer) {
        this.insert(this.length,obj, isTransfer);
    },
    /**
     * Inserts an item at an ordinal position
     * @param index
     * @param obj
     */
    insert:function (index, obj, isTransfer) {
        if (this.autoParent && obj.parentVM && obj.parentVM!==this.parentVM) {
            throw "View model already has a parent and needs to be removed from there first";
        }
        if (glu.isObject(obj) && obj.mtype ) {
            if (obj._private===undefined) {
                obj.ns = obj.ns || this.ns;
                if (this.autoParent) {
                    obj.parentVM = this.parentVM;
                    obj.parentList = this;
                }
                obj = glu.model(obj);
            }
            if (this.autoParent) {
                obj.parentList = this;
                obj._ob.attach('parentVM');
            }
            obj._ob.attachAll(); //adding to a list always reattaches an otherwise detached object
        }
        this._private.objs.splice(index, 0, obj);
        this.length++;
        this.fireEvent('lengthchanged',this.length,this.length-1);
        this.fireEvent('added', obj, index, isTransfer);
    },
    /**
     * Removes an item by reference
     * @param Obj
     * @return {*}
     */
    remove:function (Obj, isTransfer) {
        return this.removeAt(this.indexOf(Obj), isTransfer);
    },
    /**
     * Removes an item by ordinal position
     * @param index
     * @return {*}
     */
    removeAt:function (index, isTransfer) {
        var obj = this.getAt(index);
        if (obj==null) return; //nothing to do
        this._private.objs.splice(index, 1);
        this.length--;
        if (obj._ob) {
            //remove from observation graph...since it can only go child-> parent don't worry about other direction
            if (this.autoParent) {
                obj._ob.detach('parentVM');
                obj._ob.detach('rootVM');
            }
            if (this.autoDetach) {
                obj._ob.detachAll()
            }
        }
        this.fireEvent('removed', obj, index, isTransfer);
        if (index < this.activeIndex) {
            this.setActiveIndex(this.getActiveIndex() - 1);
        }
        this.fireEvent('lengthchanged',this.length,this.length+1);
        return obj;
    },
    /**
     * Removes all items
     */
    removeAll:function () {
        this.fireEvent('removedall', this);
        while (this.length > 0) {
            this.removeAt(0);
        }
    },

    /**
     * Transfers an item from another list to this one.
     * This establishes a "contract" by which we know the item never really disappears. The binder can use this
     * to re-use view components where appropriate.
     *
     * @param obj
     * @return {Number}
     */
    transferFrom:function(otherList, item, newIndex){
        if (newIndex==null) newIndex = this.length;
        otherList.remove(item, true);
        this.insert(newIndex, item, true);
        this.fireEvent('transferred', otherList, item, newIndex );
    },

    /**
     * Returns the ordinal index of an item
     * @param obj
     * @return {Number}
     */
    indexOf:function (obj) {
        if (this._private.objs.indexOf) return this._private.objs.indexOf(obj); //native indexOf
        for (var i = 0; i < this._private.objs.length; i++) {
            if (obj === this._private.objs[i]) {
                return i;
            }
        }
        return -1;
    },

    /**
     * Whether or not the supplied item is in the container
     * @param Obj
     * @return {Boolean}
     */
    contains:function (Obj) {
        return this.indexOf(Obj) > -1;
    },
    /**
     * Fetches the item at a given ordinal position
     * @param index
     * @return {*}
     */
    getAt:function (index) {
        return this._private.objs[index];
    },
    /**
     * The total number of items in the container
     * @property {Number}
     */
    length : 0,
    /**
     * An alias for length()
     * @return {Number}
     */
    getCount:function () {
        return this._private.objs.length;
    },
    /**
     * Iterates through each item in the list and applies the function
     * @param operation
     * @param scope
     */
    foreach:function (operation, scope) {
        for (var i = 0; i < this.length; i++) {
            var item = this.getAt(i);
            var myScope = scope || item;
            operation.call(myScope, item, i);
        }
    },

    /**
     * Returns a single item using a custom finder
     * @param fn
     * @param scope
     * @return {*}
     */
    find:function (fn, scope) {
        for (var i = 0; i < this.length; i++) {
            var item = this.getAt(i);
            var myScope = scope || item;
            if (fn.call(myScope, item)) {
                return item;
            }
        }
    },

    on:function (eventName, handler, scope) {
        scope = scope || this;
        this._ob.on(eventName, handler, scope);
    },

    toArray:function(){
        return this._private.objs.slice();
    },
    fireEvent:function () {
        glu.log.debug('List "' + this.referenceName + '" is firing event "' + arguments[0] + '""');
        this._ob.fireEvent.apply(this._ob, arguments);
    }
});

glu.mreg('list', glu.List);

glu.mreg('keytracking',{
    initMixin:function(){
        this.keyMap ={};
        this.idProperty = this.idProperty || 'id';
        //add initial keys since this is after constructor...
        for (var i=0;i<this._private.objs.length;i++){
            this.addKey(this._private.objs[i]);
        }
        this.on('added',this.addKey)
        this.on('removed',this.removeKey)
    },
    addKey:function(item, idx){
        var key=item[this.idProperty];
        if (this.keyMap[key]) throw new Error('Duplicate key "' + key +'" not allowed in a key-tracked list');
        if (key===undefined) return;
        this.keyMap[key] = item;
    },
    removeKey:function(item){
        var key=item[this.idProperty];
        if (key===undefined) return;
        delete this.keyMap[key];
    },
    containsKey:function(key){
        return this.keyMap[key]!==undefined;
    },
    getById:function(key){
        return this.keyMap[key];
    },
    removeAtKey:function(key){
        var item = this.keyMap[key];
        if (item==null) return;
        this.remove(item);
    }
})

glu.List.prototype.forEach = glu.List.prototype.foreach;
glu.List.prototype.where = function(filter) {
    var f = [];
    for (var i = 0; i < this.length; i++) {
        var item = this.getAt(i);
        if (filter.call(this.parentVM, item)) f.push(item);
    }
    return f;
}

glu.List.prototype.count = function(filter) {
    return this.where(filter).length;
}

glu.List.prototype.any = function(filter) {
    return this.where(filter).length > 0;
}
<commit_msg>Added new method .indexOfKey (and made alias .getAtKey for existing .getById to keep naming consistent)<commit_after>/*
 * Copyright (C) 2012 by CoNarrative
 */
/**
 * @class glu.List
 * An observable list of values or objects as a much lighter alternative to a store
 * The objects / values are not processed in any way (i.e. are not converted into Records or Models)
 * Notifications are raised when the list itself is manipulated.
 *
 */
glu.List = glu.extend(Object, {
    constructor:function (config) {
        config = config || {};
        this.autoParent = false;
        this.autoDetach = false;
        glu.deepApply(this, config);
        this.length = 0;
        this._private = this._private || {};
        this._private.objs = [];
        new glu.GraphObservable({vm:this});
        config.items = config.items || config.data || [];
        for (var i = 0; i < config.items.length; i++) {
            var item = config.items[i];
            this.add(item, true);
        }
        delete this.items;
    },
    /**
     * Adds an item to the list
     * @param obj
     * @param silent
     */
    add:function (obj, silent, isTransfer) {
        this.insert(this.length,obj, isTransfer);
    },
    /**
     * Inserts an item at an ordinal position
     * @param index
     * @param obj
     */
    insert:function (index, obj, isTransfer) {
        if (this.autoParent && obj.parentVM && obj.parentVM!==this.parentVM) {
            throw "View model already has a parent and needs to be removed from there first";
        }
        if (glu.isObject(obj) && obj.mtype ) {
            if (obj._private===undefined) {
                obj.ns = obj.ns || this.ns;
                if (this.autoParent) {
                    obj.parentVM = this.parentVM;
                    obj.parentList = this;
                }
                obj = glu.model(obj);
            }
            if (this.autoParent) {
                obj.parentList = this;
                obj._ob.attach('parentVM');
            }
            obj._ob.attachAll(); //adding to a list always reattaches an otherwise detached object
        }
        this._private.objs.splice(index, 0, obj);
        this.length++;
        this.fireEvent('lengthchanged',this.length,this.length-1);
        this.fireEvent('added', obj, index, isTransfer);
    },
    /**
     * Removes an item by reference
     * @param Obj
     * @return {*}
     */
    remove:function (Obj, isTransfer) {
        return this.removeAt(this.indexOf(Obj), isTransfer);
    },
    /**
     * Removes an item by ordinal position
     * @param index
     * @return {*}
     */
    removeAt:function (index, isTransfer) {
        var obj = this.getAt(index);
        if (obj==null) return; //nothing to do
        this._private.objs.splice(index, 1);
        this.length--;
        if (obj._ob) {
            //remove from observation graph...since it can only go child-> parent don't worry about other direction
            if (this.autoParent) {
                obj._ob.detach('parentVM');
                obj._ob.detach('rootVM');
            }
            if (this.autoDetach) {
                obj._ob.detachAll()
            }
        }
        this.fireEvent('removed', obj, index, isTransfer);
        if (index < this.activeIndex) {
            this.setActiveIndex(this.getActiveIndex() - 1);
        }
        this.fireEvent('lengthchanged',this.length,this.length+1);
        return obj;
    },
    /**
     * Removes all items
     */
    removeAll:function () {
        this.fireEvent('removedall', this);
        while (this.length > 0) {
            this.removeAt(0);
        }
    },

    /**
     * Transfers an item from another list to this one.
     * This establishes a "contract" by which we know the item never really disappears. The binder can use this
     * to re-use view components where appropriate.
     *
     * @param obj
     * @return {Number}
     */
    transferFrom:function(otherList, item, newIndex){
        if (newIndex==null) newIndex = this.length;
        otherList.remove(item, true);
        this.insert(newIndex, item, true);
        this.fireEvent('transferred', otherList, item, newIndex );
    },

    /**
     * Returns the ordinal index of an item
     * @param obj
     * @return {Number}
     */
    indexOf:function (obj) {
        if (this._private.objs.indexOf) return this._private.objs.indexOf(obj); //native indexOf
        for (var i = 0; i < this._private.objs.length; i++) {
            if (obj === this._private.objs[i]) {
                return i;
            }
        }
        return -1;
    },

    /**
     * Whether or not the supplied item is in the container
     * @param Obj
     * @return {Boolean}
     */
    contains:function (Obj) {
        return this.indexOf(Obj) > -1;
    },
    /**
     * Fetches the item at a given ordinal position
     * @param index
     * @return {*}
     */
    getAt:function (index) {
        return this._private.objs[index];
    },
    /**
     * The total number of items in the container
     * @property {Number}
     */
    length : 0,
    /**
     * An alias for length()
     * @return {Number}
     */
    getCount:function () {
        return this._private.objs.length;
    },
    /**
     * Iterates through each item in the list and applies the function
     * @param operation
     * @param scope
     */
    foreach:function (operation, scope) {
        for (var i = 0; i < this.length; i++) {
            var item = this.getAt(i);
            var myScope = scope || item;
            operation.call(myScope, item, i);
        }
    },

    /**
     * Returns a single item using a custom finder
     * @param fn
     * @param scope
     * @return {*}
     */
    find:function (fn, scope) {
        for (var i = 0; i < this.length; i++) {
            var item = this.getAt(i);
            var myScope = scope || item;
            if (fn.call(myScope, item)) {
                return item;
            }
        }
    },

    on:function (eventName, handler, scope) {
        scope = scope || this;
        this._ob.on(eventName, handler, scope);
    },

    toArray:function(){
        return this._private.objs.slice();
    },
    fireEvent:function () {
        glu.log.debug('List "' + this.referenceName + '" is firing event "' + arguments[0] + '""');
        this._ob.fireEvent.apply(this._ob, arguments);
    }
});

glu.mreg('list', glu.List);

glu.mreg('keytracking',{
    initMixin:function(){
        this.keyMap ={};
        this.idProperty = this.idProperty || 'id';
        //add initial keys since this is after constructor...
        for (var i=0;i<this._private.objs.length;i++){
            this.addKey(this._private.objs[i]);
        }
        this.on('added',this.addKey)
        this.on('removed',this.removeKey)
    },
    addKey:function(item, idx){
        var key=item[this.idProperty];
        if (this.keyMap[key]) throw new Error('Duplicate key "' + key +'" not allowed in a key-tracked list');
        if (key===undefined) return;
        this.keyMap[key] = item;
    },
    removeKey:function(item){
        var key=item[this.idProperty];
        if (key===undefined) return;
        delete this.keyMap[key];
    },
    containsKey:function(key){
        return this.keyMap[key]!==undefined;
    },
    getById:function(key){
        return this.keyMap[key];
    },
    getAtKey:function(key){
        return this.keyMap[key];
    },
    indexOfKey:function(key){
        return this.indexOf(this.getAtKey(key));
    },
    removeAtKey:function(key){
        var item = this.keyMap[key];
        if (item==null) return;
        this.remove(item);
    }
})

glu.List.prototype.forEach = glu.List.prototype.foreach;
glu.List.prototype.where = function(filter) {
    var f = [];
    for (var i = 0; i < this.length; i++) {
        var item = this.getAt(i);
        if (filter.call(this.parentVM, item)) f.push(item);
    }
    return f;
}

glu.List.prototype.count = function(filter) {
    return this.where(filter).length;
}

glu.List.prototype.any = function(filter) {
    return this.where(filter).length > 0;
}
<|endoftext|>