diff --git a/app/admin/ajax-sql.php b/app/admin/ajax-sql.php
index 1ae0253..dac3d00 100644
--- a/app/admin/ajax-sql.php
+++ b/app/admin/ajax-sql.php
@@ -7,12 +7,9 @@
}
$sql = trim(Request::val('sql'));
- if(
- !preg_match('/^SELECT\s+.*?\s+FROM\s+\S+/i', $sql)
- && !preg_match('/^SHOW\s+/i', $sql)
- ) {
+ if(!preg_match('/^\s*(SELECT\s+.*?\s+FROM\s+\S+|SHOW\s+)/is', $sql)) {
@header('HTTP/1.0 404 Not Found');
- die("Invalid query");
+ die('Invalid query');
}
// force a limit of 1000 to SELECT queries in case no limit specified
diff --git a/app/admin/incFunctions.php b/app/admin/incFunctions.php
index 12256bf..be19c66 100644
--- a/app/admin/incFunctions.php
+++ b/app/admin/incFunctions.php
@@ -87,7 +87,8 @@
########################################################################
function set_headers() {
@header('Content-Type: text/html; charset=' . datalist_db_encoding);
- @header('X-Frame-Options: SAMEORIGIN'); // prevent iframing by other sites to prevent clickjacking
+ // @header('X-Frame-Options: SAMEORIGIN'); // deprecated
+ @header("Content-Security-Policy: frame-ancestors 'self' " . application_url()); // prevent iframing by other sites to prevent clickjacking
}
########################################################################
function get_tables_info($skip_authentication = false) {
@@ -424,7 +425,13 @@ function logSlowQuery($statement, $duration) {
$statement = makeSafe(trim(preg_replace('/^\s+/m', ' ', $statement)));
$duration = floatval($duration);
$memberID = makeSafe(getLoggedMemberID());
- $uri = makeSafe($_SERVER['REQUEST_URI']);
+ $uri = $_SERVER['REQUEST_URI'];
+
+ // for 'admin/ajax-sql.php' strip sql and csrf_token params from uri
+ if(strpos($uri, 'admin/ajax-sql.php') !== false) {
+ $uri = stripParams($uri, ['sql', 'csrf_token']);
+ }
+ $uri = makeSafe($uri);
sql("INSERT INTO `appgini_query_log` SET
`statement`='$statement',
@@ -445,7 +452,13 @@ function logErrorQuery($statement, $error) {
$statement = makeSafe(trim(preg_replace('/^\s+/m', ' ', $statement)));
$error = makeSafe($error);
$memberID = makeSafe(getLoggedMemberID());
- $uri = makeSafe($_SERVER['REQUEST_URI']);
+ $uri = $_SERVER['REQUEST_URI'];
+
+ // for 'admin/ajax-sql.php' strip sql and csrf_token params from uri
+ if(strpos($uri, 'admin/ajax-sql.php') !== false) {
+ $uri = stripParams($uri, ['sql', 'csrf_token']);
+ }
+ $uri = makeSafe($uri);
sql("INSERT INTO `appgini_query_log` SET
`statement`='$statement',
@@ -455,6 +468,42 @@ function logErrorQuery($statement, $error) {
", $o);
}
+ ########################################################################
+ /**
+ * Strip specified parameters from a URL
+ * @param string $uri - the URL to strip parameters from, could be a full URL or just a URI
+ * @param array $paramsToRemove - an array of parameter names to remove
+ * @return string - the URL with specified parameters removed
+ */
+ function stripParams($uri, $paramsToRemove) {
+ // Parse the URL and its components
+ $parsedUrl = parse_url($uri);
+
+ // Parse the query string into an associative array
+ parse_str($parsedUrl['query'] ?? '', $queryParams);
+
+ // Remove specified parameters
+ foreach ($paramsToRemove as $param) {
+ unset($queryParams[$param]);
+ }
+
+ // Reconstruct the query string
+ $newQuery = http_build_query($queryParams);
+
+ // Reconstruct the URL
+ $newUrl = $parsedUrl['scheme'] ?? '';
+ if (!empty($newUrl)) {
+ $newUrl .= '://';
+ }
+ $newUrl .= $parsedUrl['host'] ?? '';
+ $newUrl .= $parsedUrl['path'] ?? '';
+ if (!empty($newQuery)) {
+ $newUrl .= '?' . $newQuery;
+ }
+ $newUrl .= $parsedUrl['fragment'] ?? '';
+
+ return $newUrl;
+ }
########################################################################
function createQueryLogTable() {
static $created = false;
@@ -1719,7 +1768,7 @@ function get_table_fields($tn = null, $include_internal_tables = false) {
'done' => "INT DEFAULT '0'",
],
'appgini_query_log' => [
- 'datetime' => "TIMESTAMP DEFAULT CURRENT_TIMESTAMP",
+ 'datetime' => "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP",
'statement' => "LONGTEXT",
'duration' => "DECIMAL(10,2) UNSIGNED DEFAULT '0.00'",
'error' => "TEXT",
diff --git a/app/admin/incHeader.php b/app/admin/incHeader.php
index 2751f68..3df7ec7 100644
--- a/app/admin/incHeader.php
+++ b/app/admin/incHeader.php
@@ -6,8 +6,9 @@
-
+
+
diff --git a/app/admin/pageInstallPlugin.php b/app/admin/pageInstallPlugin.php
index d0068d4..9e532f8 100644
--- a/app/admin/pageInstallPlugin.php
+++ b/app/admin/pageInstallPlugin.php
@@ -141,11 +141,16 @@ function showPage() {
function pageJS() {
global $Translation;
+ $pluginsOrderNum = getUserData('pluginsOrderNum');
+ $pluginsEmail = getUserData('pluginsEmail');
+
ob_start(); ?>
+
diff --git a/app/admin/pageServerStatus.php b/app/admin/pageServerStatus.php
index aabfd48..b63ea39 100644
--- a/app/admin/pageServerStatus.php
+++ b/app/admin/pageServerStatus.php
@@ -1,6 +1,6 @@
- {$Translation['google API key instructions']}"); ?>
+ {$Translation['google API key instructions']} {$Translation['restrict API key']}
"); ?>
diff --git a/app/applicants_and_tenants_dml.php b/app/applicants_and_tenants_dml.php
index e60a7fd..c00d0cf 100644
--- a/app/applicants_and_tenants_dml.php
+++ b/app/applicants_and_tenants_dml.php
@@ -111,15 +111,16 @@ function applicants_and_tenants_delete($selected_id, $AllowDeleteOfParents = fal
$id = db_fetch_row($res);
$rires = sql("SELECT COUNT(1) FROM `applications_leases` WHERE `tenants`='" . makeSafe($id[0]) . "'", $eo);
$rirow = db_fetch_row($rires);
+ $childrenATag = '%s';
if($rirow[0] && !$AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation["couldn't delete"];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'applications_leases', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'applications_leases'), $RetMsg);
return $RetMsg;
} elseif($rirow[0] && $AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation['confirm delete'];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'applications_leases', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'applications_leases'), $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
return $RetMsg;
@@ -130,15 +131,16 @@ function applicants_and_tenants_delete($selected_id, $AllowDeleteOfParents = fal
$id = db_fetch_row($res);
$rires = sql("SELECT COUNT(1) FROM `residence_and_rental_history` WHERE `tenant`='" . makeSafe($id[0]) . "'", $eo);
$rirow = db_fetch_row($rires);
+ $childrenATag = '%s';
if($rirow[0] && !$AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation["couldn't delete"];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'residence_and_rental_history', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'residence_and_rental_history'), $RetMsg);
return $RetMsg;
} elseif($rirow[0] && $AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation['confirm delete'];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'residence_and_rental_history', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'residence_and_rental_history'), $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
return $RetMsg;
@@ -149,15 +151,16 @@ function applicants_and_tenants_delete($selected_id, $AllowDeleteOfParents = fal
$id = db_fetch_row($res);
$rires = sql("SELECT COUNT(1) FROM `employment_and_income_history` WHERE `tenant`='" . makeSafe($id[0]) . "'", $eo);
$rirow = db_fetch_row($rires);
+ $childrenATag = '%s';
if($rirow[0] && !$AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation["couldn't delete"];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'employment_and_income_history', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'employment_and_income_history'), $RetMsg);
return $RetMsg;
} elseif($rirow[0] && $AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation['confirm delete'];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'employment_and_income_history', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'employment_and_income_history'), $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
return $RetMsg;
@@ -168,15 +171,16 @@ function applicants_and_tenants_delete($selected_id, $AllowDeleteOfParents = fal
$id = db_fetch_row($res);
$rires = sql("SELECT COUNT(1) FROM `references` WHERE `tenant`='" . makeSafe($id[0]) . "'", $eo);
$rirow = db_fetch_row($rires);
+ $childrenATag = '%s';
if($rirow[0] && !$AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation["couldn't delete"];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'references', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'references'), $RetMsg);
return $RetMsg;
} elseif($rirow[0] && $AllowDeleteOfParents && !$skipChecks) {
$RetMsg = $Translation['confirm delete'];
- $RetMsg = str_replace('', $rirow[0], $RetMsg);
- $RetMsg = str_replace('', 'references', $RetMsg);
+ $RetMsg = str_replace('', sprintf($childrenATag, $rirow[0]), $RetMsg);
+ $RetMsg = str_replace(['[]', ''], sprintf($childrenATag, 'references'), $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
$RetMsg = str_replace('', '', $RetMsg);
return $RetMsg;
@@ -388,9 +392,9 @@ function applicants_and_tenants_form($selectedId = '', $allowUpdate = true, $all
$templateCode = str_replace('<%%EMBEDDED%%>', (Request::val('Embedded') ? 'Embedded=1' : ''), $templateCode);
// process buttons
if($showSaveNew) {
- $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
} elseif($showSaveAsCopy) {
- $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
} else {
$templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
}
@@ -405,7 +409,7 @@ function applicants_and_tenants_form($selectedId = '', $allowUpdate = true, $all
if($hasSelectedId) {
if(!Request::val('Embedded')) $templateCode = str_replace('<%%DVPRINT_BUTTON%%>', '', $templateCode);
if($allowUpdate)
- $templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
else
$templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
diff --git a/app/applications_leases_dml.php b/app/applications_leases_dml.php
index 9b3f154..79aa23d 100644
--- a/app/applications_leases_dml.php
+++ b/app/applications_leases_dml.php
@@ -670,9 +670,9 @@ function unit_reload__RAND__(filterer_property) {
$templateCode = str_replace('<%%EMBEDDED%%>', (Request::val('Embedded') ? 'Embedded=1' : ''), $templateCode);
// process buttons
if($showSaveNew) {
- $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
} elseif($showSaveAsCopy) {
- $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
} else {
$templateCode = str_replace('<%%INSERT_BUTTON%%>', '', $templateCode);
}
@@ -687,7 +687,7 @@ function unit_reload__RAND__(filterer_property) {
if($hasSelectedId) {
if(!Request::val('Embedded')) $templateCode = str_replace('<%%DVPRINT_BUTTON%%>', '', $templateCode);
if($allowUpdate)
- $templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
+ $templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
else
$templateCode = str_replace('<%%UPDATE_BUTTON%%>', '', $templateCode);
diff --git a/app/common.js b/app/common.js
index d8174c9..64ce764 100644
--- a/app/common.js
+++ b/app/common.js
@@ -1,9 +1,14 @@
var AppGini = AppGini || {};
-AppGini.version = 24.15;
+AppGini.version = 24.18;
+
+/* global constants */
+const NO_GEOLOCATION_THOUGH_REQUIRED = -1;
+const NO_GEOLOCATION = 0;
+const GEOLOCATION_POPULATED = 1;
/* initials and fixes */
-jQuery(function() {
+$j(function() {
AppGini.count_ajaxes_blocking_saving = 0;
/* add ":truncated" pseudo-class to detect elements with clipped text */
@@ -75,10 +80,10 @@ jQuery(function() {
});
/* don't allow responsive images to initially exceed the smaller of their actual dimensions, or .6 container width */
- jQuery('.detail_view .img-responsive').each(function() {
+ $j('.detail_view .img-responsive').each(function() {
var pic_real_width, pic_real_height;
- var img = jQuery(this);
- jQuery('') // Make in memory copy of image to avoid css issues
+ var img = $j(this);
+ $j('') // Make in memory copy of image to avoid css issues
.attr('src', img.attr('src'))
.on('load', function() {
pic_real_width = this.width;
@@ -89,10 +94,10 @@ jQuery(function() {
});
});
- jQuery('.table-responsive .img-responsive').each(function() {
+ $j('.table-responsive .img-responsive').each(function() {
var pic_real_width, pic_real_height;
- var img = jQuery(this);
- jQuery('') // Make in memory copy of image to avoid css issues
+ var img = $j(this);
+ $j('') // Make in memory copy of image to avoid css issues
.attr('src', img.attr('src'))
.on('load', function() {
pic_real_width = this.width;
@@ -104,15 +109,15 @@ jQuery(function() {
});
/* toggle TV action buttons based on selected records */
- jQuery('.record_selector').click(function() {
- var id = jQuery(this).val();
- var checked = jQuery(this).prop('checked');
+ $j('.record_selector').click(function() {
+ var id = $j(this).val();
+ var checked = $j(this).prop('checked');
update_action_buttons();
});
/* select/deselect all records in TV */
- jQuery('#select_all_records').click(function() {
- jQuery('.record_selector').prop('checked', jQuery(this).prop('checked'));
+ $j('#select_all_records').click(function() {
+ $j('.record_selector').prop('checked', $j(this).prop('checked'));
update_action_buttons();
});
@@ -133,14 +138,6 @@ jQuery(function() {
/* remove empty email links */
$j('a[href="mailto:"]').remove();
- /* Disable action buttons when form is submitted to avoid user re-submission on slow connections */
- $j('form').eq(0).submit(function() {
- setTimeout(function() {
- var tn = AppGini.currentTableName();
- $j('#' + tn + '_dv_action_buttons').find('.btn').prop('disabled', true);
- }, 200); // delay purpose is to allow submitting the button values first then disable them.
- });
-
/* fix links inside alerts */
$j('.alert a:not(.btn)').addClass('alert-link');
@@ -329,46 +326,42 @@ jQuery(function() {
// render the DV layout toolbar
AppGini.renderDVLayoutToolbar();
- // handle click on layout toolbar buttons
- $j('.detail_view-layout').on('click', 'a', function(e) {
- e.preventDefault();
-
- if($j(this).hasClass('switch-to-single-column-layout')) {
- AppGini.applySingleColumnLayout();
- } else if($j(this).hasClass('switch-to-double-column-layout')) {
- AppGini.applyDoubleColumnLayout();
- } else if($j(this).hasClass('switch-to-triple-column-layout')) {
- AppGini.applyTripleColumnLayout();
- }
- });
-
+ // show records per page selector in TV
AppGini.renderTVRecordsPerPageSelector();
AppGini.appendRecordsPerPageToTableLinks();
+ $j('#insert').on('click', (e) => { AppGini.handleSubmitRecord(e, true) });
+ $j('#update').on('click', (e) => { AppGini.handleSubmitRecord(e, false) });
+
+ // handle clicking 'Capture my location' button
+ AppGini.handleCaptureLocation();
+
+ // ignore form validation on clicking '#addNew' button
+ $j('#addNew').on('click', (e) => $j('form').attr('novalidate', 'novalidate'));
});
/* show/hide TV action buttons based on whether records are selected or not */
function update_action_buttons() {
- if(jQuery('.record_selector:checked').length) {
- jQuery('.selected_records').removeClass('hidden');
- jQuery('#select_all_records')
- .prop('checked', (jQuery('.record_selector:checked').length == jQuery('.record_selector').length));
+ if($j('.record_selector:checked').length) {
+ $j('.selected_records').removeClass('hidden');
+ $j('#select_all_records')
+ .prop('checked', ($j('.record_selector:checked').length == $j('.record_selector').length));
} else {
- jQuery('.selected_records').addClass('hidden');
+ $j('.selected_records').addClass('hidden');
}
}
/* fix table-responsive behavior on Chrome */
function fix_table_responsive_width() {
- var resp_width = jQuery('div.table-responsive').width();
+ var resp_width = $j('div.table-responsive').width();
var table_width;
if(resp_width) {
- jQuery('div.table-responsive table').width('100%');
- table_width = jQuery('div.table-responsive table').width();
- resp_width = jQuery('div.table-responsive').width();
+ $j('div.table-responsive table').width('100%');
+ table_width = $j('div.table-responsive table').width();
+ resp_width = $j('div.table-responsive').width();
if(resp_width == table_width) {
- jQuery('div.table-responsive table').width(resp_width - 1);
+ $j('div.table-responsive table').width(resp_width - 1);
}
}
}
@@ -442,57 +435,93 @@ AppGini.ajaxCache = function() {
};
};
-function applicants_and_tenants_validateData() {
+function applicants_and_tenants_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
// check all required fields have values
- if(!AppGini.Validation.fieldRequired('radio', 'status', 'Status')) return false;
+ const reqFields = [
+ // [field-type, field-name, field-caption], ...
+ ['radio', 'status', 'Status'],
+ ];
+
+ reqFields.map(function(rf) {
+ // avoid displaying more error messages and overwhelming users
+ if(rf.length != 3 || errors) return;
+
+ if(!AppGini.Validation.fieldRequired(rf[0], rf[1], rf[2], insertMode)) errors = true;
+ });
+
+ if(errors) return false;
return !errors;
}
-function applications_leases_validateData() {
+function applications_leases_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
// check all required fields have values
- if(!AppGini.Validation.fieldRequired('radio', 'status', 'Application status')) return false;
- if(!AppGini.Validation.fieldRequired('radio', 'type', 'Lease type')) return false;
- if(!AppGini.Validation.fieldRequired('list', 'recurring_charges_frequency', 'Recurring charges frequency')) return false;
+ const reqFields = [
+ // [field-type, field-name, field-caption], ...
+ ['radio', 'status', 'Application status'],
+ ['radio', 'type', 'Lease type'],
+ ['list', 'recurring_charges_frequency', 'Recurring charges frequency'],
+ ];
+
+ reqFields.map(function(rf) {
+ // avoid displaying more error messages and overwhelming users
+ if(rf.length != 3 || errors) return;
+
+ if(!AppGini.Validation.fieldRequired(rf[0], rf[1], rf[2], insertMode)) errors = true;
+ });
+
+ if(errors) return false;
return !errors;
}
-function residence_and_rental_history_validateData() {
+function residence_and_rental_history_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
return !errors;
}
-function employment_and_income_history_validateData() {
+function employment_and_income_history_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
return !errors;
}
-function references_validateData() {
+function references_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
return !errors;
}
-function rental_owners_validateData() {
+function rental_owners_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
return !errors;
}
-function properties_validateData() {
+function properties_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
// check all required fields have values
- if(!AppGini.Validation.fieldRequired('text', 'property_name', 'Property Name')) return false;
- if(!AppGini.Validation.fieldRequired('radio', 'type', 'Type')) return false;
+ const reqFields = [
+ // [field-type, field-name, field-caption], ...
+ ['text', 'property_name', 'Property Name'],
+ ['radio', 'type', 'Type'],
+ ];
+
+ reqFields.map(function(rf) {
+ // avoid displaying more error messages and overwhelming users
+ if(rf.length != 3 || errors) return;
+
+ if(!AppGini.Validation.fieldRequired(rf[0], rf[1], rf[2], insertMode)) errors = true;
+ });
+
+ if(errors) return false;
// check file uploads (file type and size)
if($j('#photo').val() && !AppGini.checkFileUpload('photo', 'jpg|jpeg|gif|png|webp', 2048000)) {
@@ -502,7 +531,7 @@ function properties_validateData() {
return !errors;
}
-function property_photos_validateData() {
+function property_photos_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
@@ -514,12 +543,24 @@ function property_photos_validateData() {
return !errors;
}
-function units_validateData() {
+function units_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
// check all required fields have values
- if(!AppGini.Validation.fieldRequired('radio', 'status', 'Status')) return false;
+ const reqFields = [
+ // [field-type, field-name, field-caption], ...
+ ['radio', 'status', 'Status'],
+ ];
+
+ reqFields.map(function(rf) {
+ // avoid displaying more error messages and overwhelming users
+ if(rf.length != 3 || errors) return;
+
+ if(!AppGini.Validation.fieldRequired(rf[0], rf[1], rf[2], insertMode)) errors = true;
+ });
+
+ if(errors) return false;
// check file uploads (file type and size)
if($j('#photo').val() && !AppGini.checkFileUpload('photo', 'jpg|jpeg|gif|png|webp', 2048000)) {
@@ -529,7 +570,7 @@ function units_validateData() {
return !errors;
}
-function unit_photos_validateData() {
+function unit_photos_validateData(insertMode) {
$j('.has-error').removeClass('has-error');
var errors = false;
@@ -674,7 +715,7 @@ function loadScript(jsUrl, cssUrl, callback) {
* causes_closing: boolean, default is true.
*/
function modal_window(options) {
- return jQuery('body').agModal(options).agModal('show').attr('id');
+ return $j('body').agModal(options).agModal('show').attr('id');
}
function random_string(string_length) {
@@ -691,7 +732,7 @@ function random_string(string_length) {
* @return array of IDs (PK values) of selected records in TV (records that the user checked)
*/
function get_selected_records_ids() {
- return jQuery('.record_selector:checked').map(function() { return jQuery(this).val() }).get();
+ return $j('.record_selector:checked').map(function() { return $j(this).val() }).get();
}
function print_multiple_dv_tvdv(t, ids) {
@@ -743,8 +784,8 @@ function mass_delete(t, ids) {
'' +
'' +
'