var IqAboOneTime = { card: "#onetime_order_card", holder: "#insert_show_onetime_order", abo_holder: "#insert_show_products_order", summary_card: "#combined_summary_card", comp_holder: "#holder_html_view_comp_product", modal: "#modals-load-content", oTable: null, url: null, btn_modal_add: ".add-onetime-product-basket", btn_add: ".onetime-add-from-basket", btn_remove: ".onetime-remove-from-basket", input_change: ".onetime-input-onchange", remove_item: ".remove_onetime_from_cart", confirm_changes: ".onetime-confirm-changes", discard_changes: ".onetime-discard-changes", summary_col: "#combined_summary_col", sticky_gap: 16, _stickyTicking: false, init: function () { var _self = this; _self.url = $(_self.card).data("onetime-route"); _self.reInitCart(); _self.initSticky(); return _self; }, initSticky: function () { var _self = this; var card = document.querySelector(_self.summary_card); var col = document.querySelector(_self.summary_col); if (!card || !col) { return; } var onScrollOrResize = function () { if (_self._stickyTicking) { return; } _self._stickyTicking = true; window.requestAnimationFrame(function () { _self.updateSticky(card, col); _self._stickyTicking = false; }); }; // Capture-Phase, damit Scroll-Events beliebiger Scroll-Container erfasst werden. window.addEventListener("scroll", onScrollOrResize, true); window.addEventListener("resize", onScrollOrResize); _self.updateSticky(card, col); }, resetSticky: function (card) { card.style.position = ""; card.style.top = ""; card.style.left = ""; card.style.width = ""; card.style.zIndex = ""; }, updateSticky: function (card, col) { var _self = this; // Nur im zweispaltigen Layout (lg+) kleben. if (window.innerWidth < 992) { _self.resetSticky(card); return; } var colStyle = window.getComputedStyle(col); var padLeft = parseFloat(colStyle.paddingLeft) || 0; var padRight = parseFloat(colStyle.paddingRight) || 0; var colRect = col.getBoundingClientRect(); var contentLeft = colRect.left + padLeft; var contentWidth = col.clientWidth - padLeft - padRight; var cardHeight = card.offsetHeight; var gap = _self.sticky_gap; if (colRect.top >= gap) { // Noch nicht über den oberen Rand gescrollt -> normaler Fluss. _self.resetSticky(card); return; } // Oben anheften, aber maximal bis zum Ende der Spalte. var topPos = gap; var maxTop = colRect.bottom - cardHeight; if (maxTop < gap) { topPos = maxTop; } card.style.position = "fixed"; card.style.top = topPos + "px"; card.style.left = contentLeft + "px"; card.style.width = contentWidth + "px"; card.style.zIndex = "1020"; }, setDatabase: function (oTable) { this.oTable = oTable; }, reInitModal: function () { var _self = this; $(_self.oTable) .find(_self.btn_modal_add) .off("click") .on("click", function () { _self.addFromModal($(this)); }); }, reInitCart: function () { var _self = this; var $holder = $(_self.holder); $holder .find(_self.btn_add) .off("click") .on("click", function () { _self.changeQty($(this), 1); }); $holder .find(_self.btn_remove) .off("click") .on("click", function () { _self.changeQty($(this), -1); }); $holder .find(_self.input_change) .off("change") .on("change", function () { _self.updateInput($(this)); }); $holder .find(_self.remove_item) .off("click") .on("click", function (event) { event.preventDefault(); _self.removeItem($(this)); }); $holder .find(_self.confirm_changes) .off("click") .on("click", function () { _self.confirmChanges(); }); $holder .find(_self.discard_changes) .off("click") .on("click", function () { _self.discardChanges(); }); }, addFromModal: function (_obj) { var _self = this; var $modal = $(_self.modal); $modal.one("hidden.bs.modal", function () { _self .performRequest({ action: "add", product_id: _obj.data("product-id"), }) .done(_self.refreshView); }); $modal.modal("hide"); }, changeQty: function (_obj, delta) { var _self = this; var itemId = _obj.data("onetime-item-id"); var input = $(_self.holder).find( 'input[name="onetime_qty_' + itemId + '"]' ); var qty = _self.checkNumber(parseInt(input.val(), 10) + delta); input.val(qty); _self .performRequest({ action: "update", one_time_item_id: itemId, qty: qty, }) .done(_self.refreshView); }, updateInput: function (_obj) { var _self = this; var qty = _self.checkNumber(parseInt(_obj.val(), 10)); _obj.val(qty); _self .performRequest({ action: "update", one_time_item_id: _obj.data("onetime-item-id"), qty: qty, }) .done(_self.refreshView); }, removeItem: function (_obj) { var _self = this; _self .performRequest({ action: "remove", one_time_item_id: _obj.data("onetime-item-id"), }) .done(_self.refreshView); }, confirmChanges: function () { var _self = this; _self .performRequest({ action: "confirm", }) .done(_self.refreshView); }, discardChanges: function () { var _self = this; _self .performRequest({ action: "discard", }) .done(_self.refreshView); }, refreshView: function (data) { var _self = IqAboOneTime; if (data.html_onetime) { $(_self.holder).html(data.html_onetime); } if (data.html_abo) { $(_self.abo_holder).html(data.html_abo); } if (data.html_summary) { $(_self.summary_card).html(data.html_summary); } if (data.html_comp !== undefined) { $(_self.comp_holder).html(data.html_comp); } $(_self.modal).modal("hide"); _self.reInitCart(); if (typeof iqModalCart !== "undefined" && iqModalCart.reInitCart) { iqModalCart.reInitCart($(_self.abo_holder)); iqModalCart.reInitCart($(_self.comp_holder)); } var card = document.querySelector(_self.summary_card); var col = document.querySelector(_self.summary_col); if (card && col) { _self.updateSticky(card, col); } }, performRequest: function (data) { var _self = this; return $.ajax({ url: _self.url, data: data, type: "POST", dataType: "json", cache: false, headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"), }, }).fail(function (jqXHR) { var msg = jqXHR.responseJSON && jqXHR.responseJSON.message ? jqXHR.responseJSON.message : "Error"; var errorEl = document.getElementById("insert_onetime_error_message"); if (!errorEl) { errorEl = document.createElement("div"); errorEl.id = "insert_onetime_error_message"; errorEl.className = "alert alert-danger mt-2"; var holder = document.querySelector("#insert_show_onetime_order"); if (holder) { holder.insertBefore(errorEl, holder.firstChild); } } errorEl.textContent = msg; }); }, checkNumber: function (number) { if (number < 1 || isNaN(number)) { return 1; } if (number > 100) { return 100; } return number; }, };