// These first three must match the constants of the same names at the top of // ...\Common\BusinessLogic\OfferManagement\basic\InvisibleBll.cs // see the comments in that location. // // (I seriously considered copying them from the BLL into the ViewBag via // the two controllers, but decided it wasn't worth it for just three variables // that are only declared in two places.) var MENU_DELIMITER_SIMPLE = "`"; var MENU_DELIMITER_CRUMB = "~"; var MENU_DELIMITER_SELECTION = "|"; // Constants for the global UserMode variable var USERMODE_SELECT = 1; var USERMODE_CUSTOMIZE = 2; // This was requested in the requirements but it looks horrible. var globalUseAlternateBackgrounds = false; // Some functions need to know whether they're being called while the page is being loaded. var interactive = false; var classNameHoverSel = "hoverselected"; // These are declared here but assigned real values in the .cshtml file var globalMenuId = 0; var globalUserMode = 0; var globalUrlGatherMajors = ''; var globalUrlGatherMinors = ''; var globalUrlGatherItems = ''; var globalUrlCustomize = ''; var globalOriginalChoices = null; // The word "choices" means selected (in SELECT mode) or deleted (in DELETE mode) var currentChoices = new Array(); var originalRadio = 0; var currentRadio = 0; var currentMajorName = ''; var currentMinorName = ''; var currentMajorId = 0; var currentMinorId = 0; function splitFullNameArray(listOfFullNames) { if (listOfFullNames == null || listOfFullNames == '') { return new Array(); } return listOfFullNames.split(MENU_DELIMITER_SELECTION).sort(); } function getSimpleName(fullName, which) { if (fullName != null) { var simpleNames = fullName.split(MENU_DELIMITER_CRUMB); if (0 < which && which <= simpleNames.length) { return simpleNames[which - 1]; } } return null; } function parseSimpleNameForLevel(simpleName) { return (simpleName == null) ? 0 : parseInt(simpleName.substr(0, 1)); } function parseSimpleNameForName(simpleName) { if (simpleName != null) { var tokens = simpleName.substr(1).split(MENU_DELIMITER_SIMPLE); return tokens[0]; } return "?"; } function parseSimpleNameForId(simpleName) { if (simpleName != null) { var tokens = simpleName.substr(1).split(MENU_DELIMITER_SIMPLE); if (tokens.length >= 2) { return tokens[1]; } } return ""; } function parseSimpleNameForQuantity(simpleName) { if (simpleName != null) { var tokens = simpleName.substr(1).split(MENU_DELIMITER_SIMPLE); if (tokens.length >= 3) { return tokens[2]; } } return ""; } function buildCrumbTrail(fullName) { var trail = "no crumbs"; var crumb1 = parseSimpleNameForName(getSimpleName(fullName, 1)); var crumb2 = parseSimpleNameForName(getSimpleName(fullName, 2)); var crumb3 = parseSimpleNameForName(getSimpleName(fullName, 3)); var whichLevel = parseSimpleNameForLevel(fullName); if (whichLevel == globalLevelMajor) { trail = crumb1; } else if (whichLevel == globalLevelMinor) { trail = crumb2 + " -> " + crumb1; } else if (whichLevel == globalLevelItem) { trail = crumb3 + " -> " + crumb2 + " -> " + crumb1; } return trail; } function buildSimpleName(whichLevel, posName, targetId, quantity) { return '' + whichLevel + posName + MENU_DELIMITER_SIMPLE + targetId + MENU_DELIMITER_SIMPLE + quantity; } function buildFullName(whichLevel, posName, targetId, quantity) { var result = buildSimpleName(whichLevel, posName, targetId, quantity); if (whichLevel == globalLevelItem) { result += MENU_DELIMITER_CRUMB + buildSimpleName(globalLevelMinor, currentMinorName, currentMinorId, 0); } if (whichLevel == globalLevelItem || whichLevel == globalLevelMinor) { result += MENU_DELIMITER_CRUMB + buildSimpleName(globalLevelMajor, currentMajorName, currentMajorId, 0); } return result; } function buildListOfFullNames(whichArray) { var listOfFullNames = ''; for (var j in whichArray) { listOfFullNames += MENU_DELIMITER_SELECTION + whichArray[j]; } return listOfFullNames.substr(1); } function showColumn(whichLevel) { $jq("#" + prefixMainColumn + whichLevel).show(); } function hideColumn(whichLevel) { $jq("#" + prefixMainColumn + whichLevel).hide(); } function clearAllChoices() { hideColumn(globalLevelMinor); hideColumn(globalLevelItem); // quick & dirty way of clearing this currentChoices = new Array(); } // Remember that we can't use indexOf() because it is not available under IE6. function thisIsChosen(fullName) { for (var j in currentChoices) { if (getSimpleName(currentChoices[j], 1) == getSimpleName(fullName, 1)) { return true; } } return false; } function addToChosenArray(fullName) { if (!thisIsChosen(fullName)) { currentChoices.push(fullName); currentChoices.sort(); resetClearButton(); } } function removeFromChosenArray(fullName) { for (var j in currentChoices) { if (getSimpleName(currentChoices[j], 1) == getSimpleName(fullName, 1)) { currentChoices.splice(j, 1); resetClearButton(); break; } } } function radioChecked(value) { currentRadio = value; resetSaveButton(); } // This is only used during SELECT ITEM mode. function itemWasChecked($inputObj) { var $aObj = $inputObj.parent().find("a"); var fullName = $aObj.attr("fullName"); if ($inputObj.attr('checked')) { addToChosenArray(fullName); } else { removeFromChosenArray(fullName); } updateDisplayedList(); updateDelimitedList(); resetSaveButton(); } // It's safe to do this, because if the user cancels, // the Save function does not get called and therefore // the value doesn't get copied back to the true field. function updateDelimitedList() { $jq("#DelimitedListOfSelectedItems").val(buildListOfFullNames(currentChoices)); } function applyEffectToChosenName(fullName) { var whichLevel = parseSimpleNameForLevel(fullName); var effect = null; if (whichLevel == globalLevelMajor) { effect = 'strong'; } else if (whichLevel == globalLevelMinor) { effect = 'em'; } var result = parseSimpleNameForName(fullName); if (effect != null) { result = '<' + effect + '>' + result + ''; } return result; } function setTargetAsSelected(id) { if (id > 0) { var $aObj = $jq('[targetid="' + id + '"]'); if ($aObj != null) { // A is child of LI is child of UL, which can have at most one LI with this class var $liObj = $aObj.parent(); var $ulObject = $liObj.parent(); var $currentLI = $ulObject.find('.' + classNameHoverSel); if ($currentLI != null) { $currentLI.removeClass(classNameHoverSel); } $liObj.addClass(classNameHoverSel); } } } function revealSelection(fullName) { var simpleName = getSimpleName(fullName, 1); var targetId = parseSimpleNameForId(simpleName); var whichLevel = parseSimpleNameForLevel(simpleName); if (whichLevel == globalLevelMajor) { hideColumn(globalLevelMinor); hideColumn(globalLevelItem); } else if (whichLevel == globalLevelMinor) { // full name looks like MINOR~MAJOR simpleName = getSimpleName(fullName, 2); if (simpleName != null) { currentMajorId = parseSimpleNameForId(simpleName); currentMajorName = parseSimpleNameForName(simpleName); setTargetAsSelected(currentMajorId); updateMinorColumn(currentMajorId); } } else if (whichLevel == globalLevelItem) { // full name looks like ITEM~MINOR~MAJOR simpleName = getSimpleName(fullName, 3); if (simpleName != null) { currentMajorId = parseSimpleNameForId(simpleName); currentMajorName = parseSimpleNameForName(simpleName); updateMinorColumn(currentMajorId); setTargetAsSelected(currentMajorId); } simpleName = getSimpleName(fullName, 2); if (simpleName != null) { currentMinorId = parseSimpleNameForId(simpleName); currentMinorName = parseSimpleNameForName(simpleName); updateItemColumn(currentMajorId, currentMinorId); setTargetAsSelected(currentMinorId); } } setTargetAsSelected(targetId); } function buildDisplayedList(arrayOfChoices, verb, limitOfItemsToDisplay) { var displayedList = ''; if (arrayOfChoices.length == 0) { if (verb != null) { displayedList = 'There are no items ' + verb; } } else { var trueLimit = arrayOfChoices.length; if (limitOfItemsToDisplay > 0 && trueLimit > limitOfItemsToDisplay) { trueLimit = limitOfItemsToDisplay; } for (var j = 0; j < trueLimit; j++) { var oneEntry = applyEffectToChosenName(arrayOfChoices[j]); if (limitOfItemsToDisplay > 0) { oneEntry = '
  • ' + oneEntry + '
  • '; } else { if (verb == 'selected') { oneEntry = '' + oneEntry + ''; } oneEntry = ', ' + oneEntry; } displayedList += oneEntry; } if (limitOfItemsToDisplay > 0) { var undisplayed = arrayOfChoices.length - trueLimit; if (undisplayed > 0) { displayedList += "
  • " + "[" + undisplayed + " more]" + "
  • "; } displayedList = ""; } if (verb != null) { displayedList = 'These items are ' + verb + ': ' + displayedList.substr(2); } } return displayedList; } function updateDisplayedList() { var verb = (globalUserMode == USERMODE_SELECT) ? 'selected' : 'deleted'; var displayedList = buildDisplayedList(currentChoices, verb, 0); $jq("#spnChosenItems").html(displayedList); } function buildMenuItemList(delimitedStringFromMenuManagement) { var listOfItems = ''; if (delimitedStringFromMenuManagement != null && delimitedStringFromMenuManagement != '') { var menuSelections = delimitedStringFromMenuManagement.split(menuSelectionDelimiter); var numberOfItemsChosen = menuSelections.length; var numberOfItemsDisplayed = 0; var limitOfItemsToDisplay = 5; for (var j = 0; j < menuSelections.length; j++) { if (numberOfItemsDisplayed < limitOfItemsToDisplay) { var whichName = getNameFromFullName(menuSelections[j]); var whichLevel = getLevelFromFullName(menuSelections[j]); listOfItems += "
  • " + applyEffectToChosenName(whichLevel, whichName) + "
  • "; ++numberOfItemsDisplayed; } } if (listOfItems.length > 0) { listOfItems = ""; var undisplayed = numberOfItemsChosen - limitOfItemsToDisplay; if (undisplayed > 0) { listOfItems += "" + undisplayed + " more . . ."; } } } return listOfItems; } // Those are not typos in the delimiters for fullname . . . double quotes are allowed // in a POSNAME while single quotes are not, so we reverse the usual punctuation. function buildAnchorElement(whichLevel, posName, majorId, minorId, targetId, fullName) { var element = ''; return element; } function getImageClassName(isVisible) { return (isVisible) ? 'deleteIcon' : 'restoreIcon'; } function getImageFullClassName(isVisible) { return 'icon ' + ((isVisible) ? 'deleteIcon' : 'restoreIcon'); } function buildInputElement(isChosen, isVisible) { var element; if (globalUserMode == USERMODE_CUSTOMIZE) { element = ''; } else { var modifier = (isChosen) ? 'checked="checked" ' : ''; element = ''; } return element; } function buildColumn(whichLevel, entries) { // Show/hide the appropriate columns and mark them active/inactive. var higherLevel = 0; clearList(whichLevel); showColumn(whichLevel); if (whichLevel == globalLevelMajor) { clearList(globalLevelMinor); clearList(globalLevelItem); hideColumn(globalLevelMinor); hideColumn(globalLevelItem); } else if (whichLevel == globalLevelMinor) { higherLevel = globalLevelMajor; clearList(globalLevelItem); hideColumn(globalLevelItem); } else if (whichLevel == globalLevelItem) { higherLevel = globalLevelMinor; } if (higherLevel > 0) { $jq("#" + prefixMainColumn + higherLevel + " .active").removeClass('active'); } $jq("#" + prefixMainColumn + whichLevel + " .active").addClass('active'); // Loop through all of the entries, adding each to the column's UL // unless it is marked as "deleted" and we are in SELECT mode. // // THU 1 SEP 2011: TP 8309 says // The "Deleted Items" Section within the Menu Selection Popup should not be there // so we can simply not add those at all. var $mainList = $jq("#" + prefixMainList + whichLevel); var targetId = 0; var majorId = 0; var minorId = 0; var newLI = ''; for (var j = 0; j < entries.length; j++) { if (entries[j].Visible || globalUserMode == USERMODE_CUSTOMIZE) { if (whichLevel == globalLevelMajor) { targetId = entries[j].MajorId; majorId = entries[j].MajorId; minorId = 0; } else if (whichLevel == globalLevelMinor) { targetId = entries[j].MinorId; majorId = entries[j].MajorId; minorId = entries[j].MinorId; } else { targetId = entries[j].ItemId; majorId = entries[j].MajorId; minorId = entries[j].MinorId; } var fullName = buildFullName(whichLevel, entries[j].Name, targetId, 1); newLI = '
  • '; newLI += buildAnchorElement(whichLevel, entries[j].Name, majorId, minorId, targetId, fullName); newLI += buildInputElement(thisIsChosen(fullName), entries[j].Visible); newLI += '
  • '; $mainList.append(newLI); } } if (whichLevel == globalLevelMajor) { // do nothing, the title for this column is constant } else { var title = (whichLevel == globalLevelMinor) ? currentMajorName : currentMinorName; $jq("#" + prefixMainTitle + whichLevel).html(title); } if (globalUseAlternateBackgrounds) { $jq("ul li:nth-child(even)").addClass('even'); $jq("ul li:nth-child(odd)").addClass('alternate'); } } function clearList(listName) { $jq("#" + prefixMainList + listName).html(""); } function twoArraysAreTheSame(first, second) { // assumes that both are already sorted if (first == null || second == null || first.length != second.length) { return false; } for (var j = 0; j < first.length; j++) { if (first[j] != second[j]) { return false; } } return true; } function enableControl($control) { $control.removeAttr('disabled'); } function disableControl($control) { $control.attr('disabled', 'disabled'); } function toggleControl($control, shouldBeEnabled) { if (shouldBeEnabled) { enableControl($control); } else { disableControl($control); } } function resetSaveButton() { var saveShouldBeDisabled = (originalRadio == currentRadio) && twoArraysAreTheSame(currentChoices, globalOriginalChoices); toggleControl($jq("#btnSave"), !saveShouldBeDisabled); if (globalUserMode == USERMODE_CUSTOMIZE) { toggleControl($jq("#btnUndo"), !saveShouldBeDisabled); } } function resetClearButton() { toggleControl($jq("#btnClear"), currentChoices.length > 0); } // This is what the HTML looks like: // //
    // This is only used when globalUserMode is USERMODE_CUSTOMIZE function deleteOrRestoreItem($inputObj) { var deleting = itemIsDeleteable($inputObj); var $liObj = $inputObj.parent(); var $aObj = $liObj.find("a"); var fullName = $aObj.attr("fullName"); var whichLevel = parseSimpleNameForLevel(fullName); if (interactive) { if (whichLevel == globalLevelMajor) { hideColumn(globalLevelItem); hideColumn(globalLevelMinor); clearList(globalLevelItem); clearList(globalLevelMinor); } else if (whichLevel == globalLevelMinor) { hideColumn(globalLevelItem); clearList(globalLevelItem); } else { // Nothing to do at the item level } } // change the icon from trashcan to doublearrow, or vice-versa. // Note the horrible adjustment needed $inputObj.removeAttr("class").addClass(getImageFullClassName(!deleting)); if (deleting) { addToChosenArray(fullName); } else { removeFromChosenArray(fullName); } updateDisplayedList(); if (interactive) { resetSaveButton(); } } function getItemsAndDisplay(url, data, success) { $jq.ajax({ global: false, async: false, url: url, dataType: "json", type: "POST", contentType: "application/json; charset=utf-8", data: JSON.stringify(data), success: success, error: function (msg) { // a real weird problem is happening which causes a json parse error, when the json is just fine // proved by doing a parseJSON of the msg.responseText property. if (msg.statusText == "parsererror" && msg.status == 200) { if (msg.responseText.substr(0, 12) == '[{"MajorId":') { var data = $jq.parseJSON(msg.responseText); success(data); } } } }); } function updateMajorColumn() { getItemsAndDisplay(globalUrlGatherMajors, { menuId: globalMenuId }, function (data) { buildColumn(globalLevelMajor, data); }); } function updateMinorColumn(majorId) { getItemsAndDisplay(globalUrlGatherMinors, { menuId: globalMenuId, menuMajorGroupId: majorId }, function (data) { buildColumn(globalLevelMinor, data); }); } function updateItemColumn(majorId, minorId) { getItemsAndDisplay(globalUrlGatherItems, { menuId: globalMenuId, menuMajorGroupId: majorId, menuMinorGroupId: minorId }, function (data) { buildColumn(globalLevelItem, data); }); } function showMenuItemsSelectionModal(buying, fieldId) { clearAllChoices(); currentRadio = buying ? currentOnlyOne : currentSelectOpt; originalRadio = currentRadio; // fill the line at the top which the user sees var listOfFullNames = $jq("#" + fieldId).val(); globalOriginalChoices = splitFullNameArray(listOfFullNames); currentChoices = globalOriginalChoices.slice(); resetSaveButton(); resetClearButton(); updateDisplayedList(); updateDelimitedList(); // pop it up. fieldId always begins with "RestValue". var currentTitle = (currentChoices == '') ? "Choosing " : "Editing "; currentTitle += fieldId.substr(9) + " from menu " + globalMenuId + " . . ."; var popupbox = $jq("#MenuItemsSelection").dialog({ modal: true, width: 1000, position: 'top', maxHeight: false, maxWidth: false, draggable: true, minHeight: 100, resizable: false, title: currentTitle, open: function () { $jq("#HowToGroupItems").toggle(buying); $jq("#HowToSelectItems").toggle(!buying); } }); popupbox.parent().css({ "margin-top": "110px" }); updateMajorColumn(); $jq("#Column" + globalLevelMajor).find("li").removeClass(classNameHoverSel); } function restoreAllClicked() { if (globalUserMode == USERMODE_SELECT) { if (confirm("Are you sure you want to drop all " + currentChoices.length + " selected items?")) { clearAllChoices(); resetSaveButton(); resetClearButton(); updateDisplayedList(); updateDelimitedList(); } } else { if (currentChoices.length == 0) { alert("There are no deleted items to restore"); } else { var prompt = (currentChoices.length == 1) ? "the deleted item?" : "all " + currentChoices.length + " deleted items?"; if (confirm("Are you sure you want to restore " + prompt)) { currentChoices = new Array(); resetSaveButton(); resetClearButton(); updateDisplayedList(); $jq("#DynamicDrillDown").find("input").removeClass().addClass(getImageFullClassName(true)); } } } } function undoAllClicked() { if (confirm("Are you sure you want to undo your changes?")) { window.location.reload(); } } function cancelClicked() { if (confirm('If you are sure you want to cancel your changes, click "OK" and you will be redirected to the Store Selection page.')) { backToGrid(); } } function saveClicked() { // Must send a valid array, even if it consists of a single empty string if (currentChoices.length == 0) { currentChoices.push(''); } $jq.ajax({ async: false, url: globalUrlCustomize, type: "POST", contentType: "application/json; charset=utf-8", data: JSON.stringify( { menuId: globalMenuId, arrayOfFullNames: currentChoices }), success: saveSucceeded }); } function saveSucceeded(data, textStatus, jqXHR) { // The Save() method in the controller _always_ succeeds (see comments in MenuManagementController.cs) // to prevent the error from being caught at a higher level. We check here to see the true outcome. var prompt; if (jqXHR.responseText == 'OK') { prompt = 'Your changes were saved successfully'; } else { prompt = 'Your changes --- ' + currentChoices + ' --- could not be saved. Message is' + jqXHR.responseText; } prompt += '\n\nClick OK to be redirected back to the Store Selection page.'; alert(prompt); backToGrid(); } function backToGrid() { window.location.href = "/OfferManagement/MenuManagement" + window.location.search; } function itemIsDeleteable($inputObj) { return $inputObj.hasClass(getImageClassName(true)); } function itemNameWasClicked(obj) { var $aObj = $jq(obj); var $liObj = $aObj.parent(); var $inputObj = $liObj.find("input"); if (globalUserMode == USERMODE_SELECT || itemIsDeleteable($inputObj)) { var whichLevel = $aObj.attr("level"); if (whichLevel == globalLevelMajor) { currentMajorName = obj.firstChild.nodeValue; currentMajorId = $aObj.attr("majorid"); updateMinorColumn(currentMajorId); } else if (whichLevel == globalLevelMinor) { currentMinorName = obj.firstChild.nodeValue; currentMinorId = $aObj.attr("minorid"); updateItemColumn(currentMajorId, currentMinorId); } else { // nothing to do for globalLevelItem } $liObj.prevAll().removeClass(classNameHoverSel); $liObj.nextAll().removeClass(classNameHoverSel); $liObj.addClass(classNameHoverSel); } } $jq(document).ready(function () { if (globalUserMode == USERMODE_CUSTOMIZE) { currentChoices = globalOriginalChoices.slice(); updateDisplayedList(); resetClearButton(); updateMajorColumn(); } var $ddd = $jq("#DynamicDrillDown"); $ddd.delegate("li", "mouseout", function (event) { var $this = $jq(this); $this.removeClass('hover'); }); $ddd.delegate("li", "mouseover", function (event) { var $this = $jq(this); $this.addClass('hover'); }); interactive = true; });