如何使用Bootstrap模式和按钮进行可重用的确认控件?

时间:2019-05-22 12:31:24

标签: javascript jquery html

当前,我正在尝试通过打开Bootstrap模态以及为不同功能使用这些相同模态,使用户能够确认某些内容。在这个问题中,我将使用“计算器”类型的元素作为附加功能的示例。就目前而言,除非我将JQuery的$target.off();添加到targetModal.on("hidden.bs.modal", function (e) {});,否则确认操作将无效。

当我添加这段JQuery代码时,这也会导致我在此页面上使用的任何其他功能(关于Bootstrap模态)也中断,这意味着我需要为这些功能中的任何一个添加其他代码。我不希望这种情况发生。我如何才能使这些确认正常工作,同时又能使其他功能正常运行而又不为这些功能添加其他代码?

应该发生什么:

  1. 当选择“否”时,按钮(显然为“否”)应保持相同的颜色,但是相反的按钮(“是”按钮)应变为灰色,并且“确认?”按钮应该被禁用(如果尚未禁用)。另外,如果可见<button class="btn btn-warning pending">Pending</button>,则应将其隐藏。
  2. 选择“是”时,按钮(“是”)应保持不变的颜色,但是相反的按钮(“否”按钮)应变成灰色,并且“确认?”按钮应启用。
  3. 何时“确认?”单击按钮,它应该在模式中填充与确认相关的所有内容,并打开给定的模式。
  4. 在确认期间 退出/关闭模式而没有完成确认时,功能WillClose()(依次应更改待处理的按钮文本)给定的确认控制权以“重试”)。
  5. 成功执行确认后(通过单击给定模态中的“确认”按钮),模态应隐藏/消失(并重置内部内容)并执行ConfirmModal()函数(应禁用该功能)给定确认控件的所有按钮,并将待处理的按钮文本更改为“已确认”。
  6. 这些确认中的任何一项都应相互独立运作。

发生了什么事

除非我将$target.off()添加到模式中(例如targetModal.off()),否则确认元素会触发彼此的待处理按钮。但是,执行后者将导致其他功能“中断”。我的意思是,无论是将“填充”,“插入”或“克隆”(无论您要称呼它)在模态内的任何内容,都将多次放置在模态内(就像模态没有重置,有意义吗?)

我如何进行以下工作?

//Fields:

//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm";
//Pending selector
const pendingSelector = ".pending";
//calTrigger selector
const calcTriggerSelector = ".calc-trigger > button";
//Yes elements
const positiveNodes = document.querySelectorAll(positiveSelector);
//No elements
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? elements
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending elements
const pendingNodes = document.querySelectorAll(pendingSelector);
//calcTrigger elements
const calcTriggerNodes = document.querySelectorAll(calcTriggerSelector);

//Modal
const targetModalSelector = "#bs-modal-xl";
const targetModal = $(targetModalSelector);
const $modalInit = targetModal.html();

//Eventlisteners:

positiveNodes.forEach(node => node.addEventListener("click", function () {
  EnableConfirmBtn(this);
}));

negativeNodes.forEach(node => node.addEventListener("click", function () {
  DisableConfirmBtn(this);
}));

confirmNodes.forEach(node => node.addEventListener("click", function () {
  OpenConfirmModal(this);
}));

calcTriggerNodes.forEach(node => node.addEventListener("click", calcTrigger));

//Reset modal when closing
targetModal.on("hidden.bs.modal", function () {
  targetModal.html($modalInit);
});

//Methods:

function EnableConfirmBtn(ele) {
  ele.classList.add("btn-success");
  ele.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}

function DisableConfirmBtn(ele) {
  ele.classList.add("btn-warning");
  ele.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
}

function OpenConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");

  $(targetModalSelector + " .modal-body").html($(".clone-one").clone());
  $(targetModalSelector + " .clone-one").show();
  $(targetModalSelector + " h4.modal-title").text("");
  $(targetModalSelector + " .modal-content .modal-footer").html("");
  targetModal.modal();

  targetModal.on("click", ".clone-one", function () {
    targetModal.modal("hide");
    ConfirmModal(ele);
  });

  targetModal.on("hidden.bs.modal", function (e) {
    WillClose(ele);
    //Make use of targetModal.off(); here? <--
    //targetModal.off();
    targetModal.html($modalInit);
  });
}

function ConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Confirmed");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger", "btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-success"));
  ele.parentNode.querySelectorAll(confirmSelector).forEach(node => node.style.display = "none");
  ele.parentNode.querySelectorAll(".btn-group > button").forEach(node => node.setAttribute("disabled", ""));
}

function WillClose(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Try again");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-warning"));
}

function calcTrigger() {
  ModalHandler($(".calc").clone(), "", "", true, true);
  $(targetModalSelector + " .calc").show();
  targetModal.modal();

  document.querySelectorAll(targetModalSelector + " .calc #number-one-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "1");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-two-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "2");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-three-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "3");
  }));
  
  //I would not want to be using something like this:

  //Reset modal when closing
  //targetModal.on("hidden.bs.modal", function () {
  //targetModal.off();
  //targetModal.html($modalInit);
  //});
}

//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
  $(targetModalSelector + " h4.modal-title").text(title);
  $(targetModalSelector + " .modal-body").html(content);

  if (footer != "" && footer != undefined) {
    $(targetModalSelector + " .modal-footer").html(footer);
  }

  if (bigCloseBtn) {
    $(targetModalSelector + " .modal-content .modal-header button.close").css("float", "right");
    $(targetModalSelector + " .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
    //$(".modal .modal-content .modal-header button.close").html("close");
    $(targetModalSelector + " .modal-content .modal-header button.close").removeClass("close");
  }

  if (emptyFooter) {
    $(targetModalSelector + " .modal-content .modal-footer").html("");
  }
}
#foo-container {
    padding: 5px;
  }

  .pending {
    display: none;
  }

  .clone-one, .calc {
    display: none;
  }

  .calc {
    width: 100%;
  }

  .calc button, .calc .result-container {
    margin-top: 3px;
    margin-bottom: 3px;
  }

  .calc [class*="col-"] {
    padding-left: 3px;
    padding-right: 3px;
  }
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="modal" id="bs-modal-xl" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
  <div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <p>One fine body&hellip;</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

<div id="calc" class="calc">
  <form>
    <div class="row">
      <div class="col-xs-9">
        <div class="result-container">
          <input type="text" class="form-control" disabled>
        </div>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="x" id="">
          <span class="glyphicon glyphicon-remove"></span>
        </button>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="1" id="number-one-btn">
          1
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="2" id="number-two-btn">
          2
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="3" id="number-three-btn">
          3
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="" id="number-one-btn">
          <span class="glyphicon glyphicon-arrow-left"></span>
        </button>
      </div>
    </div>
  </form>
</div>

<div class="container">
  <div id="foo-container">
    <div class="confirmation-box">
      <div class="btn-group btn-group-lg" role="group" aria-label="...">
        <button type="button" class="btn btn-success positive">Yes</button>
        <button type="button" class="btn btn-warning negative">No</button>
      </div>
      <button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
      <button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
    </div>

    <br />

    <div class="confirmation-box">
      <div class="btn-group btn-group-lg" role="group" aria-label="...">
        <button type="button" class="btn btn-success positive">Yes</button>
        <button type="button" class="btn btn-warning negative">No</button>
      </div>
      <button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
      <button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
    </div>

    <br />

    <div class="calc-trigger">
      <button class="btn btn-lg btn-default">
        Calc trigger
      </button>
    </div>
  </div>

  <div class="clone-one">
    <button type="button" class="btn btn-lg btn-success">Clicky</button>
  </div>
</div>

JSFiddle

我只是在寻找一种需要最少代码的解决方案。如果给定的示例可以重写为较小的格式,请告诉我。

编辑:我知道上面提供的代码会添加多个事件侦听器,而我单击某些引起问题的控件的次数越多。因此,这就是为什么我正在寻找一种(尽可能简单的)解决方案,以使所有这些控件独立运行,同时保持脚本不引人注目,并保持上面提供的代码的大部分格式。

1 个答案:

答案 0 :(得分:3)

现在的问题 :使用

targetModal.on("hidden.bs.modal", function (e) {
  WillClose(ele);
  //Make use of targetModal.off(); here? <--
  //targetModal.off();
  targetModal.html($modalInit);
});

OpenConfirmModal函数内部,每次打开对话框时都会附加一个新的事件处理程序。这导致以下情况:

  1. 打开对话框并附加事件处理程序。
  2. 对话框关闭,并且执行了一个事件处理程序。
  3. 对话框打开,并附加了另一个事件处理程序。
  4. 对话框关闭,并且执行了两个事件处理程序。
  5. 对话框打开,并附加了另一个事件处理程序。
  6. 对话框关闭,并且执行了三个事件处理程序。

以此类推。确认也存在类似问题。我已经修改了代码,只添加了一个控制台日志来演示这一点-打开和关闭会使控制台上的日志越来越多:

//Fields:

//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm";
//Pending selector
const pendingSelector = ".pending";
//calTrigger selector
const calcTriggerSelector = ".calc-trigger > button";
//Yes elements
const positiveNodes = document.querySelectorAll(positiveSelector);
//No elements
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? elements
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending elements
const pendingNodes = document.querySelectorAll(pendingSelector);
//calcTrigger elements
const calcTriggerNodes = document.querySelectorAll(calcTriggerSelector);

//Modal
const targetModalSelector = "#bs-modal-xl";
const targetModal = $(targetModalSelector);
const $modalInit = targetModal.html();

//Eventlisteners:

positiveNodes.forEach(node => node.addEventListener("click", function () {
  EnableConfirmBtn(this);
}));

negativeNodes.forEach(node => node.addEventListener("click", function () {
  DisableConfirmBtn(this);
}));

confirmNodes.forEach(node => node.addEventListener("click", function () {
  OpenConfirmModal(this);
}));

calcTriggerNodes.forEach(node => node.addEventListener("click", calcTrigger));

//Reset modal when closing
targetModal.on("hidden.bs.modal", function () {
  targetModal.html($modalInit);
});

//Methods:

function EnableConfirmBtn(ele) {
  ele.classList.add("btn-success");
  ele.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}

function DisableConfirmBtn(ele) {
  ele.classList.add("btn-warning");
  ele.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
}

function OpenConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");

  $(targetModalSelector + " .modal-body").html($(".clone-one").clone());
  $(targetModalSelector + " .clone-one").show();
  $(targetModalSelector + " h4.modal-title").text("");
  $(targetModalSelector + " .modal-content .modal-footer").html("");
  targetModal.modal();

  targetModal.on("click", ".clone-one", function () {
    targetModal.modal("hide");
    console.log("hiding")
    ConfirmModal(ele);
  });

  targetModal.on("hidden.bs.modal", function (e) {
    WillClose(ele);
    console.log("closing");
    //Make use of targetModal.off(); here? <--
    //targetModal.off();
    targetModal.html($modalInit);
  });
}

function ConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Confirmed");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger", "btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-success"));
  ele.parentNode.querySelectorAll(confirmSelector).forEach(node => node.style.display = "none");
  ele.parentNode.querySelectorAll(".btn-group > button").forEach(node => node.setAttribute("disabled", ""));
}

function WillClose(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Try again");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-warning"));
}

function calcTrigger() {
  ModalHandler($(".calc").clone(), "", "", true, true);
  $(targetModalSelector + " .calc").show();
  targetModal.modal();

  document.querySelectorAll(targetModalSelector + " .calc #number-one-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "1");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-two-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "2");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-three-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "3");
  }));
  
  //I would not want to be using something like this:

  //Reset modal when closing
  //targetModal.on("hidden.bs.modal", function () {
  //targetModal.off();
  //targetModal.html($modalInit);
  //});
}

//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
  $(targetModalSelector + " h4.modal-title").text(title);
  $(targetModalSelector + " .modal-body").html(content);

  if (footer != "" && footer != undefined) {
    $(targetModalSelector + " .modal-footer").html(footer);
  }

  if (bigCloseBtn) {
    $(targetModalSelector + " .modal-content .modal-header button.close").css("float", "right");
    $(targetModalSelector + " .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
    //$(".modal .modal-content .modal-header button.close").html("close");
    $(targetModalSelector + " .modal-content .modal-header button.close").removeClass("close");
  }

  if (emptyFooter) {
    $(targetModalSelector + " .modal-content .modal-footer").html("");
  }
}
#foo-container {
    padding: 5px;
  }

  .pending {
    display: none;
  }

  .clone-one, .calc {
    display: none;
  }

  .calc {
    width: 100%;
  }

  .calc button, .calc .result-container {
    margin-top: 3px;
    margin-bottom: 3px;
  }

  .calc [class*="col-"] {
    padding-left: 3px;
    padding-right: 3px;
  }
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="modal" id="bs-modal-xl" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
  <div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <p>One fine body&hellip;</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

<div id="calc" class="calc">
  <form>
    <div class="row">
      <div class="col-xs-9">
        <div class="result-container">
          <input type="text" class="form-control" disabled>
        </div>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="x" id="">
          <span class="glyphicon glyphicon-remove"></span>
        </button>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="1" id="number-one-btn">
          1
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="2" id="number-two-btn">
          2
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="3" id="number-three-btn">
          3
        </button>
      </div>
      <div class="col-xs-3">
        <button type="button" class="btn btn-default btn-block" value="" id="number-one-btn">
          <span class="glyphicon glyphicon-arrow-left"></span>
        </button>
      </div>
    </div>
  </form>
</div>

<div class="container">
  <div id="foo-container">
    <div class="confirmation-box">
      <div class="btn-group btn-group-lg" role="group" aria-label="...">
        <button type="button" class="btn btn-success positive">Yes</button>
        <button type="button" class="btn btn-warning negative">No</button>
      </div>
      <button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
      <button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
    </div>

    <br />

    <div class="confirmation-box">
      <div class="btn-group btn-group-lg" role="group" aria-label="...">
        <button type="button" class="btn btn-success positive">Yes</button>
        <button type="button" class="btn btn-warning negative">No</button>
      </div>
      <button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
      <button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
    </div>

    <br />

    <div class="calc-trigger">
      <button class="btn btn-lg btn-default">
        Calc trigger
      </button>
    </div>
  </div>

  <div class="clone-one">
    <button type="button" class="btn btn-lg btn-success">Clicky</button>
  </div>
</div>

可以使用.off来避免这种情况,但这并不是最好的主意,因为它实际上会使代码更加笨拙。

  • 调用.off时,您只能指定一个事件,但是,这将删除该事件的 all 处理程序。 targetModal.off("hidden.bs.modal");仅适用于简单情况,但您可以从其他地方添加第二个处理程序,该处理程序可以正常工作(不会不断重新添加),并且也会被清除。
  • 如果使用特定处理程序调用{​​{1}}来删除,则需要引用该处理程序。这更有用,但更尴尬-您的代码有效地 如下所示:
.off

相反,请使用.one,它是var handler = function (e) { // ^^^^^^^------------------------------------------------------------------ <- WillClose(ele); // | targetModal.off("hidden.bs.modal", "*" handler); // `handler` references -> -^ // ^-------------- targetModal.html($modalInit);// | these need to match because }// | .off() requires a second parameter // | parameter to use the handler ref targetModal.on("hidden.bs.modal", "*", handler);// | this mandates that .on() also // ^ ---------------- uses the second parmeter 与隐式.on的组合-它会将回调函数作为事件处理程序附加,并在执行一次后将其删除。这样,您不必自己打.off

这是您使用.off的代码-现在,如果您反复打开和关闭对话框,则控制台中只会显示一个日志,而不是根据您的次数n + 1打开对话框:

.one
//Fields:

//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm";
//Pending selector
const pendingSelector = ".pending";
//calTrigger selector
const calcTriggerSelector = ".calc-trigger > button";
//Yes elements
const positiveNodes = document.querySelectorAll(positiveSelector);
//No elements
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? elements
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending elements
const pendingNodes = document.querySelectorAll(pendingSelector);
//calcTrigger elements
const calcTriggerNodes = document.querySelectorAll(calcTriggerSelector);

//Modal
const targetModalSelector = "#bs-modal-xl";
const targetModal = $(targetModalSelector);
const $modalInit = targetModal.html();

//Eventlisteners:

positiveNodes.forEach(node => node.addEventListener("click", function () {
  EnableConfirmBtn(this);
}));

negativeNodes.forEach(node => node.addEventListener("click", function () {
  DisableConfirmBtn(this);
}));

confirmNodes.forEach(node => node.addEventListener("click", function () {
  OpenConfirmModal(this);
}));

calcTriggerNodes.forEach(node => node.addEventListener("click", calcTrigger));

//Reset modal when closing
targetModal.on("hidden.bs.modal", function () {
  targetModal.html($modalInit);
});

//Methods:

function EnableConfirmBtn(ele) {
  ele.classList.add("btn-success");
  ele.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}

function DisableConfirmBtn(ele) {
  ele.classList.add("btn-warning");
  ele.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
  ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
}

function OpenConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");

  $(targetModalSelector + " .modal-body").html($(".clone-one").clone());
  $(targetModalSelector + " .clone-one").show();
  $(targetModalSelector + " h4.modal-title").text("");
  $(targetModalSelector + " .modal-content .modal-footer").html("");
  targetModal.modal();
  
  targetModal.one("click", ".clone-one", function () {
  //one --------^
    targetModal.modal("hide");
    console.log("hide")
    ConfirmModal(ele);
  });

  targetModal.one("hidden.bs.modal", function (e) {
  //one --------^
    WillClose(ele);
    console.log("will close")
    targetModal.html($modalInit);
  });
}

function ConfirmModal(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Confirmed");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger", "btn-warning"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-success"));
  ele.parentNode.querySelectorAll(confirmSelector).forEach(node => node.style.display = "none");
  ele.parentNode.querySelectorAll(".btn-group > button").forEach(node => node.setAttribute("disabled", ""));
}

function WillClose(ele) {
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Try again");
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger"));
  ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-warning"));
}

function calcTrigger() {
  ModalHandler($(".calc").clone(), "", "", true, true);
  $(targetModalSelector + " .calc").show();
  targetModal.modal();

  document.querySelectorAll(targetModalSelector + " .calc #number-one-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "1");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-two-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "2");
  }));

  document.querySelectorAll(targetModalSelector + " .calc #number-three-btn").forEach(node => node.addEventListener("click", function () {
    document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "3");
  }));
  
  //I would not want to be using something like this:

  //Reset modal when closing
  //targetModal.on("hidden.bs.modal", function () {
  //targetModal.off();
  //targetModal.html($modalInit);
  //});
}

//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
  $(targetModalSelector + " h4.modal-title").text(title);
  $(targetModalSelector + " .modal-body").html(content);

  if (footer != "" && footer != undefined) {
    $(targetModalSelector + " .modal-footer").html(footer);
  }

  if (bigCloseBtn) {
    $(targetModalSelector + " .modal-content .modal-header button.close").css("float", "right");
    $(targetModalSelector + " .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
    //$(".modal .modal-content .modal-header button.close").html("close");
    $(targetModalSelector + " .modal-content .modal-header button.close").removeClass("close");
  }

  if (emptyFooter) {
    $(targetModalSelector + " .modal-content .modal-footer").html("");
  }
}
#foo-container {
    padding: 5px;
  }

  .pending {
    display: none;
  }

  .clone-one, .calc {
    display: none;
  }

  .calc {
    width: 100%;
  }

  .calc button, .calc .result-container {
    margin-top: 3px;
    margin-bottom: 3px;
  }

  .calc [class*="col-"] {
    padding-left: 3px;
    padding-right: 3px;
  }