Skip to content

Instantly share code, notes, and snippets.

@jeremybatesDC
Last active May 21, 2019 16:22
Show Gist options
  • Save jeremybatesDC/a85506d240b6e7e97d9ae89310cf5808 to your computer and use it in GitHub Desktop.
Save jeremybatesDC/a85506d240b6e7e97d9ae89310cf5808 to your computer and use it in GitHub Desktop.
custom e-commerce D3 map
//must stick to ES5
;(function iftMapFunction(){
"use strict";
//for in loop
function UTILITY_clearThisObject(objectToEnumerate){
for(var thisPropName in objectToEnumerate) {
objectToEnumerate[thisPropName] = '';
}
}
//moving singular values here allows key/value pairs of mapStatusContainer to all be of the same shape (max 8);
var singularViewOnlyStatusContainer = {
currentStateCode: ''
,currentStateName: ''
}
var userAlreadySavedSections = {
userHomeSectionProductID: null
,additionalAlreadySavedSections: []
,additionalComponentSavedSections: []
}
function MapStatusContainerDeepARRAY_CONSTRUCTOR(currentProductId, currentProductCode, currentProductName, currentComponentProductId, currentComponentProductCode, currentComponentProductShortName, currentMemberPrice, currentPostalCodeRange, currentComponentParentProduct){
this.currentProductId = currentProductId;
this.currentProductCode = currentProductCode;
this.currentProductName = currentProductName;
this.currentComponentProductId = currentComponentProductId;
this.currentComponentProductCode = currentComponentProductCode;
this.currentComponentProductShortName = currentComponentProductShortName;
this.currentMemberPrice = currentMemberPrice;
this.currentPostalCodeRange = currentPostalCodeRange;
this.currentComponentParentProduct = currentComponentParentProduct;
}
//MAX 8
var mapStatusContainerDeepARRAY = [];
function constructFreshMapStatusContainerModel(){
for(var i = 0; i < 8; i++){
var thisConstructedThing = new MapStatusContainerDeepARRAY_CONSTRUCTOR(null, null, null, null, null, null, null, null);
mapStatusContainerDeepARRAY.push(thisConstructedThing);
}
}
//doesNotNeedToBeGlobal,but itS more readable if the clear function is visually next to the model
function safeManualResetOfmapStatusContainerDeepARRAY(){
mapStatusContainerDeepARRAY = [];
constructFreshMapStatusContainerModel();
}
//hidden or not handled by iterator elsewhere -- but could create a model for it
// function PanelDisplayStatusARRAY_CONSTRUCTOR(hiddenOrNot, disabledOrNot, isComponentOrNot){}
function OutputStatusContainerDeepARRAY_CONSTRUCTOR(ProductId, ProductName, ComponentProductId, ComponentProductShortName, MemberPrice){
this.ProductId = ProductId;
this.ProductName = ProductName;
this.ComponentProductId = ComponentProductId;
this.ComponentProductShortName = ComponentProductShortName;
this.MemberPrice = MemberPrice;
}
//max 8
var deepOutputObjectForStaging = [];
function constructFreshStagingContainerModel(){
for(var i = 0; i < 8; i++){
var thisConstructedThing = new OutputStatusContainerDeepARRAY_CONSTRUCTOR(null, null, null, null, null);
deepOutputObjectForStaging.push(thisConstructedThing);
}
}
function OutputStatusContainerDeepARRAY_CONSTRUCTOR__COMPONENTS(ProductId, ProductName, ComponentProductId, ComponentProductShortName, MemberPrice){
this.ProductId = ProductId;
this.ProductName = ProductName;
this.ComponentProductId = ComponentProductId;
this.ComponentProductShortName = ComponentProductShortName;
this.MemberPrice = MemberPrice;
}
var deepOutputObjectForStagingCOMPONENTS = [];
function constructFreshStagingContainerModelCOMPONENTS(){
for(var i = 0; i < 8; i++){
var thisConstructedThing = new OutputStatusContainerDeepARRAY_CONSTRUCTOR__COMPONENTS(null, null, null, null, null);
deepOutputObjectForStagingCOMPONENTS.push(thisConstructedThing);
}
}
//doesNotNeedToBeGlobal,but itS more readable if the clear function is visually next to the model
function safeManualResetOfOutputStatusContainerDeepARRAY(){
deepOutputObjectForStaging = [];
deepOutputObjectForStagingCOMPONENTS = [];
constructFreshStagingContainerModel();
constructFreshStagingContainerModelCOMPONENTS();
}
//the staging container is a bit different because itS order matters and must be preserved
function setUserPreselections(){
//sets property userAlreadySavedSections.userHomeSectionProductID
//reference to span to check for home section
var hiddenInputToCheckForHomeSections = document.getElementById('IFTHomeSectionProductId');
//global asterisk selector in case this is prefixed or suffexed in some way
var nodeListOfOptionalSectionsInputs = document.querySelectorAll('input[id*="MembershipJoinSection_SectionRepeater"]');
var nodeListOfComponentProductsAlreadySelected = document.querySelectorAll('[id$="IFTSectionProductIdComponent"');
//ctl00_MainContent_ctl00_MembershipJoinSection_SectionRepeater_ctl00_HiddenFieldComponentProductId
var componentSectionHiddenInput = document.getElementById('ctl00_MainContent_ctl00_MembershipJoinSection_componentRepeater_ctl00_IFTSectionProductIdComponent');
if(hiddenInputToCheckForHomeSections !== null && hiddenInputToCheckForHomeSections.value !== null){
userAlreadySavedSections.userHomeSectionProductID = parseInt(hiddenInputToCheckForHomeSections.value);
}
if(nodeListOfOptionalSectionsInputs !== null){
for(var i = 0; i < nodeListOfOptionalSectionsInputs.length; i++){
var valueOfInput = parseInt(nodeListOfOptionalSectionsInputs[i].value);
//data has some stray 0s
if (valueOfInput !== 0){
userAlreadySavedSections.additionalAlreadySavedSections.push(valueOfInput);
}
}
//console.log(userAlreadySavedSections.additionalAlreadySavedSections);
(function getDataQuirkValues(){
var theCompProdCodeToMatch;
var theRawSectionItemBelongingToHomeUserSelection = rawSectionData.SectionItems.filter(function(thisRawSectionItem){
return thisRawSectionItem.ProductId === userAlreadySavedSections.userHomeSectionProductID;
});
theRawSectionItemBelongingToHomeUserSelection.map(function(thisRawSect){
theCompProdCodeToMatch = thisRawSect.ProductCode + 'C';
//console.log('heyYo' + thisRawSect.ProductCode);
//console.log(thisRawSect);
});
var theRawSectionItemsBelongingToQuirkyOnPageValues = rawSectionData.SectionItems.filter(function(thisRawSectionItem){
return thisRawSectionItem.ComponentProductCode === theCompProdCodeToMatch;
});
//console.log(theRawSectionItemsBelongingToQuirkyOnPageValues);
theRawSectionItemsBelongingToQuirkyOnPageValues.map(function(thisRawSectItm){
userAlreadySavedSections.additionalComponentSavedSections.push(thisRawSectItm.ProductId);
});
})();
for(var zzTop = 0; zzTop < userAlreadySavedSections.additionalAlreadySavedSections.length; zzTop++){
var prodCodePlusC;
var theRawSectionItemBelongingToThisPageProvidedValues = rawSectionData.SectionItems.filter(function(thisRawSectionItem){
return thisRawSectionItem.ComponentProductId === userAlreadySavedSections.additionalAlreadySavedSections[zzTop];
});
theRawSectionItemBelongingToThisPageProvidedValues.map(function(x){
//console.log(x);
prodCodePlusC = x.ProductCode + 'C';
});
var theRawSectionItemsOfAssociatedComponentProducts = rawSectionData.SectionItems.filter(function(thisRwSctItm){
return thisRwSctItm.ComponentProductCode === prodCodePlusC
});
theRawSectionItemsOfAssociatedComponentProducts.map(function(thisAssociatedComponentProduct){
//console.log(thisAssociatedComponentProduct);
userAlreadySavedSections.additionalComponentSavedSections.push(thisAssociatedComponentProduct.ComponentProductId);
});
}
}
//console.log(userAlreadySavedSections.additionalComponentSavedSections);
if(nodeListOfComponentProductsAlreadySelected !== null){
for(var ii = 0; ii < nodeListOfComponentProductsAlreadySelected.length; ii++){
userAlreadySavedSections.additionalAlreadySavedSections.push(parseInt(nodeListOfComponentProductsAlreadySelected[ii].value));
}
}
}
//these keys can be used later to filter mapStatusContainer at queryTime
var fieldsRequiredByPanelView = {
currentProductName: ''
,currentMemberPrice: ''
,currentComponentProductShortName: ''
,currentPostalCodeRange: ''
}
function iftMapFunctionInit(){
//construct models
constructFreshMapStatusContainerModel();
constructFreshStagingContainerModel();
constructFreshStagingContainerModelCOMPONENTS();
setUserPreselections();
//donT put text value here because it might be null and i donT want any logic in this variable declaration area.
//get reference to outermost wrapper to show/hide with modal
var iftMapWrapperOuter = document.getElementById('iftMapWrapperOuter');
var iftMapButtonOpen = document.getElementById('iftMapButtonOpen');
var iftMapButtonClose = document.getElementById('iftMapButtonCloseWrapper');
var iftMapButtonCancel = document.getElementById('iftMapButtonCancel');
var seletedStateDisplay = document.getElementById('seletedStateDisplay');
var stateSelectMenu = document.getElementById('stateSelectMenu');
var internationalSelectMenu = document.getElementById('internationalSelectMenu');
var arrayOfSpansToPopulateEmpty = Array.prototype.slice.call(document.querySelectorAll('.iftMap__sectionData__wrapper span'));
var hiddenInputForBackend = document.getElementById('IFTSavedSectionHiddenfield');
var hiddenInputForBackendCOMPONENTS = document.getElementById('ctl00_MainContent_ctl00_MembershipJoinSection_IFTSavedSectionHiddenfieldCOMPONENTS');
var activeStateString = 'iftMapWrapperOuter--ACTIVE-STATE';
var disabledStateString = 'iftMap__sectionData__wrapper--DISABLED-STATE';
var hiddenStateString = 'iftMap__sectionData__wrapper--HIDDEN-STATE';
//already have a reference, but itS more general for etch-a-sketch reasons
var nodeListOfPanelsToPopulate = document.querySelectorAll('.iftMap__sectionData__wrapper');
var arrayOfPanelsToPopulate = Array.prototype.slice.call(nodeListOfPanelsToPopulate);
var arrayOfArrayOfFieldsToPopulate = [];
var nodeListOfCheckboxes = document.querySelectorAll('.iftMap__sectionData__wrapper [type="checkbox"]');
var arrayOfCheckboxes = Array.prototype.slice.call(nodeListOfCheckboxes);
//IMPORTANT. CREATING SET OF EMPTY SPANS FOR EACH PANEL
arrayOfPanelsToPopulate.map(function(thisPanel){
var arrayOfSpans = Array.prototype.slice.call(thisPanel.querySelectorAll('span'));
arrayOfArrayOfFieldsToPopulate.push(arrayOfSpans);
});
//DRAW THE MAP
var svg = d3.select('#iftMap');
var path = d3.geoPath();
//d3.json('javascripts/data/topoJSONusCustom.json', function(error, data) {
d3.json('../Scripts/data/topoJSONusCustom.json', function(error, data) {
if (error) throw error;
svg.append('g')
.attr('class', 'states iftMap__svg__g')
.selectAll('path')
.data(topojson.feature(data, data.objects.states).features)
.enter()
.append('path')
.attr('id', function(thisState){
return thisState.id
})
.attr('class', 'usState iftMap__svg__path')
.attr('d', path)
.on('click', function(thisState){
mapHandlerFunction('click', thisState, 'isFromMap');
});
svg.append('path')
.attr('class', 'state-borders iftMap__svg__path--stateBorders')
.attr('d', path(topojson.mesh(data, data.objects.states, function(a, b) { return a !== b; })));
});
//END DRAW MAP
function mapHandlerFunction(event, statefromD3, isFromMap){
//if a state on the map has been clicked
if(isFromMap) {
singularViewOnlyStatusContainer.currentStateCode = statefromD3.id;
singularViewOnlyStatusContainer.currentStateName = statefromD3.properties.stateName;
removeAddActiveState('thenAdd');
stateSelectMenu.value = singularViewOnlyStatusContainer.currentStateCode;
}
//if a dropdown item has been selected (select menu visible only on mobile)
else if(event.currentTarget.id === 'stateSelectMenu') {
singularViewOnlyStatusContainer.currentStateCode = stateSelectMenu.options[stateSelectMenu.selectedIndex].value;
singularViewOnlyStatusContainer.currentStateName = stateSelectMenu.options[stateSelectMenu.selectedIndex].text;
removeAddActiveState('thenAdd');
}
//if an international item has been selected
else if(event.currentTarget.id === 'internationalSelectMenu'){
singularViewOnlyStatusContainer.currentStateCode = internationalSelectMenu.options[internationalSelectMenu.selectedIndex].value;
singularViewOnlyStatusContainer.currentStateName = internationalSelectMenu.options[internationalSelectMenu.selectedIndex].text;
//clear dropdown list since not usState
stateSelectMenu.value = '';
removeAddActiveState();
clearCheckBoxes();
}
//OK, now display!
writeDataToThePage();
}//end mapHandlerFunction
//this is a css thing
function unRevealPanels(){
//preserve nodelist & stick to For loops here (foreach not fully supported)
for(var i = 0; i < nodeListOfPanelsToPopulate.length; i++){
nodeListOfPanelsToPopulate[i].classList.add(hiddenStateString);
}
}
//this also ties into functionality
function disablePanels(){
for(var i = 0; i < nodeListOfPanelsToPopulate.length; i++){
nodeListOfCheckboxes[i].disabled = true;
nodeListOfPanelsToPopulate[i].classList.add(disabledStateString);
}
}
function removeAddActiveState(thenAdd){
//query statecode
var selectedItem = document.querySelector('.usState--SELECTED');
//if there is an active item, remove itS active class.
if (selectedItem !== null){
//selectedItem.classList.remove('usState--SELECTED');
selectedItem.setAttribute('class', 'usState iftMap__svg__path')
}
if(thenAdd){
//IE11 isn't handling classlist correctly here
//document.getElementById(singularViewOnlyStatusContainer.currentStateCode).classList.add('usState--SELECTED');
document.getElementById(singularViewOnlyStatusContainer.currentStateCode).setAttribute('class', 'usState iftMap__svg__path usState--SELECTED');
}
}
function clearTonsOfStuffBeforeWritingDataToPage(){
//start by clearing models
safeManualResetOfmapStatusContainerDeepARRAY();
safeManualResetOfOutputStatusContainerDeepARRAY();
//clear the input value we are populating for the backend on section click
clearHiddenInputForBackend();
clearHiddenInputForBackendCOMPONENTS();
//next, clear content, flags and data attributes
//(could consult model)
clearNoResultsMessageContainer();
clearCheckBoxes();
clearDataFlags();
removeAllToolTips();
clearPanelsOfContentAndDataAttributes();
//reset statuses of the panels themselves;
unRevealPanels();
disablePanels();
}
function writeDataToThePage(){
clearTonsOfStuffBeforeWritingDataToPage();
//called without arguments becuase that function queries the model
displayAreaName();
//FILTER SectionItems array to make new subarray of matching state sections (max 8)
var matchingSectionItems = rawSectionData.SectionItems.filter(function(sectionItem){
return sectionItem.StateCode === singularViewOnlyStatusContainer.currentStateCode
});
//NO RESULTS
if(matchingSectionItems.length < 1){
displayNoResultsMessage();
}
//now, map function to that new subarray
var iteratorNum = 0;
var indexOfPanelContainingHomeUserSection;
var indexesOfPanelsContainingAlreadySavedSections = [];
//if doing a map method with a counter, might be more idiomatic to use for loop
matchingSectionItems.map(function(matchingSectionItem){
//not all of these things should be in the map
//console.log(matchingSectionItem);
var indexOfSectionItem = rawSectionData.SectionItems.indexOf(matchingSectionItem);
//SET PROPERTIES IN MODEL
(function setAllTheProperties(){
//this is hardcoded, kinda. The order matters, so this should be a list operation. Or at least a forEach for ForIn loop. Better to do a list operation over properties
mapStatusContainerDeepARRAY[iteratorNum].currentProductId = rawSectionData.SectionItems[indexOfSectionItem].ProductId;
mapStatusContainerDeepARRAY[iteratorNum].currentProductCode = rawSectionData.SectionItems[indexOfSectionItem].ProductCode;
mapStatusContainerDeepARRAY[iteratorNum].currentProductName = rawSectionData.SectionItems[indexOfSectionItem].ProductName;
mapStatusContainerDeepARRAY[iteratorNum].currentComponentProductId = rawSectionData.SectionItems[indexOfSectionItem].ComponentProductId;
mapStatusContainerDeepARRAY[iteratorNum].currentComponentProductCode = rawSectionData.SectionItems[indexOfSectionItem].ComponentProductCode;
mapStatusContainerDeepARRAY[iteratorNum].currentComponentProductShortName = rawSectionData.SectionItems[indexOfSectionItem].ComponentProductShortName;
mapStatusContainerDeepARRAY[iteratorNum].currentMemberPrice = rawSectionData.SectionItems[indexOfSectionItem].MemberPrice;
mapStatusContainerDeepARRAY[iteratorNum].currentPostalCodeRange = rawSectionData.SectionItems[indexOfSectionItem].PostalCodeRange;
mapStatusContainerDeepARRAY[iteratorNum].currentComponentParentProduct = rawSectionData.SectionItems[indexOfSectionItem].ComponentParentProduct;
iteratorNum++;
})();
});//end of matchingSectionItems.map
(function populatePanels(){
for(var z = 0; z < nodeListOfPanelsToPopulate.length; z++){
var arrayOfSpansInThisPanel = arrayOfArrayOfFieldsToPopulate[z];
//4 spans per panel, so the function in the loop below will run 16 times
for(var zz = 0; zz < arrayOfSpansInThisPanel.length; zz++){
var valueForThisField = mapStatusContainerDeepARRAY[z][Object.keys(fieldsRequiredByPanelView)[zz]];
arrayOfSpansInThisPanel[zz].innerHTML = valueForThisField;
}
//using currentComponentParentProduct as flag. May need to change test
var valueForParentPanel = mapStatusContainerDeepARRAY[z].currentComponentParentProduct;
nodeListOfPanelsToPopulate[z].setAttribute('data-thispanel-productId', mapStatusContainerDeepARRAY[z].currentProductId);
nodeListOfPanelsToPopulate[z].setAttribute('data-thispanel-productCode', mapStatusContainerDeepARRAY[z].currentProductCode);
nodeListOfPanelsToPopulate[z].setAttribute('data-thispanel-componentProductId', mapStatusContainerDeepARRAY[z].currentComponentProductId);
nodeListOfPanelsToPopulate[z].setAttribute('data-thispanel-componentProductCode', mapStatusContainerDeepARRAY[z].currentComponentProductCode);
//console.log(valueForParentPanel);
if(valueForParentPanel === 'IFT'){
nodeListOfPanelsToPopulate[z].setAttribute('data-thispanel', 'thisPanelHasComponentSection');
}
}
})();
//this runs once per state selection
(function actionsBasedOnSectionsUserAlreadyHas(){
for(var i = 0; i < matchingSectionItems.length; i++){
if(matchingSectionItems[i].ProductId === userAlreadySavedSections.userHomeSectionProductID){ //always just one
indexOfPanelContainingHomeUserSection = i;
}
//console.log(userAlreadySavedSections);
//if the product ID of the matching section item is one of the already selected sections
if(
userAlreadySavedSections.additionalAlreadySavedSections.indexOf(matchingSectionItems[i].ProductId) > -1
|| userAlreadySavedSections.additionalAlreadySavedSections.indexOf(matchingSectionItems[i].ComponentProductId) > -1
|| userAlreadySavedSections.additionalComponentSavedSections.indexOf(matchingSectionItems[i].ProductId) > -1
|| userAlreadySavedSections.additionalComponentSavedSections.indexOf(matchingSectionItems[i].ComponentProductId) > -1
){
var numToPush = i;
indexesOfPanelsContainingAlreadySavedSections.push(numToPush);
}
}
})();//end actionsBasedOnUserHomeSectionOuterMostFunction
//QUERY THE DOM FOR THESE UNLESS PREPARED TO DO A PANEL STATE CONTAINER [hasTip, disabled, hidden]
//this runs once per state selection
(function panelStatusFunctionAfterStateChoice(){
for(var i = 0; i < nodeListOfPanelsToPopulate.length; i++){
var thisPanelToBeInspected = nodeListOfPanelsToPopulate[i];
(function decideWhetherSectionIsComponent(){
(function decideTooltips(){
if(thisPanelToBeInspected.getAttribute('data-thispanel') === 'thisPanelHasComponentSection'){
var referenceElem = thisPanelToBeInspected.querySelectorAll('label')[0];
createToolTipOnDemand(referenceElem);
}
})();
//here can go other decisions based on whether section is component product
})();//end decideWhetherSectionIsComponent
(function unDisablePanelsAfterStateChoice(){
//make sure record associated with the panel [using the index of the loop] does not contain user home section or already added sections before unDisabling a panel
if(i !== indexOfPanelContainingHomeUserSection && indexesOfPanelsContainingAlreadySavedSections.indexOf(i) < 0)
{
thisPanelToBeInspected.classList.remove(disabledStateString);
thisPanelToBeInspected.querySelector('input').disabled = false;
}
else {
//if panel DOES CONTAIN home state, so disable the input of course
thisPanelToBeInspected.querySelector('input').disabled = true;
}
})();
(function unHidePanelsWithDataAfterStateChoice(){
//check the first span in the panel to see if there is any data
var firstSpanInPanel = thisPanelToBeInspected.querySelectorAll('span')[0];
var valOfQuickRef = firstSpanInPanel.innerHTML;
//if there is any actual value here, unhide the panel
if(valOfQuickRef !== null && valOfQuickRef !== 'null' && valOfQuickRef !== ''){
thisPanelToBeInspected.classList.remove(hiddenStateString);
}
})();
}//end for loop
})();//end of panelStatusFunctionPerStateChoice
}//end of write data to page function
function createToolTipOnDemand(theReferenceFormLabelElement){
var tooltipElement = document.createElement('i');
tooltipElement.setAttribute('class', 'niftyTooltip');
tooltipElement.setAttribute('data-toolTipText', 'Additional sections listed below are complimentary with this selection.');
tooltipElement.innerHTML = '<svg class="iconInfo" viewBox="0 0 32 32"><use xlink:href="#iconInfo"/></svg>';
var theFirstChild = theReferenceFormLabelElement.firstChild;
theReferenceFormLabelElement.insertBefore(tooltipElement, theFirstChild);
}
//IE doesNt support remove. Must target parent and remove child
function removeAllToolTips(){
var nodelistOfTooltips = document.querySelectorAll('.niftyTooltip');
if(nodelistOfTooltips !== null){
for(var i = 0; i < nodelistOfTooltips.length; i++){
//nodelistOfTooltips[i].remove();
nodelistOfTooltips[i].parentNode.removeChild(nodelistOfTooltips[i]);
}
}
}
function displayNoResultsMessage(){
var theMessageToDisplay = 'There are no sections available. Please choose another state';
var messageContainer = document.createElement('div');
messageContainer.id = 'noResultsMessageContainer';
messageContainer.innerHTML = '<span>' + theMessageToDisplay + '</span>';
var theReferenceElementInDoc = document.querySelectorAll('.dataDisplay__row > .col-sm-3')[0];
var theFirstChild = theReferenceElementInDoc.firstChild;
theReferenceElementInDoc.insertBefore(messageContainer, theFirstChild);
}
function displayAreaName(){
seletedStateDisplay.innerHTML = singularViewOnlyStatusContainer.currentStateName;
}
function clearPanelsOfContentAndDataAttributes(){
//force clears without consulting model
arrayOfSpansToPopulateEmpty.map(function(thisSpan){
thisSpan.innerHTML = '';
thisSpan.setAttribute('data-thisspan', '');
});
}
function clearNoResultsMessageContainer(){
//query this here, not at the top
var noResultsMessageContainer = document.getElementById('noResultsMessageContainer');
if(noResultsMessageContainer !== null){
//noResultsMessageContainer.remove();
//for IE 11
noResultsMessageContainer.parentNode.removeChild(noResultsMessageContainer);
}
}
function clearCheckBoxes(){
for(var i = 0; i < nodeListOfCheckboxes.length; i++){
nodeListOfCheckboxes[i].checked = false;
}
}
function clearDataFlags(){
for(var i = 0; i < nodeListOfCheckboxes.length; i++){
nodeListOfPanelsToPopulate[i].setAttribute('data-thispanel', '');
nodeListOfPanelsToPopulate[i].setAttribute('data-thispanel-productId', '');
nodeListOfPanelsToPopulate[i].setAttribute('data-thispanel-productCode', '');
nodeListOfPanelsToPopulate[i].setAttribute('data-thispanel-componentProductId', '');
nodeListOfPanelsToPopulate[i].setAttribute('data-thispanel-componentProductCode', '');
}
}
function clearHiddenInputForBackend(){
hiddenInputForBackend.value = '';
}
function clearHiddenInputForBackendCOMPONENTS(){
if(hiddenInputForBackendCOMPONENTS !== null){
hiddenInputForBackendCOMPONENTS.value = '';
}
}
function showHideWholeMap(event){
if(event.currentTarget === iftMapButtonOpen) {
iftMapWrapperOuter.classList.add(activeStateString);
}
if(event.currentTarget === iftMapButtonClose || event.currentTarget === iftMapButtonCancel) {
iftMapWrapperOuter.classList.remove(activeStateString);
}
}
function checkBoxHandler(event){
var referenceToParentPanelOfCheckedInput = event.currentTarget.parentElement.parentElement;
//first clear the model & inputForBackend
safeManualResetOfOutputStatusContainerDeepARRAY();
clearHiddenInputForBackend();
clearHiddenInputForBackendCOMPONENTS();
//then adjust with panel status & stage stuff
adjustPanelStatusesBasedOnCurrentSelections(event, referenceToParentPanelOfCheckedInput);
stageSectionsBasedOnCurrentSelections(referenceToParentPanelOfCheckedInput);
}
function adjustPanelStatusesBasedOnCurrentSelections(event, referenceToParentPanelOfCheckedInput){
//map over panels to disable panels containing component products of the chosen section
var indexOfParentPanel = arrayOfPanelsToPopulate.indexOf(referenceToParentPanelOfCheckedInput);
//use FILTER to create an array of all panels that are NOT the one being interacted with
var arrayOfPanelsToAdjustMINUStheOnejustChosen = arrayOfPanelsToPopulate.filter(function(thisPanel){
//narrow that array so that it only includes components of currently interacted with thing
if(arrayOfPanelsToPopulate.indexOf(thisPanel) !== indexOfParentPanel){
return thisPanel;
}
});
//am i a component?
if(referenceToParentPanelOfCheckedInput.getAttribute('data-thispanel') === 'thisPanelHasComponentSection') {
//If so, map over the other panels to find fellow(s)
arrayOfPanelsToAdjustMINUStheOnejustChosen.map(function(thisPanelThatIsnTtheChosenOne){
if(thisPanelThatIsnTtheChosenOne.getAttribute('data-thispanel') === 'thisPanelHasComponentSection'){
if(event.currentTarget.checked === true){
reDisableOrEnableComponentProductOfCheckedItem(thisPanelThatIsnTtheChosenOne, 'reDisable');
//STAGE thisPanelThatIsnTtheChosenOne
thisPanelThatIsnTtheChosenOne.setAttribute('data-componentOfSelected', 'componentOfSelected');
}
else {
reDisableOrEnableComponentProductOfCheckedItem(thisPanelThatIsnTtheChosenOne, 'enable');
//UNSTAGE thisPanelThatIsnTtheChosenOne
thisPanelThatIsnTtheChosenOne.setAttribute('data-componentOfSelected', '');
}
}
});
}
function reDisableOrEnableComponentProductOfCheckedItem(thisPanelThatIsnTtheChosenOne, reDisableOrEnable){
if(reDisableOrEnable === 'reDisable'){
thisPanelThatIsnTtheChosenOne.classList.add(disabledStateString);
thisPanelThatIsnTtheChosenOne.querySelector('input').disabled = true;
}
else if (reDisableOrEnable === 'enable'){
thisPanelThatIsnTtheChosenOne.classList.remove(disabledStateString);
thisPanelThatIsnTtheChosenOne.querySelector('input').disabled = false;
}
}
}
//need to ensure this runs AFTER previous function is complete (so consider calling from end of previous function)
function stageSectionsBasedOnCurrentSelections(referenceToParentPanelOfCheckedInput){
var indexesOfSelectedSections = [];
var indexesOfPanelsContainingComponentSection = [];
for (var abc = 0; abc < nodeListOfCheckboxes.length; abc++){
//test must include things checked AND things marked as components
if(nodeListOfCheckboxes[abc].checked === true ){
indexesOfSelectedSections.push(abc);
}
if(nodeListOfPanelsToPopulate[abc].getAttribute('data-componentOfSelected') === 'componentOfSelected'){
indexesOfPanelsContainingComponentSection.push(abc)
}
}
//console.log('the following panels are selected ' + indexesOfSelectedSections);
//console.log('the following panels are components of selected ' + indexesOfPanelsContainingComponentSection);
//the checkbox handler clears the model and checkboxes, but maybe that should go here
(function grabValuesFromMapStatusContainerDeepARRAY(){
//this model can be 8
for(var i = 0; i < mapStatusContainerDeepARRAY.length; i++){
//stage checked
if(indexesOfSelectedSections.indexOf(i) > -1){
deepOutputObjectForStaging[i].ProductId = mapStatusContainerDeepARRAY[i].currentProductId;
deepOutputObjectForStaging[i].ProductName = mapStatusContainerDeepARRAY[i].currentProductName;
deepOutputObjectForStaging[i].ComponentProductId = mapStatusContainerDeepARRAY[i].currentComponentProductId;
deepOutputObjectForStaging[i].ComponentProductShortName = mapStatusContainerDeepARRAY[i].currentComponentProductShortName;
deepOutputObjectForStaging[i].MemberPrice = mapStatusContainerDeepARRAY[i].currentMemberPrice;
}
//stage components
if(indexesOfPanelsContainingComponentSection.indexOf(i) > -1){
deepOutputObjectForStagingCOMPONENTS[i].ProductId = mapStatusContainerDeepARRAY[i].currentProductId;
deepOutputObjectForStagingCOMPONENTS[i].ProductName = mapStatusContainerDeepARRAY[i].currentProductName;
deepOutputObjectForStagingCOMPONENTS[i].ComponentProductId = mapStatusContainerDeepARRAY[i].currentComponentProductId;
deepOutputObjectForStagingCOMPONENTS[i].ComponentProductShortName = mapStatusContainerDeepARRAY[i].currentComponentProductShortName;
deepOutputObjectForStagingCOMPONENTS[i].MemberPrice = mapStatusContainerDeepARRAY[i].currentMemberPrice;
}
}
//console.log(deepOutputObjectForStaging);
//console.log(deepOutputObjectForStagingCOMPONENTS)
})();
(function putOutputArraysInHiddenInputs(){
//insert value here.
hiddenInputForBackend.value = JSON.stringify(deepOutputObjectForStaging);
//backend hasnT added this yet and i want to avoid errors
if(hiddenInputForBackendCOMPONENTS !== null){
//console.log(JSON.stringify(deepOutputObjectForStagingCOMPONENTS));
hiddenInputForBackendCOMPONENTS.value = JSON.stringify(deepOutputObjectForStagingCOMPONENTS);
}
})();
}
//EVENTS
(function addEventListeners(){
stateSelectMenu.addEventListener('change', mapHandlerFunction, false);
internationalSelectMenu.addEventListener('change', mapHandlerFunction, false);
iftMapButtonOpen.addEventListener('click', showHideWholeMap, false);
iftMapButtonClose.addEventListener('click', showHideWholeMap, false);
iftMapButtonCancel.addEventListener('click', showHideWholeMap, false);
arrayOfCheckboxes.map(function(thisCheckbox){
thisCheckbox.addEventListener('change', checkBoxHandler, false);
})
})();
}
document.addEventListener('DOMContentLoaded', iftMapFunctionInit);
})();
#iftMapWrapperOuter {
display: none;
position:fixed;
top:0;
left: 0;
width:100%;
max-width: 100%;
height: 100%;
background:rgba(0,0,0,0.2);
overflow-y: scroll;
z-index: 999999;
&.iftMapWrapperOuter--ACTIVE-STATE {
display: block;
}
}
.iftMap__wrapper--inner{
background-color: $white;
padding: $gutter-width;
margin-top: $gutter-width;
position: relative;
overflow: hidden;
}
.iftMap__header {
// position:absolute;
// top:0;
// left:0;
width: 100%;
// background:$ift-grey-medium-lighter;
}
.iftMap__svg {
transform:scale(.5);
transform-origin: 0 0;
@include break(max, $breakpoint-max-mobile){
//width: 100%;
//height:auto;
margin-bottom: -250px;
}
@include break(min, $breakpoint-min-tablet){
//blame microsoft
margin-bottom: -300px;
}
@include break(max, 399px){
transform:scale(.3);
margin-bottom: -400px;
}
}
.usState {
cursor: pointer;
fill: #dddddd;
stroke: #999999;
stroke-width: .03rem;
}
.states {
:hover {
fill:rgba(87,134,199,1);
}
.usState--SELECTED {
fill:rgba(87,134,199,1);
}
}
.state-borders {
fill: none;
stroke: #666666;
stroke-width: 0.5px;
stroke-linejoin: round;
stroke-linecap: round;
pointer-events: none;
}
.iftMap__wrapper--outer {
@include break(max, $breakpoint-max-1023){
text-align: center;
}
@include break(min, $breakpoint-min-lg){
max-width: $breakpoint-min-md;
}
header {
@include break(max, $breakpoint-max-mobile){
font-size: 1.2rem;
p {
font-size: 1.2rem;
}
}
}
.row {
//padding-bottom: 0;
}
[class^="col-"]{
padding-left: 0;
padding-right: 0;
}
}
.iftMap__additionalItemsBox__wrapper--outer {
text-align: left;
@include break(min, $breakpoint-min-md){
padding-top:$gutter-width/2;
}
}
.iftMap__mobile__selectMenu__wrapper--outer {
// @include break(min, $breakpoint-min-tablet){
// display: none;
// }
.iftMap__additionalItemsBox__wrapper--inner {
padding-bottom:0;
}
}
.iftMap__stateSelectMenu {
@include break(max, $breakpoint-max-mobile){
margin-bottom: $gutter-width / 2;
font-size: 1.2rem;
option {
font-size: 1.4rem
//transform:scale(.275);
}
}
}
.iftMap__additionalItemsBox--internationalSections {
.iftMap__additionalItemsBox__wrapper--inner {
@include break(max, $breakpoint-max-mobile){
padding-top:0;
}
}
}
.iftMap__internationalSelectMenu {
color:$ift-blue;
overflow: auto;
height: auto;
background-color: transparent;
border: none;
option {
color: $ift-blue;
background-color: transparent !important;
}
@include break(max, $breakpoint-max-mobile){
font-size: 1rem;
option {
font-size: 1rem;
//transform:scale(.275);
}
}
@include break(min, $breakpoint-min-tablet){
font-size: 1.2rem;
option {
font-size: 1.2rem;
//transform:scale(.275);
}
}
}
.iftMap__row--hasMap {
@include break(max, $breakpoint-max-mobile){
padding-bottom: $gutter-width/2;
}
}
.dataDisplay__row {
padding-bottom:$gutter-width/2;
text-align:left;
}
.dataDisplay__header {
border-bottom: 1px solid $ift-grey-200;
}
.seletedStateDisplay__headline__span {
color: $ift-blue;
}
.iftMap__button--cancel{
@include unButton()
}
a.iftMap__button--save{
color: white
}
.iftMap__sectionData__wrapper {
position:relative;
font-size: 1.2rem;
line-height: 1;
padding-right:$gutter-width;
@include break(max, $breakpoint-max-mobile){
padding-bottom: $gutter-width;
}
> label {
display: table;
position:relative;
padding-bottom: 1.6rem;
input {
display: table-cell;
//tough override of other join forms
margin-left: 0 !important;
}
span {
display: table-cell;
padding-left:.5rem;
}
}
}
.iftMap__sectionData__detail {
padding-bottom: $gutter-width / 2;
}
.iftMap__zipCodes {
padding:$gutter-width / 8;
font-size: 1.1rem;
border: 1px solid $ift-grey-200;
}
.iftMap__additionalItemsBox__headline {
@include break(max, $breakpoint-max-mobile){
font-size: 1.4rem;
}
}
.iftMap__additionalItemsBox__wrapper--inner {
background: $ift-grey-medium-lighter;
padding: $gutter-width / 2;
position:relative;
}
.iftMap__internationalSelectMenu__footer {
font-size: 1.2rem;
line-height: 1;
@include break(max, $breakpoint-max-mobile){
font-size:1rem;
}
}
.iftMap__sectionData__wrapper--HIDDEN-STATE {
display: none;
}
.iftMap__sectionData__wrapper--DISABLED-STATE {
//pointer-events:none;
opacity: .3333;
cursor: not-allowed;
pointer-events:none;
&:hover {
cursor: not-allowed;
}
label {
pointer-events:none;
cursor: not-allowed;
&:hover {
cursor: not-allowed;
}
&:before {
content: '\002713';
position: absolute;
top: -3px;
left: 2px;
font-size: 1.2rem;
color:#999;
//box-shadow: 1px 1px inset #000;
}
}
input {
//prevent click somehow;
z-index: -1;
pointer-events:none;
cursor: not-allowed;
&:hover {
cursor: not-allowed;
}
}
//z-index: 0;
//disallow highlight and actual click
//also, obscure member price and show notApplicatble message
.iftMap__memberPrice {
span {
visibility: hidden;
}
}
}
.iftMap__memberPrice {
span {
&:before {
content: '$';
}
}
}
//tooltip
.niftyTooltip {
position:absolute;
right: -1.4rem;
&:hover,
&:active,
&:focus {
&:after {
content: attr(data-toolTipText);
position:absolute;
top: 2rem;
right: 0;
//that position isnT working as expected
//left: 2rem;
display: inline-block;
min-width: 100px;
background:#fff;
border: 1px solid #000;
padding: 1rem;
z-index: 1;
}
}
}
.iftMap__sectionData__footer {
position:absolute;
background: $ift-grey-medium-lighter;
padding:$gutter-width/4;
font-size: 1rem;
line-height: 1;
//top:$gutter-width;
// left: 0;
// z-index: 9;
//demoOnly
margin-top: -200px;
margin-left: 150px;
max-width: 300px;
.row {
padding-bottom:$gutter-width/8;
}
//default to hidden state in the html
&.iftMap__sectionData__footer--HIDDEN-STATE{
display: none;
}
}
.iconInfo {
width: 16px;
height: 16px;
cursor: pointer;
stroke-width: 3px;
stroke: $white;
fill:$ift-blue-dark;
}
.iftMap__sectionData__footer__column--label {
font-weight: bold;
}
.iftMap__tooltip__closeButton__wrapper {
position:absolute;
top:0;
right: 0;
width: 1.6rem;
height: 1.6rem;
cursor: pointer;
background:#000;
&:hover {
cursor: pointer;
}
}
.iftMap__tooltip__closeButton__svg {
width: 1rem;
height: 1rem;
stroke: #fff;
stroke-width:3px;
}
.iftMap__wrapper--outer__closeButton__wrapper {
position: absolute;
top: 1rem;
right: 1rem;
width: 3.2rem;
height: 3.2rem;
padding: .8rem;
cursor: pointer;
background: #000;
overflow: hidden;
border-radius: 100%;
&:hover {
cursor: pointer;
}
}
.iftMap__wrapper--outer__closeButton__svg {
width: 1.6rem;
height: 1.6rem;
stroke: #fff;
stroke-width:4px;
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment