495 lines
19 KiB
JavaScript
495 lines
19 KiB
JavaScript
/*
|
|
$Revision$
|
|
$Id$
|
|
|
|
File: mobile.js
|
|
Description: clientside functions for pda
|
|
*/
|
|
|
|
window.fcltmobile = 1;
|
|
|
|
if (window && window.localStorage && window.localStorage.getItem("interface") == "touch") {
|
|
toTouch();
|
|
}
|
|
|
|
$(function() {
|
|
// Alle niet :target's worden default onderdrukt, als er geen :target is; toon dan de eerste pagina
|
|
window.addEventListener("hashchange", function() {
|
|
var hash = location.hash.split("#")[1];
|
|
if (hash) {
|
|
$(".page.show").removeClass("show");
|
|
var $targetPage = $(".page#" + hash);
|
|
if ($targetPage.length) {
|
|
$targetPage.addClass("show");
|
|
} else {
|
|
// Als er geen pagina is, dan terug naar de eerste pagina
|
|
$(".page:first").addClass("show");
|
|
}
|
|
} else {
|
|
// Als er geen hash is, dan terug naar de eerste pagina
|
|
$(".page.show").removeClass("show");
|
|
$(".page:first").addClass("show");
|
|
}
|
|
});
|
|
|
|
if (!location.href.split("#")[1]) {
|
|
$(".page:first").addClass("show");
|
|
}
|
|
|
|
// Set initial theme
|
|
toggleTheme();
|
|
|
|
/* theme change eventHandler */
|
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", toggleTheme);
|
|
|
|
/* Footer eventHandlers */
|
|
$(".pda-button-more").off("click").on("click", function() {
|
|
$(this).toggleClass("open");
|
|
});
|
|
|
|
$(document)
|
|
.off("touchstart touchend touchcancel")
|
|
.on("touchstart", function(e) {
|
|
var $target = $(e.target).closest(".tappable");
|
|
if (!$target.hasClass("tappable")) {
|
|
return;
|
|
}
|
|
if ($target.find(".tappable-target").length) {
|
|
$target = $target.find(".tappable-target");
|
|
}
|
|
$target.addClass("fclt-active");
|
|
$(document).one("scrollstart", () => {
|
|
$(".tappable.fclt-active .tappable-target.fclt-active").removeClass("fclt-active");
|
|
});
|
|
}).on("touchend touchcancel", function(e) {
|
|
var $target = $(e.target).closest(".tappable");
|
|
if (!$target.hasClass("tappable")) {
|
|
return;
|
|
}
|
|
if ($target.find(".tappable-target").length) {
|
|
$target = $target.find(".tappable-target");
|
|
}
|
|
$target.removeClass("fclt-active");
|
|
$(document).off("scrollstart");
|
|
});
|
|
|
|
var path = window.location.pathname;
|
|
var page = path.split("/").pop();
|
|
$("a[href='" + page + "']").addClass("active-page");
|
|
/* \Footer eventHandlers */
|
|
|
|
// Card more button
|
|
$(".tappable.fclt-more").on("click", toggleRows);
|
|
|
|
// Swipe
|
|
let touchstart = { "x": 0, "y": 0 };
|
|
const SWIPE_THRESHOLD = {
|
|
"x": window.innerWidth / 2.5,
|
|
"y": window.innerHeight / 2.5
|
|
}
|
|
let touchmoveHandler = e => {
|
|
let translateX = (e.touches[0].screenX - touchstart.x);
|
|
let translateY = (e.touches[0].screenY - touchstart.y);
|
|
let isHoriSwiping = Math.abs(translateX) > Math.abs(translateY); /* else => vertical scrolling */
|
|
if (isHoriSwiping &&
|
|
(translateX > 0 && typeof swipeRightAction === "function" ||
|
|
translateX < 0 && typeof swipeLeftAction === "function")) {
|
|
e.currentTarget.style.transform = "translateX(" + translateX + "px)";
|
|
e.currentTarget.style.opacity = 1 - Math.abs(translateX) / window.innerWidth;
|
|
// } else if ( translateY < 0 && typeof swipeUpAction === "function" ||
|
|
// translateY > 0 && typeof swipeDownAction === "function") {
|
|
// e.currentTarget.style.transform = "translateY(" + translateX + "px)";
|
|
// e.currentTarget.style.opacity = 1 - translateY / window.innerHeight;
|
|
} else {
|
|
e.currentTarget.style.transform = null;
|
|
e.currentTarget.style.opacity = null;
|
|
if (!isHoriSwiping) { /* Cancel swipe */
|
|
e.currentTarget.removeEventListener("touchmove", touchmoveHandler);
|
|
e.currentTarget.dataset.swipeActive = 0;
|
|
}
|
|
}
|
|
}
|
|
let swipeables = document.getElementsByClassName("swipeable");
|
|
[...swipeables].forEach(element => {
|
|
element.addEventListener("touchstart", e => {
|
|
touchstart.x = e.touches[0].screenX;
|
|
touchstart.y = e.touches[0].screenY;
|
|
e.currentTarget.addEventListener("touchmove", touchmoveHandler);
|
|
e.currentTarget.dataset.swipeActive = 1;
|
|
});
|
|
element.addEventListener("touchend", e => {
|
|
if (touchstart.x === 0 && touchstart.y === 0 ||
|
|
e.currentTarget.dataset.swipeActive != 1) {
|
|
return;
|
|
}
|
|
let touchend = {
|
|
"x": e.changedTouches[0].screenX,
|
|
"y": e.changedTouches[0].screenY
|
|
};
|
|
let swipeFunc;
|
|
// if (touchstart.y - touchend.y > SWIPE_THRESHOLD.y) { // UP
|
|
// swipeFunc = window["swipeUpAction"];
|
|
// } else if (touchend.y - touchstart.y > SWIPE_THRESHOLD.y) { // DOWN
|
|
// swipeFunc = window["swipeDownAction"];
|
|
// }
|
|
if (touchstart.x - touchend.x > SWIPE_THRESHOLD.x) { // LEFT
|
|
swipeFunc = window["swipeLeftAction"];
|
|
} else if (touchend.x - touchstart.x > SWIPE_THRESHOLD.x) { // RIGHT
|
|
swipeFunc = window["swipeRightAction"];
|
|
}
|
|
if (typeof swipeFunc === "function") {
|
|
e.currentTarget.removeEventListener("touchmove", touchmoveHandler);
|
|
e.currentTarget.dataset.swipeActive = 0;
|
|
swipeFunc(e.currentTarget);
|
|
}
|
|
touchstart = { "x": 0, "y": 0 };
|
|
if (e.currentTarget) {
|
|
e.currentTarget.style.transform = null;
|
|
e.currentTarget.style.opacity = null;
|
|
e.currentTarget.removeEventListener("touchmove", touchmoveHandler);
|
|
e.currentTarget.dataset.swipeActive = 0;
|
|
}
|
|
});
|
|
});
|
|
|
|
// Multiactions
|
|
const $bulkables = $(".bulkable");
|
|
$bulkables.add(".tappable").on("contextmenu", e => e.preventDefault());
|
|
if ($bulkables.length) {
|
|
$(".cancel.multiaction").on("click", e => toggleBulkAction("off"));
|
|
const $counter = $(".multiaction-count");
|
|
const bulkEventHandler = e => {
|
|
e.preventDefault();
|
|
let $this = $(e.currentTarget);
|
|
let isActive = $this.hasClass("bulk-selected");
|
|
$this.toggleClass("bulk-selected", !isActive);
|
|
$counter.attr("data-count", +$counter.attr("data-count") + (isActive ? -1 : 1));
|
|
if ($(".bulkable.bulk-selected").length === 0) {
|
|
toggleBulkAction("off");
|
|
}
|
|
}
|
|
|
|
window.toggleBulkAction = function _toggleBulkAction(newState) {
|
|
let isActive = $(".fclt-content").hasClass("bulk-active");
|
|
if (newState === "on" && !isActive) {
|
|
$(".fclt-content").addClass("bulk-active");
|
|
$(".bulkable > .card-link, .bulkable.list-group-item-action").each((i, el) => {
|
|
$(el)
|
|
.data("href", $(el).attr("href"))
|
|
.data("onclick", $(el).attr("onclick"))
|
|
.attr({
|
|
"href": null,
|
|
"onclick": null,
|
|
"aria-disabled": true
|
|
});
|
|
});
|
|
$(".bulkable").on("click", bulkEventHandler);
|
|
} else if (newState === "off" && isActive) {
|
|
$(".fclt-content").removeClass("bulk-active");
|
|
$counter.attr("data-count", 0);
|
|
$(".bulkable").off("click", bulkEventHandler)
|
|
.removeClass("bulk-selected");
|
|
$(".bulkable > .card-link, .bulkable.list-group-item-action").each((i, el) => {
|
|
$(el)
|
|
.attr({
|
|
"href": $(el).data("href"),
|
|
"onclick": $(el).data("onclick"),
|
|
"aria-disabled": false
|
|
}).removeData("href onclick");
|
|
});
|
|
}
|
|
}
|
|
|
|
$bulkables.each((i, elem) => {
|
|
$(elem).on("fclt-longpress", e => {
|
|
e.preventDefault();
|
|
toggleBulkAction("on");
|
|
bulkEventHandler(e);
|
|
});
|
|
});
|
|
}
|
|
|
|
function addLongPressEventHandler($elem) {
|
|
$elem
|
|
.on("touchstart.longpress", e => {
|
|
let $this = $(e.currentTarget);
|
|
var longpressTimer = window.setTimeout($().trigger.bind($this, "fclt-longpress"), 750);
|
|
$this.data("longpressTimer", longpressTimer);
|
|
}).on("touchend.longpress touchcancel.longpress", e => {
|
|
let $this = $(e.currentTarget);
|
|
var longpressTimer = $this.data("longpressTimer");
|
|
if (longpressTimer) {
|
|
window.clearTimeout(longpressTimer);
|
|
$this.removeData("longpressTimer");
|
|
}
|
|
});
|
|
}
|
|
|
|
var $longpressables = $bulkables; // Kan worden uitgebreid
|
|
|
|
addLongPressEventHandler($longpressables);
|
|
|
|
// Filter
|
|
$(".list-group-filter").on("input", function () {
|
|
if (window.filterTimeout) {
|
|
clearTimeout(window.filterTimeout);
|
|
}
|
|
window.filterTimeout = setTimeout(searchList.bind(this), 500);
|
|
});
|
|
|
|
$("textarea").autogrow();
|
|
});
|
|
|
|
function toggleRows() {
|
|
var $card = $(this).closest(".card");
|
|
$card.find(".fa-chevron-down, .fa-chevron-up").toggleClass("fa-chevron-down fa-chevron-up");
|
|
$card.find(".row.open, .row.closed").toggleClass("open closed");
|
|
}
|
|
|
|
function getActiveTheme() {
|
|
let activeTheme = window.localStorage.getItem("color-scheme");
|
|
if (activeTheme !== "light" && activeTheme !== "dark") {
|
|
activeTheme = "auto";
|
|
}
|
|
return activeTheme;
|
|
}
|
|
|
|
function getThemeIcon(theme) {
|
|
theme = theme || getActiveTheme();
|
|
if (theme === "light") {
|
|
return "fa-sun-bright";
|
|
} else if (theme === "dark") {
|
|
return "fa-moon fas";
|
|
} else {
|
|
return "fa-circle-half-stroke far";
|
|
}
|
|
}
|
|
|
|
function toggleTheme(newTheme) {
|
|
if (newTheme === "light" || newTheme === "dark") {
|
|
window.localStorage.setItem("color-scheme", newTheme);
|
|
} else if (newTheme === "auto") {
|
|
window.localStorage.removeItem("color-scheme");
|
|
}
|
|
let activeTheme = getActiveTheme();
|
|
if (activeTheme !== "light" && activeTheme !== "dark") { // Dus auto
|
|
activeTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
}
|
|
$("html").attr("data-bs-theme", activeTheme);
|
|
$("[data-theme-toggle]").children("i").replaceWith(I(getThemeIcon(newTheme)));
|
|
}
|
|
|
|
function removeCardAnimated(elem) {
|
|
const elemStyle = window.getComputedStyle(elem);
|
|
let padding = parseInt(elemStyle.paddingTop) + parseInt(elemStyle.paddingBottom);
|
|
elem.style.flexBasis = elem.clientHeight - padding + "px";
|
|
elem.style.visibility = "hidden";
|
|
while (elem.lastChild) { // Vanilla .empty();
|
|
elem.removeChild(elem.lastChild);
|
|
}
|
|
elem.offsetHeight; // Flushes the CSS changes
|
|
elem.classList.add("card-removing"); // Sets transition duration
|
|
elem.addEventListener("transitionend", () => {
|
|
elem.remove();
|
|
}, { once: true });
|
|
elem.classList.add("card-remove"); // Animate object vertically disappearing
|
|
}
|
|
|
|
function searchList() {
|
|
var s = this.value.toLowerCase();
|
|
var $section = $(this).next("section");
|
|
// Remove expliciete 'first' en 'last' classes voor de styling
|
|
$(".list-group-item-first, .list-group-item-last").removeClass("list-group-item-first list-group-item-last");
|
|
if ($section.length) {
|
|
if (s === "") {
|
|
$section.find(".list-group-item").show();
|
|
} else {
|
|
// De regels
|
|
$section.find(".list-group-item").each((i, elem) => {
|
|
$(elem).toggle($(elem).text().toLowerCase().indexOf(s) != -1);
|
|
});
|
|
// De dividers (eventueel)
|
|
$section.find(".list-group-header").each((i, elem) => {
|
|
$(elem).toggle($(elem).nextUntil(".list-group-header").filter(":visible").length > 0);
|
|
});
|
|
}
|
|
}
|
|
// Add expliciete 'first' en 'last' classes voor de styling
|
|
$section.find(".list-group-item").filter(":visible").first().addClass("list-group-item-first");
|
|
$section.find(".list-group-item").filter(":visible").last().addClass("list-group-item-last");
|
|
}
|
|
|
|
function McltCallbackAndThen(afterAction) {
|
|
return function(json, textStatus) {
|
|
if (json.message) alert(json.message); // Normaal door FcltMgr.closeDetail
|
|
if (json.warning) alert(json.warning);
|
|
if (json.toaster) jqToast(json.toaster);
|
|
json.message = null;
|
|
json.warning = null;
|
|
json.toaster = null;
|
|
if (json.success) {
|
|
if (afterAction) afterAction(json);
|
|
}
|
|
}
|
|
};
|
|
|
|
function McltCallbackAndThenAlways(afterAction) {
|
|
return function(json, textStatus) {
|
|
if (json.message) alert(json.message);
|
|
if (json.warning) alert(json.warning);
|
|
if (json.toaster) jqToast(json.toaster);
|
|
json.message = null;
|
|
json.warning = null;
|
|
json.toaster = null;
|
|
if (afterAction) afterAction(json);
|
|
}
|
|
};
|
|
|
|
function jqToast(msg) {
|
|
var $toaster = $(`
|
|
<div class="toast align-items-center" role="alert" aria-live="assertive" aria-atomic="true">
|
|
<div class="d-flex">
|
|
<div class="toast-body">
|
|
${msg}
|
|
</div>
|
|
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
`).appendTo("body");
|
|
$toaster.on("hidden.bs.toast", function () { $(this).remove(); });
|
|
var toaster = new bootstrap.Toast($toaster);
|
|
toaster.show();
|
|
}
|
|
|
|
var McltCallbackSaved = McltCallbackAndThen(function(json) {
|
|
if (json.success)
|
|
jqToast(L("lcl_mobile_data_saved"));
|
|
});
|
|
|
|
var McltCallbackRefresh = McltCallbackAndThen(function(json) {
|
|
window.location.href = window.location.href;
|
|
});
|
|
|
|
var McltCallbackClose = McltCallbackAndThen(function(json) {
|
|
window.history.back(1);
|
|
});
|
|
|
|
var McltCallbackHome = McltCallbackAndThen(function(json) {
|
|
// window.history.back(1); doet geen refresh als je bijvoorbeeld net een reservering hebt verwijderd
|
|
window.location.href = rooturl + "/appl/pda/facilitor.asp";
|
|
});
|
|
|
|
var mobile = {
|
|
button: {
|
|
click: async function(evt, btn) {
|
|
FcltMgr.stopPropagation(evt);
|
|
|
|
if (btn.getAttribute("singlepress") && $(btn).hasClass("btn_disabled")) { // FcltMgr.alert("Heb geduld");
|
|
return;
|
|
}
|
|
if (btn.getAttribute("singlepress")) {
|
|
mobile.button.disable(btn);
|
|
}
|
|
var elem = btn.getAttribute("mobClick");
|
|
|
|
// window.fcltevent = evt;
|
|
var result = eval(elem);
|
|
if (typeof result === "object" && result instanceof Promise) {
|
|
result = await result;
|
|
}
|
|
// Dit lijkt erg onzinning (we zitten binnen mobile) maar soms als
|
|
// een scherm/dialoog net gesloten is door de action van de button
|
|
// blijkt de code toch nog hier te komen terwijl mobile weg is
|
|
if (typeof mobile == "undefined")
|
|
return;
|
|
|
|
if (result === false) {
|
|
mobile.button.enable(btn);
|
|
}
|
|
|
|
},
|
|
disable: function(btn) {
|
|
if (!btn || btn.tagName != 'A')
|
|
return; // not a mobile button
|
|
|
|
$(btn).toggleClass("btn_disabled", true)
|
|
.removeClass("btn_enabled");
|
|
},
|
|
enable: function(btn) {
|
|
if (!btn || btn.tagName != 'A')
|
|
return; // not a mobile button
|
|
|
|
$(btn).toggleClass("btn_enabled", true)
|
|
.removeClass("btn_disabled");
|
|
}
|
|
},
|
|
changePage: function _changePage(id) {
|
|
if (id) {
|
|
$(".page.show").removeClass("show");
|
|
location.hash = "#" + id;
|
|
} else { // Back
|
|
if (location.hash) {
|
|
$(".page:first").addClass("show");
|
|
location.hash = "";
|
|
} else {
|
|
history.back(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var $signatureButton;
|
|
var save_url;
|
|
function onBijlagenMobile(formurl /* protected */, saveUrl /* protected */, multi, objButton) {
|
|
save_url = saveUrl; /* Global voor uploadDone() */
|
|
$signatureButton = $(objButton); /* Global voor uploadDone() */
|
|
$.get(formurl, {}, function (data) { // Levert een HTML segment op; een <script> en een <div>
|
|
$("#form-signature").html(data).trigger("create"); // Zet dat in de bestaande hash-pagina
|
|
mobile.changePage("page-signature"); // En ga naar die pagina
|
|
});
|
|
}
|
|
|
|
// make filename safe for show
|
|
function safeFilename(s) {
|
|
return s.replace(/[\x00-\x1F|\/|\\|\*|\%\<\>\"\:\;\?\|\+]+/g, "_");
|
|
}
|
|
// remove element of deleted file
|
|
function removeElement(element) {
|
|
return function(json) {
|
|
let $bijlageButton = element.closest(".attachments_form").find(".add_attachment > [role=button][nBijlagen]");
|
|
if ($bijlageButton.length) {
|
|
$bijlageButton.attr("nBijlagen", parseInt($bijlageButton.attr("nBijlagen") || 0, 10) - 1);
|
|
}
|
|
element.remove();
|
|
if (json.toaster) {
|
|
jqToast(json.toaster);
|
|
}
|
|
}
|
|
};
|
|
// delete flex-attachment
|
|
function DeleteFile(fname, safeDeleteurl, element) {
|
|
FcltMgr.confirm(L("lcl_delete") + " " + safeFilename(fname) + "?", function() {
|
|
var data = {};
|
|
protectRequest.dataToken(data);
|
|
$.post("../shared/" + safeDeleteurl,
|
|
data,
|
|
McltCallbackAndThen(removeElement(element))
|
|
);
|
|
});
|
|
}
|
|
|
|
function disable(btn) {
|
|
$(btn).attr("onclick", "return false;")
|
|
.toggleClass("btn-disabled", true)
|
|
.removeClass("btn-enabled");
|
|
}
|
|
|
|
function toTouch() {
|
|
window.localStorage.setItem("interface", "touch");
|
|
parent.location.href = "../../default.asp?interface=touch";
|
|
}
|
|
|
|
function toDesktop() {
|
|
window.localStorage.setItem("interface", "desktop");
|
|
parent.location.href = "../../default.asp?interface=desktop";
|
|
} |