Files
Facilitor/APPL/Localscripts/FcltJquery.js
Jos Groot Lipman e62de953f5 Merge 2017.3 Gold D patches
svn path=/Website/trunk/; revision=37896
2018-05-15 09:44:44 +00:00

615 lines
23 KiB
JavaScript

/*
$Revision$
$Id$
File: FcltJquery.js
Description: Generieke functies die bij jquery wordt gebruikt.
Parameters:
Context: Bestand wordt gelijktijdig geinclude met jquery.js in Shared/header.inc (Requires plugin)
Note:
*/
// Let op: afterAction wordt alleen uitgevoerd als json.success gezet
function FcltCallbackAndThen(afterAction)
{
return function (json, textStatus)
{
if (json.message) FcltMgr.alert(json.message);
if (json.warning) FcltMgr.alert(json.warning);
if (json.toaster) FcltMgr.topmanager().window.$.toast({ text: json.toaster, icon: "success", position : 'top-center', loaderBg: '#fff'});
json.message = null;
json.warning = null;
json.toaster = null;
if (json.success)
{
if (afterAction) afterAction(json);
}
}
};
function FcltCallbackAndThenAlways(afterAction)
{
return function (json, textStatus)
{
if (json.message) FcltMgr.alert(json.message);
if (json.warning) FcltMgr.alert(json.warning);
if (json.toaster) FcltMgr.topmanager().window.$.toast({ text: json.toaster, icon: "success", position : 'top-center', loaderBg: '#fff'});
json.message = null;
json.warning = null;
json.toaster = null;
if (afterAction) afterAction(json);
}
};
var FcltCallback = FcltCallbackAndThen(null);
var FcltCallbackRefresh = FcltCallbackAndThen(function ()
{
FcltMgr.reload();
});
var FcltCallbackClose = FcltCallbackAndThen(function (json)
{
json.close = true;
FcltMgr.closeDetail(window, json);
});
var FcltCallbackDirtyLine = FcltCallbackAndThen(function (json)
{
// Bestaat json.key uit 1 of meerdere keys?
if (json.key.indexOf(",") >= 0)
{
var key = json.key.split(",");
for (var i = 0; i < key.length; i++)
{
$("#row" + key[i]).addClass('dirty');
}
}
else
$("#row" + json.key).addClass('dirty');
});
// Roep met Ajax syncroon(!) een asp bestand aan en lever de JSON data op.
function FcltSyncgetJSON(url, data)
{
var globalData;
jQuery.ajax({ type: "GET",
url: url,
async: false,
data: data,
dataType: "json",
success: function (data, textStatus) { globalData = data; globalData.textStatus = textStatus; }
});
if (globalData && globalData.warning)
FcltMgr.alert(globalData.warning);
if (globalData && globalData.error)
FcltMgr.alert(globalData.error);
if (globalData && globalData.toaster)
FcltMgr.topmanager().window.$.toast({ text: globalData.toaster, icon: "success", position : 'top-center', loaderBg: '#fff'});;
return globalData;
}
function FcltToast(msg, type, position, loaderBg)
{
if (msg == null || msg == "")
return;
var icon;
switch(type)
{
case 0: icon = "success"; break;
case 1: icon = "error"; break;
case 2: icon = "info"; break;
case 3: icon = "warning"; break;
default: icon = "success";
}
position = position || "top-center";
loaderBg = loaderBg || "#fff";
FcltMgr.topmanager().window.$.toast({ text: msg, icon: icon, position: position, loaderBg: loaderBg });;
}
// Handig, komt heel veel voor
function gen_cancel()
{
FcltMgr.closeDetail(window, { cancel: true } );
}
var ajaxBusy = [];
// TODO Alleen als Logging aan?
$(document).ajaxError(function(XMLHttpRequest,textStatus, errorThrown)
{
if (XMLHttpRequest.responseText.match(/^FCLTFriendly:/)) // Friendly tekst uit shared/500_error.asp
{
FcltMgr.alert(XMLHttpRequest.responseText.substring(13));
}
else if (XMLHttpRequest.responseText.match(/^FCLTExpired:/)) // Expired tekst uit common.inc
{
if (FcltMgr.getData('expired'))
FcltMgr.getData('expired')();
else
FcltMgr.alert(XMLHttpRequest.responseText.substring(12));
}
else
{
if (XMLHttpRequest.status != 0)
{
if (XMLHttpRequest.responseJSON && "error" in XMLHttpRequest.responseJSON)
var errtxt = XMLHttpRequest.responseJSON.error.message; // een api2.error(400, "Tekst");
else
errtxt = "JQuery Ajax Error: " + textStatus
+ "\n" + XMLHttpRequest.status + ": " + XMLHttpRequest.statusText
+ (errorThrown && errorThrown != XMLHttpRequest.statusText? "\n" + errorThrown:"")
+ "\n\n" + this.type + " " + this.url;
FcltMgr.alert(errtxt
+ "\n\n" + new Date().toLocaleString());
}
}
});
$(document).ajaxSend(function (event, xhr, options) {
if (options.type.toUpperCase() === "POST")
{
var $body = $("body");
var ajaxSend = setTimeout(function () {
if (window.location.href.match(/empty\.asp|empty\.html/ig))
{
if (!$body.find("div.busyloading").length)
{
var w = Math.max(0, $(window).width() - 62);
$body.prepend("<div style='left:"+(w/2)+"px' class='busyloading'><i class='fa fa-spinner fa-pulse fa-4x fa-fw'></i></div>");
}
}
else if (!$body.find("div.busyoverlay").length)
{
var wrapper = "<div class='busyoverlay'></div>";
$body.contents().wrap(wrapper);
}
}, 500);
window.ajaxBusy.push(ajaxSend);
ajaxSend = setTimeout(function () {
if (!$body.find("div.busyloading").length)
{
var w = Math.max(0, $(window).width() - 62);
$body.prepend("<div style='left:"+(w/2)+"px' class='busyloading'><i class='fa fa-spinner fa-pulse fa-4x fa-fw'></i></div>");
}
}, 2000);
window.ajaxBusy.push(ajaxSend);
}
}).ajaxComplete(function (event, xhr, options) {
if (options.type.toUpperCase() === "POST")
{
for (var i = 0; i < window.ajaxBusy.length; i++) {
clearTimeout(window.ajaxBusy[i]);
}
if ($("div.busyoverlay").length)
$("div.busyoverlay").contents().unwrap();
$(".busyloading").remove();
}
});
// Experiment:
// Ctrl+W sluit onze eigen tabjes ipv browser tabjes?
// TODO: eigenlijk via FcltMgr._pageManager._closeTab(this)? Of juist niet?
// Je kunt nu ook je portal tabje sluiten. Is niet de bedoeling
//$(window).keydown(function(event)
//{
// if (FcltMgr && event.ctrlKey && event.keyCode == 87) // ctrl+W
// {
// FcltMgr.closeDetail();
// event.preventDefault(); // Niet de *browser* tab
// }
// });
// FIX FSN#22060 charset encoding probleem met $.getJSON en Ajax
// Mochten we ooit op utf8 overstappen dan kan dit er waarschijnlijk uit.
// http://forum.jquery.com/topic/serialize-problem-with-latin-1-iso-8859-1-and-solution
var myEncode = function (s)
{
return unescape(encodeURIComponent(escape(s))).replace(/\+/g, "%2B");
}
jQuery.extend({
param: function( a ) {
var s = [];
// If an array was passed in, assume that it is an array
// of form elements
if ( a.constructor == Array || a.jquery ){
// Serialize the form elements
jQuery.each( a, function(){
s.push(myEncode(this.name) + "=" + myEncode(this.value));
});
}
// Otherwise, assume that it's an object of key/value pairs
else{
// Serialize the key/values
for ( var j in a )
// If the value is an array then the key names need to be repeated
if ( a[j] && a[j].constructor == Array )
jQuery.each( a[j], function(){
s.push(myEncode(j) + "=" + myEncode(this));
});
else
s.push(myEncode(j) + "=" + myEncode(a[j]));
}
// Return the resulting serialization
return s.join("&").replace(/ /g, "+");
},
serialize: function() {
return this.param(this.serializeArray());
}
});
// Voormalig jquery.autogrow-textarea.js
(function($) {
/*
* Auto-growing textareas; technique ripped from Facebook
* JGL: modified shadow width ook goed doen als textarea (nog) invisible
* JGL: modified with delayedUpdate
*/
$.fn.autogrow = function(options) {
this.filter('textarea').each(function() {
var $this = $(this),
minHeight = $this.height(),
self = this;
var shadow = $('<div></div>').css({
position: 'absolute',
top: -10000,
left: -10000,
width: Math.max(0,$(this).width() - parseInt($this.css('paddingLeft')) - parseInt($this.css('paddingRight'))),
fontSize: $this.css('fontSize'),
fontFamily: $this.css('fontFamily'),
lineHeight: $this.css('lineHeight'),
resize: 'none'
}).appendTo(document.body);
var delayedUpdate = function() {
if (self.timerID) clearTimeout(self.timerID);
self.timerID = setTimeout( function () { update.apply(self) }, 250);
}
var update = function() {
if (self.timerID) clearTimeout(self.timerID);
var times = function(string, number) {
for (var i = 0, r = ''; i < number; i ++)
{
r += string;
}
return r;
};
var val = this.value.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/&/g, '&amp;')
.replace(/\n$/, '<br/>&nbsp;')
.replace(/\n/g, '<br/>')
.replace(/ {2,}/g, function(space) { return times('&nbsp;', space.length -1) + ' ' });
shadow.html(val);
shadow.css("width", Math.max(0,$(this).width() - parseInt($this.css('paddingLeft')) - parseInt($this.css('paddingRight'))));
var oldheight = parseInt($(this).css('height'));
var newheight = Math.max(shadow.height() + 20, minHeight);
if (oldheight != newheight)
{
$(this).css('height', newheight);
FcltMgr.resized(window);
}
/* Experimentele max-lengte indicatie onder label
var len = this.value.length;
var maxlen = parseInt(this.getAttribute("maxlength"), 10)||4000;
var $lbl = $("label[for="+ this.name +"]");
$lbl.find("div").remove();
if ($lbl.length && len > maxlen * (90/100))
{
if (len > maxlen)
$lbl.append("<div style='color:red;font-size:0.9em;'>Te lang.<br>Maximum is {0}, huidig is {1}</div>".format(maxlen, len));
else
$lbl.append("<div style='color:blue;font-size:0.9em'>{1}/{0} karakters</div>".format(maxlen, len));
}
*/
}
$(this).change(delayedUpdate).keyup(delayedUpdate).keydown(delayedUpdate).blur(update);
update.apply(this);
});
return this;
}
})(jQuery);
jQuery.fn.filterByText = function(textbox, selectSingleMatch) {
return this.each(function() {
var select = this;
var options = [];
$(select).find('option').each(function() {
options.push(this);
});
$(select).data('options', options);
$(textbox).bind('change keyup', function() {
var options = $(select).empty().scrollTop(0).data('options');
var search = $.trim($(this).val()).toUpperCase();
$.each(options, function(i) {
var option = options[i];
if($(option).text().toUpperCase().indexOf(search) > -1) {
$(select).append(option);
}
});
if (selectSingleMatch === true &&
$(select).children().length === 1) {
$(select).children().get(0).selected = true;
$(select).children().trigger("change");
}
});
});
};
// Add a clickable sign after a select element that when clicked
// toggles the multiple attribute on the select box
(function($){
$( document ).on('click', '.multi_select_toggle', function(e){
e.stopPropagation();
var sel_id = $(this).attr("fcltfor");
var selector = $('select#' + sel_id);
if (selector.length && selector[0].className.match(/^ui-/))
return; // Afblijven van jQuery calendar jaar listboxje
var old = selector.attr('multiple');
selector.attr('multiple', !old);
selector.attr('size', old?1:Math.min(selector.find("option").length, 8));
$(e.target).html(old?'&raquo;':'&laquo;');
FcltMgr.resized();
})
$.fn.extend({
multiSelectToggle : function(options){
//Settings list and the default values
var defaults = {
label: '&raquo;'
};
var options = $.extend(defaults, options);
return this.each(function() {
var lbl = $("<span fcltfor='" + this.id + "' class='multi_select_toggle' />").html(options.label);
var div = $('<div />').addClass('multitoggle'); // deze div schuiven we 20px naar links
$(this).wrap(div);
$(this).before(lbl);
});
}
});
$(function () {
$('select[fcltmulti=1]').multiSelectToggle();
});
})(jQuery);
function fcltPrompt(title, defval, fnSuccess, params)
{
params = params || "";
$('<div></div>').appendTo('body')
.html('<div>' + (params.hint||"") + '</div>'
+ "<input type='text' id='fcltPrompt' class='fld" + (params.required ? " required" : "" ) + "'"
+ " value='" + defval + "'"
+ (params.maxlength ? " maxlength="+params.maxlength : "" )
+"><br>"
+ "<label for='fcltPrompt_radio_T'><input type='radio' name='fcltTabs' id='fcltPrompt_radio_T' value='T' checked>"+params.data.textoptionT+"</label><br>"
+ "<label for='fcltPrompt_radio_M'><input type='radio' name='fcltTabs' id='fcltPrompt_radio_M' value='M'>"+params.data.textoptionM+"</label><br>"
)
.dialog({
modal: true,
title: title,
zIndex: 10000,
autoOpen: true,
width: 'auto',
resizable: false,
buttons: [
{
text: L("lcl_submit"),
click: function () {
if ($.trim($("#fcltPrompt").val()) == "")
{
$("#fcltPrompt").addClass("missing");
FcltMgr.alert(L("lcl_shared_validator_missing"));
}
else
{
params.data.taboption = $("input[name=fcltTabs]:checked").val();
fnSuccess($("#fcltPrompt").val(), params.data);
$(this).dialog("close");
}
}
},
{
text: L("lcl_cancel"),
click: function () {
$(this).dialog("close");
}
}
],
close: function (event, ui) {
$(this).remove();
}
});
}
function do_fcltfilters()
{ // Filters van opgeslagen tabjes verwerken
if (window.fcltfilters && window.iface && window.fcltfilters != "null")
{
iface.stringToForm(window.fcltfilters, $('form[name=u2]'));
var formObject = JSON.parse(window.fcltfilters);
if ("columns" in formObject) // Dit is het hidden veld wat normaal meegesubmit wordt
{ // Werk de interface checkboxjes ook bij
var colarr = formObject.columns.split(",");
var grparr = formObject.groupby.split(",");
$("#scfcolpicker tr").each(function()
{
if (!this.id)
return;
var pos = $.inArray(this.id, colarr);
if (pos > -1)
{
$(this).find("input[type=checkbox]").prop("checked", true);
var selectgroup = $(this).find("select");
selectgroup.val(grparr[pos]);
}
else
{
$(this).find("input[type=checkbox]").prop("checked", false);
}
});
// En nu de volgorde ook nog aanpassen
$("#scfcolpicker tbody tr").sort(function(a,b) {
var $a = $("#scfcolpicker tbody tr#" + a.id);
var $b = $("#scfcolpicker tbody tr#" + b.id);
var pos1 = (!$a.find("input[type=checkbox]").prop("checked")?(1000+$a.index()):$.inArray(a.id, colarr));
var pos2 = (!$b.find("input[type=checkbox]").prop("checked")?(1000+$b.index()):$.inArray(b.id, colarr));
return pos1 - pos2;
}).appendTo('#scfcolpicker tbody');
}
// Voeg ook de gepinde filters toe die initieel optioneel zijn
if (typeof addFilter == "function")
{
$.each(formObject, function(key, val) {
$("div#search>div>select>option[value="+key+"]").eq(0).each(function () {
$(this).prop("selected", true);
addFilter($(this).parent("select"));
});
});
}
if ("scf_pivot" in formObject) // Dit is het hidden veld wat normaal meegesubmit wordt
{
$("#chk_pivot").prop("checked", formObject.scf_pivot == 1)
}
}
if (window.advfilters && window.iface && window.advfilters != "null" && typeof myModal === "function")
{
myModal(JSON.parse(window.advfilters));
}
if (window.afterfiltersready)
{
window.afterfiltersready.call();
}
}
function updateTableHeaders() {
$("div.divrstable").each(function() {
var $originalHeaderRow = $(".tableFloatingHeaderOriginal", this);
var $floatingHeaderRow = $(".tableFloatingHeader", this);
// Copy row width from whole table
// $floatingHeaderRow.css("width", $originalHeaderRow.width()); // FSN#51558 disabled (superfluous?)
// Copy cell widths from original header cells
var $originalHeaderRowChildren = $originalHeaderRow.find("TH, TD");
$floatingHeaderRow.find("TH, TD").each(function(index) {
// Vanaf jQuery 3.3.1 (2018.1+) is .width() een non-integer en kunnen we width() gebruiken:
// var cellWidth = $originalHeaderRowChildren.eq(index).width();
// PLAT#53099: daarvoor (2017.3-) moeten we even onhandige fix gebruiken:
var cellWidth = window.getComputedStyle($originalHeaderRowChildren.eq(index)[0]).width;
$(this).css("width", cellWidth);
});
var insideFrame = $(this).offset();
var outsideFrame = $(window.frameElement).offset();
var scrollTop = $(window.parent).scrollTop() + $(window).scrollTop();
var offset = 0;
if (insideFrame) offset += insideFrame.top;
if (outsideFrame && $(window.parent).scrollTop() != 0) offset += outsideFrame.top;
// if browser is IE then correct the top positioning
var IEcorr = (/*@cc_on!@*/false)?-4:0;
if ((scrollTop > offset) && (scrollTop < offset + $(this).height()))
{
$originalHeaderRow.css("visibility", "visible");
$floatingHeaderRow.css("top", (IEcorr + Math.min(scrollTop - offset, $(this).height() - $floatingHeaderRow.height())) + "px");
}
else
{
$originalHeaderRow.css("visibility", "hidden");
$floatingHeaderRow.css("top", "0px");
}
});
}
$(function() {
setTimeout( do_fcltfilters, 250); // Heel klein beetje uitstellen zodat eventuele
// suggests geinitialiseerd zijn
$("table:not(.tab_cat_sched) > thead").each(function() {
$(this).parent("table").wrap("<div class=\"divrstable\" style=\"position:relative\"></div>");
var $originalHeaderRow = $(this);
var $clonedHeaderRow = $originalHeaderRow.clone(true)
$originalHeaderRow.before($clonedHeaderRow);
// if browser is IE then correct the left margin
var IEcorr = (/*@cc_on!@*/false)?-2:1;
$clonedHeaderRow.addClass("tableFloatingHeader");
$clonedHeaderRow.css("position", "absolute");
$clonedHeaderRow.css("top", "0px");
$clonedHeaderRow.css("left", IEcorr);
$clonedHeaderRow.css("opacity", "0.90");
$originalHeaderRow.addClass("tableFloatingHeaderOriginal");
});
$(window).on("scroll", updateTableHeaders);
$(window).on("resize", updateTableHeaders);
$(window).on("load", updateTableHeaders);
try {
$(window.parent).on("scroll", updateTableHeaders);
$(window.parent).on("resize", updateTableHeaders);
} catch (e)
{
// in een frame?
}
$("div.collapsed").on("click", updateTableHeaders);
$("#autofilter").on("keyup", updateTableHeaders);
// Anders geheugenlek
$(window).on("unload", function ()
{
try {
$(window.parent).off("scroll", updateTableHeaders);
$(window.parent).off("resize", updateTableHeaders);
} catch (e)
{
// in een frame?
}
});
updateTableHeaders();
});