/* $Revision$ $Id$ File: console.js Description: Generic include file for consoles for Facilitor */ var targets = {}, models = {}, day_in_ms = 86400000, language = "EN", windowObjectReference, environment = "production"; /* System constants */ var dataTables_i18n = { NL: { "sProcessing": "Bezig...", "sLengthMenu": "_MENU_ resultaten weergeven", "sZeroRecords": "Geen resultaten gevonden", "sInfo": "_START_ tot _END_ van _TOTAL_ resultaten", "sInfoEmpty": "Geen resultaten om weer te geven", "sInfoFiltered": " (gefilterd uit _MAX_ resultaten)", "sInfoPostFix": "", "sSearch": "Zoeken:", "sEmptyTable": "Geen resultaten aanwezig in de tabel", "sInfoThousands": ".", "sLoadingRecords": "Een moment geduld aub - bezig met laden...", "oPaginate": { "sFirst": "Eerste", "sLast": "Laatste", "sNext": "Volgende", "sPrevious": "Vorige" }, "oAria": { "sSortAscending": ": activeer om kolom oplopend te sorteren", "sSortDescending": ": activeer om kolom aflopend te sorteren" } }, DE: { "sEmptyTable": "Keine Daten in der Tabelle vorhanden", "sInfo": "_START_ bis _END_ von _TOTAL_ Einträgen", "sInfoEmpty": "Keine Daten vorhanden", "sInfoFiltered": "(gefiltert von _MAX_ Einträgen)", "sInfoPostFix": "", "sInfoThousands": ".", "sLengthMenu": "_MENU_ Einträge anzeigen", "sLoadingRecords": "Wird geladen ..", "sProcessing": "Bitte warten ..", "sSearch": "Suchen", "sZeroRecords": "Keine Einträge vorhanden", "oPaginate": { "sFirst": "Erste", "sPrevious": "Zurück", "sNext": "Nächste", "sLast": "Letzte" }, "oAria": { "sSortAscending": ": aktivieren, um Spalte aufsteigend zu sortieren", "sSortDescending": ": aktivieren, um Spalte absteigend zu sortieren" }, "select": { "rows": { "_": "%d Zeilen ausgewählt", "0": "", "1": "1 Zeile ausgewählt" } }, "buttons": { "print": "Drucken", "colvis": "Spalten", "copy": "Kopieren", "copyTitle": "In Zwischenablage kopieren", "copyKeys": "Taste ctrl oder \u2318 + C um Tabelle
in Zwischenspeicher zu kopieren.

Um abzubrechen die Nachricht anklicken oder Escape drücken.", "copySuccess": { "_": "%d Zeilen kopiert", "1": "1 Zeile kopiert" }, "pageLength": { "-1": "Zeige alle Zeilen", "_": "Zeige %d Zeilen" } } }, EN: { "sEmptyTable": "No data available in table", "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", "sInfoEmpty": "Showing 0 to 0 of 0 entries", "sInfoFiltered": "(filtered from _MAX_ total entries)", "sInfoPostFix": "", "sInfoThousands": ",", "sLengthMenu": "Show _MENU_ entries", "sLoadingRecords": "Loading...", "sProcessing": "Processing...", "sSearch": "Search:", "sZeroRecords": "No matching records found", "oPaginate": { "sFirst": "First", "sLast": "Last", "sNext": "Next", "sPrevious": "Previous" }, "oAria": { "sSortAscending": ": activate to sort column ascending", "sSortDescending": ": activate to sort column descending" } }, FR: { "sEmptyTable": "Aucune donnée disponible dans le tableau", "sInfo": "Affichage de l'élément _START_ à _END_ sur _TOTAL_ éléments", "sInfoEmpty": "Affichage de l'élément 0 à 0 sur 0 élément", "sInfoFiltered": "(filtré à partir de _MAX_ éléments au total)", "sInfoPostFix": "", "sInfoThousands": ",", "sLengthMenu": "Afficher _MENU_ éléments", "sLoadingRecords": "Chargement...", "sProcessing": "Traitement...", "sSearch": "Rechercher :", "sZeroRecords": "Aucun élément correspondant trouvé", "oPaginate": { "sFirst": "Premier", "sLast": "Dernier", "sNext": "Suivant", "sPrevious": "Précédent" }, "oAria": { "sSortAscending": ": activer pour trier la colonne par ordre croissant", "sSortDescending": ": activer pour trier la colonne par ordre décroissant" }, "select": { "rows": { "_": "%d lignes sélectionnées", "0": "Aucune ligne sélectionnée", "1": "1 ligne sélectionnée" } } } }; /* global functions */ // console messages for development support window.console.original_log = window.console.log; window.console.log = function (msg, force) { if (environment == "development" || force) { window.console.original_log(msg); } }; // return the data of a single object or of a row object (e.g. obj.data["issue"] or obj.data["issues"][row]) function rowInfo(obj, row) { "use strict"; return (obj.single ? obj.data[obj.table] : obj.data[obj.table][row]); } // return the value of a column function dataInfo(obj, row, column) { "use strict"; return rowInfo(obj, row)[column]; } // return a formatted column value according to the column_type function typeFormat(parms) { "use strict"; switch (parms.column_type) { case "datetime": if (parms.single) { // return the datevalue in case of a single object column return new Date(parms.value); } return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(parms.value)); // niet na een return break; case "date": if (parms.single) { // return the datevalue in case of a single object column return new Date(parms.value); } return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(new Date(parms.value)); // niet na een return break; case "integer": return parseInt(parms.value, 10); // niet na een return break; case "number": // return safe number return $.fn.dataTable.render.number().display(parms.value); // niet na een return break; default: // return safe text return $.fn.dataTable.render.text().display(parms.value); } } // return label of the column function columnType(obj, column) { "use strict"; // determine column_type from [ targets[target].columns[column].type ] or from [ models[model].field[column].type ] or from fallback value "text" return (obj.columns[column].type || (models[obj.url].fields[column] && models[obj.url].fields[column].type) || "text"); } // return label of the column function columnLabel(obj, column) { "use strict"; // determine label from [ models[model].field[column].label ] or else from [ target.columns[column].label ] or else from [ column name ] return ((models[obj.url].fields[column] && models[obj.url].fields[column].label) || obj.columns[column].label || column); } // return value of the column (single value or [column].name value) function columnValue(data) { "use strict"; // determine whether the value is an object with a { name: value } return (data && typeof data.name !== "undefined" ? data.name || "" : data || ""); } // return the formatted column value, independent of single object or row object function dataFormat(obj, row, column) { "use strict"; // get column value (as single value or as { id: xx, name: yy }) var data = dataInfo(obj, row, column); return typeFormat({ value: columnValue(data), column_type: columnType(obj, column), single: obj.single }); } // return combined server-data and targets[target]/models[model][column] information object function columnInfo(obj, row, column) { "use strict"; var data, column_label, column_data, column_type, column_valuemin, column_valuemax, column_recid; // get column value (as single value or as { id: xx, name: yy }) data = dataInfo(obj, row, column); // get column label column_label = columnLabel(obj, column); // get formatted column value column_data = dataFormat(obj, row, column); // get column_type column_type = columnType(obj, column); // determine minimum value (only for use in a progressbar) column_valuemin = (obj.columns[column].valuemin || 0); // determine maximum value (only for use in a progressbar) column_valuemax = (obj.columns[column].valuemax || 100); // determine record id in case the column is a foreign table value column_recid = (data && typeof data.id !== "undefined" ? parseInt(data.id, 10) : false); return { data: data, column_label: column_label, column_data: column_data, column_type: column_type, column_valuemin: column_valuemin, column_valuemax: column_valuemax, column_recid: column_recid }; } // return the column [ data-order ] value, used for ordering DataTable rows ([ date ] or [ datetime ] serial number only) function dataOrder(obj, row, column) { "use strict"; var column_type = columnType(obj, column), value, data = dataInfo(obj, row, column); if (obj.single) { value = ""; } else { value = columnValue(data); } switch (column_type) { case "datetime": case "date": return new Date(value).getTime(); // niet na een return break; default: return false; } } // return DataTable settings based on targets[target]columns function tColumnDefs(obj) { "use strict"; var defs = { language: dataTables_i18n[language], columnDefs: [] }, index = 0; $.each(obj.columns, function (key, value) { if (key !== "id") { if (value.hidden) { defs.columnDefs.push({ targets: [index], visible: false, searchable: true }); } index++; } }); console.log(defs); return defs; } // return tableHeader row function theadColumns(obj) { "use strict"; var thead = "", column; for (column in obj.columns) { if (column !== "id") { thead += '' + $.fn.dataTable.render.text().display(columnLabel(obj, column)) + ''; } } return thead; } // return tableBody rows function tbodyData(obj) { "use strict"; var tbody = "", row, column, order, col_info; for (row = 0; row < obj.data[obj.table].length; row += 1) { tbody += ''; for (column in obj.columns) { if (column !== "id") { col_info = columnInfo(obj, row, column); tbody += '' + col_info.column_data + ''; } } tbody += ''; } return tbody; } // return formdata (single record form) function formData(obj) { "use strict"; var target_selector = targets[obj.target].selector; var formbody = "", column, column_id, col_info; for (column in obj.columns) { if (column !== "id" && !(targets[obj.target].columns[column].hidden || false)) { column_id = target_selector + "-" + column; col_info = columnInfo(obj, undefined, column); col_info.column_id = column_id; col_info.single = obj.single; formbody += '
' + '' + new Field(col_info).render() + '
'; } } return formbody; } // return filterdata (buttons for filtering DataTable data) function filterData(obj) { "use strict"; // var container_selector = targets[obj.target].selector; var formbody = "", row, column, col_info, btn_size_class = targets[obj.target].btn_size_class, btn_has_icon = targets[obj.target].btn_has_icon, icon_column = targets[obj.target].icon_column, color_column = targets[obj.target].color_column, icon; for (row = 0; row < obj.data[obj.table].length; row += 1) { if (icon_column && !!obj.data[obj.table][row][icon_column] && obj.data[obj.table][row][icon_column].substring(0, 3) == "fa-") { icon = obj.data[obj.table][row][icon_column]; } else { icon = "fa-tag"; } formbody += ''; } return formbody; } // populate the target (datatable, form or filter) function populate(obj) { "use strict"; // the model needs to be present (loaded) for correct workings, except for reports (graphs) if (targets[obj.target].report || models[obj.url].id) { var $this = $("#" + targets[obj.target].selector), h2; obj.columns = obj.columns || targets[obj.target].columns; console.log("populate: " + obj.target); obj.table = obj.single || obj.url; h2 = '

' + (lcl[language][targets[obj.target].title] || obj.table) + '

'; obj.single = obj.single || false; // render single record form html if (obj.single) { var fdata = formData(obj); $this.html(h2 + '
' + fdata + '
' + new Customfields(obj).render()); // render buttons from rows for filter form html } else if (targets[obj.target].filter) { var fdata = filterData(obj); $this.html(h2 + '
' + fdata + '
'); // render h2 header only for report } else if (targets[obj.target].report) { $this.html(h2); // render table html } else { var $this, thead, tbody, table; thead = '' + theadColumns(obj) + ''; tbody = '' + tbodyData(obj) + ''; table = '' + thead + tbody + '
'; $this.html(h2 + table); } // set trigger(s) if available if (targets[obj.target].trigger) { $(targets[obj.target].trigger_selector, $this).off().on(targets[obj.target].events, targets[obj.target].trigger); } // run ready function if available if (targets[obj.target].ready) { targets[obj.target].ready(obj); } } else { console.log("model " + obj.url + "not yet present!"); // retry the populate until the model is present setTimeout(function () { populate(obj); }, 100); } } // save the model definition in models function setModel(obj) { "use strict"; if (obj.model) { models[obj.model] = obj.data; obj.data.fields.forEach(function (field) { models[obj.model].fields[field.id] = field; }); } } // get api2 data through ajax function api2(obj) { "use strict"; if (obj.target) { obj.filter = (Object.keys(targets[obj.target].columns).length ? (obj.filter ? obj.filter + "&" : "?") + "fields=" + Object.keys(targets[obj.target].columns).join(",") : obj.filter || ""); } var ajaxHdl = $.ajax({ url: settings.facilitor_url + "api2/" + obj.url + (obj.filter || ""), dataType: "json", success: function (data, textStatus, jqXHR) { console.log("Ajax success start: " + (obj.target || obj.model)); obj.data = data; if (obj.model) { setModel(obj); } else { populate(obj); } console.log(data); console.log("Ajax success stop: " + (obj.target || obj.model)); }, complete: function (jqXHR, textStatus) { console.log("Ajax complete: " + (obj.target || obj.model)); } }); console.log({ target: (obj.target || "model_" + obj.model), ajaxHdl: ajaxHdl }); } // google maps initialisation var map, marker, geocoder, panorama, selector; // google maps interface to set a location and a marker function codeAddress(address) { "use strict"; geocoder.geocode({ 'address': address }, function (results, status) { if (status == 'OK') { map.setCenter(results[0].geometry.location); marker = new google.maps.Marker({ map: map, position: results[0].geometry.location }); panorama.setPosition(results[0].geometry.location); panorama.addListener('position_changed', function () { if (!panorama.getVisible()) { panorama.setVisible(true); } }); $("#" + selector).closest(".row").attr("hidden", false); } else { alert('Geocode was not successful for the following reason: ' + status); } }); } // google maps initialisation and first location set to Facilitor function initAutocomplete(mapselector, viewselector, location) { "use strict"; selector = mapselector; // The location of Facilitor var facilitor = location || { lat: 52.216670, lng: 6.946060 }; // map part map = new google.maps.Map( document.getElementById(mapselector), { zoom: 13, center: facilitor, mapTypeId: 'roadmap' }); marker = new google.maps.Marker({ map: map, position: facilitor }); // streetview part panorama = new google.maps.StreetViewPanorama( document.getElementById(viewselector), { position: facilitor, panControl: false, addressControl: false, pov: { heading: 34, pitch: 20 } }); map.setStreetView(panorama); geocoder = geocoder || new google.maps.Geocoder(); $("#" + mapselector).closest(".row").attr("hidden", !location); } /* settings and functions from refactoring of targets object */ var settings = { facilitor_url: "../../", btn_class: "btn-secundary", btn_text_class: "text-dark", btn_selected_class: "btn-success", btn_partial_class: "btn-success", btn_size_class: "col-sm-3", btn_has_icon: true, icon_column: false, color_column: false }; // set partial, full or no class on parent button dependent on the number of selected child buttons function setParentSelectedClass(parms) { "use strict"; var selected = $("button:visible." + settings.btn_selected_class + " div[name=" + parms.name + "][recid=" + parms.value + "]", parms.context).length; var present = $("button:visible div[name=" + parms.name + "][recid=" + parms.value + "]", parms.context).length; // reset classes to default var button = $("button[recid=" + parms.value + "]", parms.parent) .removeClass(settings.btn_selected_class + ' ' + settings.btn_partial_class) .addClass(settings.btn_class + ' ' + settings.btn_text_class) .css({ backgroundColor: "" }); // all childs are selected if (present == selected) { button .addClass(settings.btn_selected_class) .removeClass(settings.btn_class + ' ' + settings.btn_text_class) .css({ backgroundColor: (button.attr("color") ? button.attr("color") : "") }); // part of the childs are selected } else if (selected > 0) { button .addClass(settings.btn_selected_class + ' ' + settings.btn_partial_class) .removeClass(settings.btn_class + ' ' + settings.btn_text_class) .css({ backgroundColor: (button.attr("color") ? button.attr("color") : "") }); } return button; } // set full or no class on child buttons dependent on the parent button function setChildSelectedClass(parms) { "use strict"; var button; var items = $("button div[name=" + parms.name + "][recid=" + parms.$this.attr("recid") + "]", parms.parent); items .each( function () { button = $(this).closest("button"); button .removeClass(settings.btn_partial_class) .toggleClass(settings.btn_selected_class, parms.$this.hasClass(settings.btn_selected_class)) .toggleClass(settings.btn_class, !parms.$this.hasClass(settings.btn_selected_class)) .toggleClass(settings.btn_text_class, !parms.$this.hasClass(settings.btn_selected_class)) .css({ backgroundColor: (button.attr("color") && button.hasClass(settings.btn_selected_class) ? button.attr("color") : "") }); } ); return items; } // set color of child-buttons to color of parent-button when a child-button has no specific color of it's own function setChildrenColor(parms) { "use strict"; var $this, parent; var items = $("button:not([color]) div[name=" + parms.name + "]", parms.context); items .each( function () { $this = $(this); // parent button has a specific colour parent = $("button[recid=" + $this.attr("recid") + "]", parms.parent); if (parent.length) { $this.closest("button") .attr("color", parent.attr("color")) .css({ backgroundColor: parent.attr("color") }); } } ); } // save recid's of selected buttons in [ context ] function saveSelectedbuttonIds(parms) { "use strict"; targets[parms.target].selected_ids = []; $("button." + settings.btn_selected_class, parms.context).each(function () { targets[parms.target].selected_ids.push($(this).attr("recid")); }); } // save recid's used in table function saveUsedtabledataIds(parms) { "use strict"; var index, recid, key_count = {}; targets[parms.target].selected_ids = []; $("td[name=" + parms.name + "]", parms.context).each(function () { recid = $(this).attr("recid"); key_count[recid] = key_count[recid] ? key_count[recid] + 1 : 1; index = targets[parms.target].selected_ids.indexOf(recid); if (index === -1) { targets[parms.target].selected_ids.push(recid); } }); return key_count; } // set classes for button dependent on button_selected_class function setButtonClasses(parms) { "use strict"; parms.$this.removeClass(settings.btn_selected_class == settings.btn_partial_class ? "" : settings.btn_partial_class) .toggleClass(settings.btn_selected_class) .toggleClass(settings.btn_class, !parms.$this.hasClass(settings.btn_selected_class)) .toggleClass(settings.btn_text_class, !parms.$this.hasClass(settings.btn_selected_class)) .css({ backgroundColor: (parms.$this.attr("color") && parms.$this.hasClass(settings.btn_selected_class) ? parms.$this.attr("color") : "") }); } // reset classes for all buttons function resetAllButtonClasses(parms) { "use strict"; $("button", parms.context) .removeClass(settings.btn_partial_class + ' ' + settings.btn_selected_class) .addClass(settings.btn_class + ' ' + settings.btn_text_class) .css({ backgroundColor: "" }); } // set hidden attr for buttons dependent on button_selected_class function setButtonHidden(parms) { "use strict"; $("button", parms.context) .attr("hidden", function () { $(this).attr("hidden", !$(this).hasClass(settings.btn_selected_class)) }); } // autoselect first row in case there is only 1 result function autoselectRow(parms) { "use strict"; // select (click) the first row if there is only 1 result if ($("tbody tr", "#" + targets[parms.target].selector).length == 1) { $("tbody tr:first", "#" + targets[parms.target].selector).click(); } } // redraw the table and select first row in case there is only 1 result function redrawTable(parms) { "use strict"; targets[parms.target].data_table.draw(); $("#" + targets[parms.target].selector).closest("div.card").resize(); autoselectRow(parms); } // resize innerHeight of target-card to innerHeight of base-card function resizeCard(targetselector, baseselector) { function _resizeCard() { console.log("resize " + targetselector); $("#" + targetselector).closest("div.card").innerHeight($("#" + baseselector).closest("div.card").innerHeight()); } return function _setTimeout() { setTimeout(_resizeCard, 100); } } /* Objects to be used for rendering dashboards */ // Object with render function to return field html (without label) function Field(parms) { "use strict"; var self = this, date, time; // prefix a string with a zero when string length < length to be used ( hour/minute/day/month fields ) var prefixZero = function (str, len) { return ("0" + str).slice(-len); }; this.single = parms.single; this.column_name = parms.column_name; this.column_type = parms.column_type; this.column_id = parms.column_id; this.column_data = typeFormat({ value: (parms.column_data || ""), column_type: parms.column_type, single: parms.single }); this.column_valuemin = parms.column_valuemin; this.column_valuemax = parms.column_valuemax; this.render = function () { switch (self.column_type) { case "progressbar": return '
' + '
' + '
'; // niet na een return break; case "check": return '
' + '' + '
'; // niet na een return break; case "textarea": return '
' + '' + '
'; // niet na een return break; case "date": date = self.column_data == "" ? "" : self.column_data.getFullYear().toString() + "-" + prefixZero((self.column_data.getMonth() + 1).toString(), 2) + "-" + prefixZero(self.column_data.getDate().toString(), 2); return '
' + '' + '
'; // niet na een return break; case "datetime": time = self.column_data == "" ? "" : prefixZero(self.column_data.getHours().toString(), 2) + ":" + prefixZero(self.column_data.getMinutes().toString(), 2); date = self.column_data == "" ? "" : self.column_data.getFullYear().toString() + "-" + prefixZero((self.column_data.getMonth() + 1).toString(), 2) + "-" + prefixZero(self.column_data.getDate().toString(), 2); return '
' + '' + '
' + '
' + '' + '
'; // niet na een return break; case "time": time = self.column_data == "" ? "" : prefixZero(self.column_data.getHours().toString(), 2) + ":" + prefixZero(self.column_data.getMinutes().toString(), 2); return '
' + '' + '
'; // niet na een return break; default: return '
' + '' + '
'; // niet na een return break; } } console.log(self); } // Object with render function to return label and customfield html function Customfield(parms) { "use strict"; var self = this; this.single = parms.single; this.column_name = parms.column_name; this.custom_field = parms.custom_field; this.selector = parms.selector; this.column_id = parms.selector + "-" + self.custom_field.propertyid; // translate customfield-type to model field-type this.custom_field_type = function () { switch (self.custom_field.type) { case "V": return "check"; case "D": return "date"; case "T": return "time"; case "N": return "number"; default: return "text"; } } this.render = function () { return '
' + '' + new Field({ single: self.single, column_name: self.column_name, column_id: self.column_id, column_type: self.custom_field_type(), column_data: self.custom_field.value }).render() + '
'; } console.log(self); } // Object with render function to return html for all customfields including labels function Customfields(parms) { "use strict"; var self = this; // sort customfields on sequence this.custom_fields = (parms.data[parms.table].custom_fields ? parms.data[parms.table].custom_fields.sort(function (a, b) { return (a.sequence > b.sequence ? 1 : -1) }) : []); this.single = parms.single; this.target = parms.target; this.table = parms.table; this.render = function () { var fields = "", custom_field; if (targets[self.target].show_custom_fields && self.custom_fields.length) { for (custom_field in self.custom_fields) { // only customfields other than type Q, L or M if (["Q", "L", "M"].indexOf(self.custom_fields[custom_field].type) == -1 && (targets[self.target].show_custom_field_when_empty || self.custom_fields[custom_field].value != null)) { fields += new Customfield({ single: self.single, column_name: custom_field, selector: targets[self.target].selector, custom_field: self.custom_fields[custom_field] }).render(); } } } return '
' + fields + '
'; } console.log(self); } // Object base for targets function Target(parms) { "use strict"; var self = this; var choose = function (first_choice, fallback_choice) { return (typeof first_choice != "undefined" ? first_choice : fallback_choice); }; this.title = parms.title || ""; this.selector = parms.selector; this.mode = parms.mode; this.columns = choose(parms.columns, {}); this.events = choose(parms.events, "click"); this.trigger = parms.trigger || false; this.ready = parms.ready || false; this.filter = parms.filter || false; this.report = parms.report || false; this.trigger_selector = (this.filter ? "button" : "table tbody tr"); this.btn_size_class = choose(parms.btn_size_class, settings.btn_size_class); this.btn_has_icon = choose(parms.btn_has_icon, true); this.icon_column = choose(parms.icon_column, settings.icon_column); this.color_column = choose(parms.color_column, settings.color_column); this.show_custom_fields = parms.show_custom_fields || false; this.show_custom_field_when_empty = parms.show_custom_field_when_empty || false; console.log(self); }