Last active
May 21, 2019 16:22
-
-
Save jeremybatesDC/a85506d240b6e7e97d9ae89310cf5808 to your computer and use it in GitHub Desktop.
custom e-commerce D3 map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment