- Updated copyright headers in 3,055 core application files - Changed 'Copyright (C) 2014-2025' to 'Copyright (C) 2014-2026' - Added 123 new files from EspoCRM core updates - Removed 4 deprecated files - Total changes: 61,637 insertions, 54,283 deletions This is a routine maintenance update for the new year 2026.
736 lines
19 KiB
JavaScript
736 lines
19 KiB
JavaScript
/************************************************************************
|
||
* This file is part of EspoCRM.
|
||
*
|
||
* EspoCRM – Open Source CRM application.
|
||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||
* Website: https://www.espocrm.com
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU Affero General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU Affero General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Affero General Public License
|
||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of this program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU Affero General Public License version 3.
|
||
*
|
||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||
************************************************************************/
|
||
|
||
var InstallScript = function(opt) {
|
||
this.reChecking = false;
|
||
|
||
if (typeof(opt.action) !== 'undefined') {
|
||
var action = opt.action;
|
||
this.action = action;
|
||
this[action]();
|
||
}
|
||
|
||
if (typeof(opt.langs) !== 'undefined') {
|
||
this.langs = opt.langs;
|
||
}
|
||
|
||
if (typeof(opt.modRewriteUrl) !== 'undefined') {
|
||
this.modRewriteUrl = opt.modRewriteUrl;
|
||
}
|
||
|
||
if (typeof(opt.apiPath) !== 'undefined') {
|
||
this.apiPath = opt.apiPath.substr(1) + '/';
|
||
}
|
||
|
||
if (typeof(opt.serverType) !== 'undefined') {
|
||
this.serverType = opt.serverType;
|
||
}
|
||
|
||
if (typeof(opt.OS) !== 'undefined') {
|
||
this.OS = opt.OS;
|
||
}
|
||
|
||
this.connSett = {};
|
||
this.userSett = {};
|
||
this.systemSettings = {};
|
||
this.emailSettings = {};
|
||
this.checkActions = [
|
||
{
|
||
'action': 'checkPermission',
|
||
'break': true
|
||
},
|
||
{
|
||
'action': 'saveSettings',
|
||
'break': true
|
||
},
|
||
{
|
||
'action': 'checkModRewrite',
|
||
'break': true
|
||
},
|
||
{
|
||
'action': 'buildDatabase',
|
||
'break': true
|
||
}
|
||
|
||
];
|
||
this.checkIndex = 0;
|
||
this.checkError = false;
|
||
|
||
this.initSanitizeHtml();
|
||
}
|
||
|
||
InstallScript.prototype.main = function() {
|
||
var self = this;
|
||
var nextAction = 'step1';
|
||
|
||
$("#start").click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(nextAction);
|
||
});
|
||
|
||
$('[name="user-lang"]').change(() => {
|
||
this.goTo(self.action);
|
||
});
|
||
|
||
$('[name="theme"]').change(() => {
|
||
this.goTo(self.action);
|
||
});
|
||
}
|
||
|
||
InstallScript.prototype.step1 = function() {
|
||
var self = this;
|
||
var backAction = 'main';
|
||
var nextAction = 'step2';
|
||
|
||
$('#back').click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(backAction);
|
||
})
|
||
|
||
$("#next").click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
var licenseAgree = $('#license-agree');
|
||
|
||
if (licenseAgree.length > 0 && !licenseAgree.is(':checked')) {
|
||
$(this).removeAttr('disabled');
|
||
self.showMsg({msg: self.getLang('You must agree to the license agreement', 'messages'), error: true});
|
||
}
|
||
else {
|
||
self.goTo(nextAction);
|
||
}
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.step2 = function() {
|
||
var self = this;
|
||
var backAction = 'step1';
|
||
var nextAction = 'setupConfirmation';
|
||
|
||
$('#back').click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(backAction);
|
||
})
|
||
|
||
$('#test-connection, #next').click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.setConnSett();
|
||
if (!self.validate()) {
|
||
$(this).removeAttr('disabled');
|
||
return;
|
||
}
|
||
self.showLoading();
|
||
|
||
var btn = $(this);
|
||
self.checkSett({
|
||
success: function(data) {
|
||
if (data.success) {
|
||
if (btn.attr('id') == 'next') self.goTo(nextAction);
|
||
else self.showMsg({msg: self.getLang('All Settings correct', 'messages')});
|
||
}
|
||
else {
|
||
$('#next').removeAttr('disabled');
|
||
}
|
||
$('#test-connection').removeAttr('disabled');
|
||
self.hideLoading();
|
||
}, // success END
|
||
error: function() {
|
||
$('#next').removeAttr('disabled');
|
||
$('#test-connection').removeAttr('disabled');
|
||
self.hideLoading();
|
||
}, // error END
|
||
|
||
}) // checkSett END
|
||
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.setupConfirmation = function() {
|
||
const self = this;
|
||
const backAction = 'step2';
|
||
|
||
$('#back').click(function(){
|
||
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(backAction);
|
||
})
|
||
|
||
$("#next").click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.showLoading();
|
||
self.actionsChecking();
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.step3 = function() {
|
||
const self = this;
|
||
const backAction = '';
|
||
const nextAction = 'step4';
|
||
|
||
$('input[name="user-name"]').blur(function(){
|
||
let value = $(this).val();
|
||
value = value.replace(/[^a-z0-9_\s]/gi, '').replace(/[\s]/g, '_').toLowerCase();
|
||
$(this).val(value);
|
||
})
|
||
|
||
$('#back').click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(backAction);
|
||
})
|
||
|
||
$("#next").click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.setUserSett();
|
||
if (!self.validate()) {
|
||
$(this).removeAttr('disabled');
|
||
return;
|
||
}
|
||
|
||
self.checkPass({
|
||
success: function(){
|
||
const data = self.userSett;
|
||
|
||
data['user-name'] = self.userSett.name;
|
||
data['user-pass'] = self.userSett.pass;
|
||
|
||
data.action = 'createUser';
|
||
$.ajax({
|
||
url: "index.php",
|
||
type: "POST",
|
||
data: data,
|
||
dataType: 'json',
|
||
})
|
||
.done(function(ajaxData){
|
||
if (typeof(ajaxData) != 'undefined' && ajaxData.success) {
|
||
self.goTo(nextAction);
|
||
} else {
|
||
$("#next").removeAttr('disabled');
|
||
self.showMsg({msg: self.getLang(ajaxData.errorMsg, 'messages'), error: true});
|
||
}
|
||
})
|
||
},
|
||
error: function(msg) {
|
||
$("#next").removeAttr('disabled');
|
||
self.showMsg({msg: self.getLang(msg, 'messages'), error: true});
|
||
}
|
||
});
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.step4 = function() {
|
||
const self = this;
|
||
const backAction = 'step3';
|
||
const nextAction = 'finish';
|
||
|
||
$('#back').click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
self.goTo(backAction);
|
||
})
|
||
|
||
$("#next").click(function(){
|
||
$(this).attr('disabled', 'disabled');
|
||
|
||
self.setSystemSett();
|
||
if (!self.validate()) {
|
||
$(this).removeAttr('disabled');
|
||
return;
|
||
}
|
||
|
||
const data = self.systemSettings;
|
||
|
||
data.action = 'savePreferences';
|
||
|
||
$.ajax({
|
||
url: "index.php",
|
||
type: "POST",
|
||
data: data,
|
||
dataType: 'json',
|
||
})
|
||
.done(ajaxData => {
|
||
if (typeof(ajaxData) != 'undefined' && ajaxData.success) {
|
||
self.goTo(nextAction);
|
||
}
|
||
});
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.errors = function() {
|
||
const self = this;
|
||
|
||
this.reChecking = true;
|
||
|
||
$("#re-check").click(function () {
|
||
$(this).attr('disabled', 'disabled');
|
||
|
||
self.showLoading();
|
||
self.actionsChecking();
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.finish = function() {
|
||
const self = this;
|
||
|
||
$("#start").click(() => {
|
||
self.goToEspo();
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.setConnSett = function() {
|
||
this.connSett.dbPlatform = $('[name="db-platform"]').val();
|
||
this.connSett.dbName = $('[name="db-name"]').val();
|
||
this.connSett.hostName = $('[name="host-name"]').val();
|
||
this.connSett.dbUserName = $('[name="db-user-name"]').val();
|
||
this.connSett.dbUserPass = $('[name="db-user-password"]').val();
|
||
this.connSett.dbDriver = $('[name="db-driver"]').val();
|
||
}
|
||
|
||
InstallScript.prototype.setUserSett = function() {
|
||
this.userSett.name = $('[name="user-name"]').val();
|
||
this.userSett.pass = $('[name="user-pass"]').val();
|
||
this.userSett.confPass = $('[name="user-confirm-pass"]').val();
|
||
}
|
||
|
||
InstallScript.prototype.setSystemSett = function() {
|
||
this.systemSettings.dateFormat = $('[name="dateFormat"]').val();
|
||
this.systemSettings.timeFormat = $('[name="timeFormat"]').val();
|
||
this.systemSettings.timeZone = $('[name="timeZone"]').val();
|
||
this.systemSettings.weekStart = $('[name="weekStart"]').val();
|
||
this.systemSettings.defaultCurrency = $('[name="defaultCurrency"]').val();
|
||
this.systemSettings.thousandSeparator = $('[name="thousandSeparator"]').val();
|
||
this.systemSettings.decimalMark = $('[name="decimalMark"]').val();
|
||
this.systemSettings.language = $('[name="language"]').val();
|
||
}
|
||
|
||
InstallScript.prototype.checkSett = function(opt) {
|
||
const self = this;
|
||
this.hideMsg();
|
||
|
||
const data = this.connSett;
|
||
data.action = 'settingsTest';
|
||
|
||
$.ajax({
|
||
url: "index.php",
|
||
data: data,
|
||
type: "POST",
|
||
dataType: 'json',
|
||
})
|
||
.done(data => {
|
||
if (typeof(data.success) !== 'undefined' && data.success) {
|
||
data.success = true;
|
||
} else {
|
||
let msg = '';
|
||
const rowDelim = '<br>';
|
||
|
||
if (typeof(data.errors)) {
|
||
const errors = data.errors;
|
||
|
||
Object.keys(errors).forEach(function (errorName) {
|
||
const errorData = errors[errorName];
|
||
|
||
switch(errorName) {
|
||
case 'phpRequires':
|
||
const len = errorData.length;
|
||
|
||
for (let index = 0; index < len; index++) {
|
||
let temp = self.getLang('The PHP extension was not found...', 'messages');
|
||
|
||
temp = temp.replace('{extName}', errorData[index]);
|
||
|
||
msg += temp + rowDelim;
|
||
}
|
||
|
||
break;
|
||
|
||
case 'modRewrite':
|
||
msg += errorData + rowDelim;
|
||
|
||
break;
|
||
|
||
case 'dbConnect':
|
||
let temp;
|
||
|
||
if (typeof(errorData.errorCode) !== 'undefined') {
|
||
temp = self.getLang(errorData.errorCode, 'messages');
|
||
|
||
if (temp == errorData.errorCode && typeof(errorData.errorMsg) !== 'undefined') {
|
||
temp = errorData.errorMsg;
|
||
}
|
||
}
|
||
else if (typeof(errorData.errorMsg) !== 'undefined') {
|
||
temp = errorData.errorMsg;
|
||
}
|
||
|
||
msg += temp + rowDelim;
|
||
|
||
break;
|
||
|
||
default:
|
||
msg += self.getLang(errorName, 'messages').replace('{minVersion}', errorData) + rowDelim;
|
||
}
|
||
|
||
});
|
||
}
|
||
|
||
if (msg == '') {
|
||
msg = self.getLang('Some errors occurred!', 'messages');
|
||
}
|
||
|
||
self.showMsg({msg: msg, error: true});
|
||
}
|
||
|
||
opt.success(data);
|
||
})
|
||
.fail(() => {
|
||
const msg = self.getLang('Ajax failed', 'messages');
|
||
self.showMsg({msg: msg, error: true});
|
||
opt.error();
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.validate = function() {
|
||
this.hideMsg();
|
||
|
||
let valid = true;
|
||
let elem = null;
|
||
let fieldRequired = [];
|
||
|
||
switch (this.action) {
|
||
case 'step2':
|
||
fieldRequired = ['db-name', 'host-name', 'db-user-name', 'db-driver'];
|
||
break;
|
||
|
||
case 'step3':
|
||
fieldRequired = ['user-name', 'user-pass', 'user-confirm-pass'];
|
||
break;
|
||
|
||
case 'step4':
|
||
fieldRequired = ['decimalMark'];
|
||
break;
|
||
}
|
||
|
||
const len = fieldRequired.length;
|
||
|
||
for (let index = 0; index < len; index++) {
|
||
elem = $('[name="'+fieldRequired[index]+'"]').filter(':visible');
|
||
if (elem.length > 0) {
|
||
if (elem.val() == '') {
|
||
elem.parent().parent().addClass('has-error');
|
||
valid = false;
|
||
}
|
||
else {
|
||
elem.parent().parent().removeClass('has-error');
|
||
}
|
||
}
|
||
}
|
||
|
||
// decimal and group sep
|
||
$('[name="thousandSeparator"]').parent().parent().removeClass('has-error');
|
||
|
||
if (typeof(this.systemSettings.thousandSeparator) !== 'undefined'
|
||
&& typeof(this.systemSettings.decimalMark) !== 'undefined'
|
||
&& this.systemSettings.thousandSeparator == this.systemSettings.decimalMark
|
||
&& valid) {
|
||
|
||
$('[name="thousandSeparator"]').parent().parent().addClass('has-error');
|
||
$('[name="decimalMark"]').parent().parent().addClass('has-error');
|
||
|
||
const msg = this.getLang('Thousand Separator and Decimal Mark equal', 'messages');
|
||
this.showMsg({msg: msg, error: true});
|
||
valid = false;
|
||
}
|
||
|
||
return valid;
|
||
}
|
||
|
||
InstallScript.prototype.setForm = function(opt) {
|
||
const formId = opt.formId || 'nav';
|
||
const action = opt.action || 'main';
|
||
|
||
const actionField = $('<input>', {'name': 'action', 'value': action, 'type': 'hidden'});
|
||
|
||
$('#'+formId).append(actionField);
|
||
$('#'+formId).attr('method', 'POST');
|
||
}
|
||
|
||
InstallScript.prototype.goTo = function(action) {
|
||
this.setForm({action: action});
|
||
$('#nav').submit();
|
||
}
|
||
|
||
InstallScript.prototype.getLang = function(key, type) {
|
||
return (
|
||
typeof(this.langs) !== 'undefined' &&
|
||
typeof(this.langs[type]) !== 'undefined' &&
|
||
typeof(this.langs[type][key]) !== 'undefined'
|
||
) ? this.langs[type][key] : key;
|
||
}
|
||
|
||
InstallScript.prototype.showMsg = function(opt) {
|
||
this.hideMsg();
|
||
|
||
let message = opt.msg || '';
|
||
const error = opt.error || false;
|
||
|
||
if (message) {
|
||
message = this.sanitizeHtml(message);
|
||
|
||
$('#msg-box').html(message);
|
||
$('#msg-box').removeClass('hide');
|
||
$('#msg-box').removeClass('alert-success');
|
||
$('#msg-box').removeClass('alert-danger');
|
||
}
|
||
|
||
if (error) {
|
||
$('#msg-box').addClass('alert-danger');
|
||
} else {
|
||
$('#msg-box').addClass('alert-success');
|
||
}
|
||
}
|
||
|
||
InstallScript.prototype.initSanitizeHtml = function() {
|
||
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
|
||
if ('target' in node) {
|
||
node.setAttribute('target','_blank');
|
||
}
|
||
});
|
||
}
|
||
|
||
InstallScript.prototype.sanitizeHtml = function(html) {
|
||
return DOMPurify.sanitize(html);
|
||
}
|
||
|
||
InstallScript.prototype.hideMsg = function() {
|
||
$('#msg-box').html('');
|
||
$('#msg-box').addClass('hide');
|
||
}
|
||
|
||
InstallScript.prototype.showLoading = function() {
|
||
Espo.Ui.notifyWait();
|
||
}
|
||
|
||
InstallScript.prototype.hideLoading = function() {
|
||
Espo.Ui.notify(false);
|
||
}
|
||
|
||
InstallScript.prototype.checkPass = function(opt) {
|
||
const successHand = opt.success || (() => {});
|
||
const errorHand = opt.error || (() => {});
|
||
|
||
if (this.userSett.pass !== this.userSett.confPass) {
|
||
errorHand('Passwords do not match');
|
||
|
||
return;
|
||
}
|
||
|
||
successHand();
|
||
}
|
||
|
||
InstallScript.prototype.actionsChecking = function() {
|
||
this.checkIndex = 0;
|
||
this.checkErrors = [];
|
||
|
||
this.checkAction({
|
||
'success': true,
|
||
});
|
||
}
|
||
|
||
InstallScript.prototype.checkAction = function(dataMain) {
|
||
var self = this;
|
||
var data = {};
|
||
|
||
if (this.checkIndex === this.checkActions.length) {
|
||
self.callbackChecking(dataMain);
|
||
return;
|
||
}
|
||
|
||
var currIndex = this.checkIndex;
|
||
var checkAction = this.checkActions[currIndex].action;
|
||
this.checkIndex++;
|
||
|
||
if (checkAction === 'checkModRewrite') {
|
||
this.checkModRewrite();
|
||
return;
|
||
}
|
||
if (checkAction === 'saveSettings') {
|
||
data['user-name'] = this.userSett.name;
|
||
data['user-pass'] = this.userSett.pass;
|
||
}
|
||
|
||
data.action = checkAction;
|
||
|
||
$.ajax({
|
||
url: "index.php",
|
||
type: "POST",
|
||
data: data,
|
||
dataType: 'json',
|
||
})
|
||
.done(ajaxData => {
|
||
if (typeof(ajaxData) != 'undefined' && ajaxData.success) {
|
||
|
||
self.checkAction(ajaxData);
|
||
} else {
|
||
if (typeof(self.checkActions[currIndex]) != 'undefined'
|
||
&& typeof(self.checkActions[currIndex].break) != 'undefined'
|
||
&& self.checkActions[currIndex].break) {
|
||
// break next checking
|
||
self.callbackChecking(ajaxData);
|
||
}
|
||
}
|
||
})
|
||
.fail(ajaxData => {
|
||
if (
|
||
typeof(self.checkActions[currIndex]) != 'undefined'
|
||
&& typeof(self.checkActions[currIndex].break) != 'undefined'
|
||
&& self.checkActions[currIndex].break) {
|
||
// break next checking
|
||
|
||
ajaxData = {
|
||
'success': false,
|
||
'errorMsg': [self.getLang('Ajax failed', 'messages')]
|
||
}
|
||
self.callbackChecking(ajaxData);
|
||
}
|
||
else {
|
||
self.checkAction(ajaxData);
|
||
}
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.checkModRewrite = function() {
|
||
var self = this;
|
||
this.modRewriteUrl;
|
||
|
||
const urlAjax = '..' + this.modRewriteUrl;
|
||
var realJqXHR = $.ajax({
|
||
url: urlAjax,
|
||
type: "GET",
|
||
})
|
||
.always(function(data, textStatus, jqXHR){
|
||
let status = jqXHR.status || realJqXHR.status || 404;
|
||
status += '';
|
||
|
||
var data = {'success': 0};
|
||
|
||
if (status == '200' || status == '401') {
|
||
var data = {'success': 1};
|
||
}
|
||
|
||
self.callbackModRewrite(data);
|
||
})
|
||
}
|
||
|
||
InstallScript.prototype.callbackModRewrite = function(data) {
|
||
var ajaxData = {
|
||
'success': true,
|
||
}
|
||
|
||
if (typeof(data.success) != 'undefined' && data.success) {
|
||
this.checkAction(ajaxData);
|
||
return;
|
||
}
|
||
|
||
ajaxData.success = false;
|
||
ajaxData.errorMsg = this.getModRewriteErrorMessage();
|
||
|
||
const realCheckIndex = this.checkIndex - 1;
|
||
|
||
if (
|
||
typeof(this.checkActions[realCheckIndex]) != 'undefined' &&
|
||
typeof(this.checkActions[realCheckIndex].break) != 'undefined'
|
||
) {
|
||
if (this.checkActions[realCheckIndex].break) {
|
||
// break next checking
|
||
this.callbackChecking(ajaxData);
|
||
} else {
|
||
this.checkAction(ajaxData);
|
||
}
|
||
}
|
||
}
|
||
|
||
InstallScript.prototype.callbackChecking = function(data) {
|
||
this.hideLoading();
|
||
|
||
if (typeof(data) != 'undefined' && data.success) {
|
||
this.goTo('step3');
|
||
} else {
|
||
let errorMsg = (typeof (data.errorMsg)) ? data.errorMsg : '';
|
||
|
||
errorMsg += (typeof(data.errorFixInstruction) != 'undefined')? data.errorFixInstruction : '';
|
||
|
||
if (this.reChecking) {
|
||
this.showMsg({msg: errorMsg, error: true});
|
||
$("#re-check").removeAttr('disabled');
|
||
} else {
|
||
this.setForm({action: 'errors'});
|
||
$('#nav').submit();
|
||
}
|
||
}
|
||
}
|
||
|
||
InstallScript.prototype.getEspoPath = function(onlyPath) {
|
||
onlyPath = typeof onlyPath !== 'undefined' ? onlyPath : false;
|
||
|
||
let location = window.location.href;
|
||
|
||
if (onlyPath) {
|
||
location = window.location.pathname;
|
||
}
|
||
|
||
location = location.replace(/install\/?/, '');
|
||
|
||
return location;
|
||
}
|
||
|
||
InstallScript.prototype.getModRewriteErrorMessage = function() {
|
||
let message = '';
|
||
|
||
if (typeof(this.langs) !== 'undefined') {
|
||
message = (typeof(this.langs['options']['modRewriteTitle'][this.serverType]) !== 'undefined') ?
|
||
this.langs['options']['modRewriteTitle'][this.serverType] :
|
||
this.langs['options']['modRewriteTitle']['default'];
|
||
|
||
message += (
|
||
typeof(this.langs['options']['modRewriteInstruction'][this.serverType]) !== 'undefined' &&
|
||
typeof(this.langs['options']['modRewriteInstruction'][this.serverType][this.OS]) !== 'undefined'
|
||
) ? this.langs['options']['modRewriteInstruction'][this.serverType][this.OS] : '';
|
||
|
||
message = message
|
||
.replace("{ESPO_PATH}", this.getEspoPath(true))
|
||
.replace("{API_PATH}", this.apiPath).replace("{API_PATH}", this.apiPath);
|
||
}
|
||
|
||
return message;
|
||
}
|
||
|
||
InstallScript.prototype.goToEspo = function() {
|
||
const location = this.getEspoPath();
|
||
|
||
window.location.replace(location);
|
||
}
|
||
|
||
window.InstallScript = InstallScript;
|