mirror of
https://github.com/ONLYOFFICE/onlyoffice.github.io.git
synced 2026-04-07 14:04:30 +08:00
861 lines
23 KiB
JavaScript
861 lines
23 KiB
JavaScript
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2025
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
|
|
var themeType = 'light';
|
|
var type = 'add';
|
|
var aiModel = null;
|
|
var isModelCmbInit = true;
|
|
|
|
var providersList = [];
|
|
var providerModelsList = [];
|
|
|
|
var nameInputEl = document.getElementById('name-input');
|
|
var providerNameCmbEl = document.getElementById('provider-name-cmb');
|
|
$(providerNameCmbEl).on('select2:open', onOpenProviderComboBox);
|
|
|
|
var providerUrlInputEl = document.getElementById('provider-url-input');
|
|
var providerKeyInputEl = document.getElementById('provider-key-input');
|
|
var modelNameCmbEl = document.getElementById('model-name-cmb');
|
|
var updateModelsBtnEl = document.getElementById('update-models-btn');
|
|
var updateModelsErrorEl = document.getElementById('update-models-error');
|
|
|
|
var isCustomName = false;
|
|
var isFirstLoadOfModels = true;
|
|
|
|
nameInputEl.addEventListener('change', onChangeNameInput);
|
|
providerUrlInputEl.addEventListener('change', onChangeProviderUrlInput);
|
|
providerKeyInputEl.addEventListener('change', onChangeProviderKeyInput)
|
|
updateModelsBtnEl.addEventListener('click', updateModelsList);
|
|
|
|
var modelsList = [];
|
|
function getModelById(id) {
|
|
for (let i = 0, len = modelsList.length; i < len; i++) {
|
|
if (modelsList[i].id === id)
|
|
return modelsList[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
var nameInputValidator = new ValidatorWrapper({
|
|
fieldEl: nameInputEl
|
|
});
|
|
|
|
var providerUrlValidator = new ValidatorWrapper({
|
|
fieldEl: providerUrlInputEl
|
|
});
|
|
|
|
var providerNameValidator = new ValidatorWrapper({
|
|
fieldEl: providerNameCmbEl,
|
|
borderedEl: function() {
|
|
return providerNameValidator.containerEl.querySelector('.select2-selection');
|
|
}
|
|
});
|
|
$(providerNameCmbEl).select2({width: '100%'});
|
|
|
|
var modelNameValidator = new ValidatorWrapper({
|
|
fieldEl: modelNameCmbEl,
|
|
borderedEl: function() {
|
|
return modelNameValidator.containerEl.querySelector('.select2-selection');
|
|
}
|
|
});
|
|
$(modelNameCmbEl).select2({width: '100%'});
|
|
|
|
var providerKeyInput = new MaskedInput({
|
|
el: providerKeyInputEl
|
|
});
|
|
|
|
|
|
$('#custom-providers-button label').click(function(e) {
|
|
window.Asc.plugin.sendToPlugin("onOpenCustomProvidersModal");
|
|
});
|
|
|
|
var updateModelsLoader = null;
|
|
var updateModelsErrorTip = new Tooltip(updateModelsErrorEl, {
|
|
xAnchor: 'right',
|
|
align: 'right',
|
|
yOffset: 2,
|
|
width: 233,
|
|
});
|
|
|
|
const providerKeyTip = new Tooltip(providerKeyInputEl, {
|
|
align: 'center',
|
|
width: 250,
|
|
text: "You can obtain information about the key on the provider's website. This field is not mandatory.",
|
|
});
|
|
|
|
const useAllBtn = new ToggleButton({
|
|
id: 'use-all',
|
|
label: 'All',
|
|
onToggle: function(value) {
|
|
for (const capability in capabilitiesElements) {
|
|
var item = capabilitiesElements[capability];
|
|
item.btn.setValue(value);
|
|
}
|
|
}
|
|
});
|
|
|
|
var capabilitiesElements = {
|
|
text: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-text',
|
|
label: 'Text',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Chat
|
|
},
|
|
image: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-image',
|
|
label: 'Images',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Image
|
|
},
|
|
embeddings: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-embeddings',
|
|
label: 'Embeddings',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Embeddings
|
|
},
|
|
audio: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-audio',
|
|
label: 'Audio Processing',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Audio
|
|
},
|
|
moderations: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-moderations',
|
|
label: 'Content Moderation',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Moderations
|
|
},
|
|
realtime: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-realtime',
|
|
label: 'Realtime Tasks',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Realtime
|
|
},
|
|
code: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-code',
|
|
label: 'Coding Help',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Code
|
|
},
|
|
vision: {
|
|
btn: new ToggleButton({
|
|
id: 'use-for-vision',
|
|
label: 'Visual Analysis',
|
|
onToggle: onToggleCapability
|
|
}),
|
|
capabilities: AI.CapabilitiesUI.Vision
|
|
}
|
|
};
|
|
|
|
var heightUpdateConditions = {
|
|
_init: false,
|
|
_translate: false,
|
|
_markReady: function(key) {
|
|
heightUpdateConditions[key] = true;
|
|
heightUpdateConditions._checkAllReady();
|
|
},
|
|
_checkAllReady: function() {
|
|
if (
|
|
heightUpdateConditions._init &&
|
|
heightUpdateConditions._translate
|
|
) {
|
|
updateWindowHeight();
|
|
}
|
|
},
|
|
|
|
initReady: function() {
|
|
heightUpdateConditions._markReady('_init');
|
|
},
|
|
translateReady: function() {
|
|
heightUpdateConditions._markReady('_translate');
|
|
}
|
|
};
|
|
|
|
var resolveModels = null;
|
|
var rejectModels = null;
|
|
window.Asc.plugin.init = function() {
|
|
window.Asc.plugin.sendToPlugin("onInit");
|
|
window.Asc.plugin.attachEvent("onThemeChanged", onThemeChanged);
|
|
window.Asc.plugin.attachEvent("onModelInfo", onModelInfo);
|
|
window.Asc.plugin.attachEvent("onSubmit", onSubmit);
|
|
window.Asc.plugin.attachEvent("onProvidersUpdate", onProvidersUpdate);
|
|
window.Asc.plugin.attachEvent("onGetModels", function(data) {
|
|
if(data.error == 1) {
|
|
rejectModels && rejectModels(data);
|
|
} else {
|
|
modelsList = data.models;
|
|
let res = data.models.map(function(model) {
|
|
return {
|
|
name: model.name,
|
|
capabilities: model.capabilities
|
|
}
|
|
});
|
|
res.sort(function(a,b){ return (a.name < b.name) ? -1 : ((a.name === b.name) ? 0 : 1); });
|
|
|
|
data.models = res;
|
|
resolveModels && resolveModels(data);
|
|
}
|
|
});
|
|
|
|
heightUpdateConditions.initReady();
|
|
}
|
|
window.Asc.plugin.onThemeChanged = onThemeChanged;
|
|
|
|
window.Asc.plugin.onTranslate = function () {
|
|
let elements = document.querySelectorAll('.i18n');
|
|
elements.forEach(function(element) {
|
|
element.innerText = window.Asc.plugin.tr(element.innerText);
|
|
});
|
|
|
|
for (const capability in capabilitiesElements) {
|
|
var item = capabilitiesElements[capability];
|
|
item.btn.setLabel(window.Asc.plugin.tr(item.btn.getLabel()));
|
|
}
|
|
|
|
providerKeyInputEl.setAttribute('placeholder', window.Asc.plugin.tr(providerKeyInputEl.getAttribute('placeholder')));
|
|
|
|
heightUpdateConditions.translateReady();
|
|
};
|
|
|
|
window.addEventListener("resize", onResize);
|
|
onResize();
|
|
|
|
function onThemeChanged(theme) {
|
|
window.Asc.plugin.onThemeChangedBase(theme);
|
|
|
|
themeType = theme.type || 'light';
|
|
updateBodyThemeClasses(theme.type, theme.name);
|
|
updateThemeVariables(theme);
|
|
|
|
$('img.icon').each(function() {
|
|
var src = $(this).attr('src');
|
|
var newSrc = src.replace(/(icons\/)([^\/]+)(\/)/, '$1' + themeType + '$3');
|
|
$(this).attr('src', newSrc);
|
|
});
|
|
}
|
|
|
|
function getZoomSuffixForImage() {
|
|
var ratio = Math.round(window.devicePixelRatio / 0.25) * 0.25;
|
|
ratio = Math.max(ratio, 1);
|
|
ratio = Math.min(ratio, 2);
|
|
if(ratio == 1) return ''
|
|
else {
|
|
return '@' + ratio + 'x';
|
|
}
|
|
}
|
|
|
|
function updateWindowHeight() {
|
|
const contentHeight = $('body').prop('scrollHeight');
|
|
const visibleHeight = $('body').innerHeight();
|
|
|
|
if(contentHeight > visibleHeight) {
|
|
window.Asc.plugin.sendToPlugin("onUpdateHeight", contentHeight + 5);
|
|
}
|
|
}
|
|
|
|
function onResize () {
|
|
$('img').each(function() {
|
|
var el = $(this);
|
|
var src = $(el).attr('src');
|
|
if(!src.includes('resources/icons/')) return;
|
|
|
|
var srcParts = src.split('/');
|
|
var fileNameWithRatio = srcParts.pop();
|
|
var clearFileName = fileNameWithRatio.replace(/@\d+(\.\d+)?x/, '');
|
|
var newFileName = clearFileName;
|
|
newFileName = clearFileName.replace(/(\.[^/.]+)$/, getZoomSuffixForImage() + '$1');
|
|
srcParts.push(newFileName);
|
|
el.attr('src', srcParts.join('/'));
|
|
});
|
|
}
|
|
|
|
function onProvidersUpdate(info) {
|
|
providersList = [];
|
|
|
|
for (let i = 0, len = info.providers.length; i < len; i++) {
|
|
let srcProvider = info.providers[i];
|
|
providersList.push({
|
|
id : srcProvider.name,
|
|
name : srcProvider.name,
|
|
url : srcProvider.url,
|
|
key : srcProvider.key,
|
|
});
|
|
}
|
|
|
|
updateProviderComboBox(false);
|
|
}
|
|
|
|
function onModelInfo(info) {
|
|
type = (info.model ? 'edit' : 'add');
|
|
|
|
providersList = [];
|
|
|
|
for (let i = 0, len = info.providers.length; i < len; i++) {
|
|
let srcProvider = info.providers[i];
|
|
providersList.push({
|
|
id : srcProvider.name,
|
|
name : srcProvider.name,
|
|
url : srcProvider.url,
|
|
key : srcProvider.key,
|
|
});
|
|
}
|
|
|
|
if(info.model) {
|
|
var key = '';
|
|
isCustomName = true;
|
|
|
|
aiModel = {
|
|
name : info.model.name,
|
|
id : info.model.id,
|
|
provider : info.model.provider
|
|
};
|
|
|
|
var findedProvider = info.providers.find(function(provider) {
|
|
return provider.name == aiModel.provider;
|
|
});
|
|
if (findedProvider) {
|
|
key = findedProvider.key;
|
|
}
|
|
|
|
nameInputEl.value = aiModel.name;
|
|
|
|
$(providerNameCmbEl).val(aiModel.provider);
|
|
providerKeyInputEl.value = key;
|
|
}
|
|
updateProviderComboBox(!!aiModel);
|
|
updateCapabilitiesBtns(info.model ? info.model.capabilities : AI.CapabilitiesUI.None);
|
|
}
|
|
|
|
function onSubmit() {
|
|
var isProviderNameValid = providerNameValidator.validate();
|
|
var isNameInputValid = nameInputValidator.validate();
|
|
var isProviderUrlValid = providerUrlValidator.validate();
|
|
var isModelNameValid = modelNameValidator.validate();
|
|
if(!isProviderNameValid || !isNameInputValid || !isProviderUrlValid || !isModelNameValid) return;
|
|
|
|
let model = {
|
|
provider : {
|
|
name : providerNameCmbEl.value,
|
|
url : providerUrlInputEl.value,
|
|
key : providerKeyInputEl.value
|
|
},
|
|
name : nameInputEl.value,
|
|
id : modelNameCmbEl.value,
|
|
capabilities: getCapabilities()
|
|
};
|
|
|
|
// let modelInfo = getModelById(model.id);
|
|
// if (modelInfo)
|
|
// model.capabilities = modelInfo.capabilities;
|
|
|
|
window.Asc.plugin.sendToPlugin("onChangeModel", model);
|
|
}
|
|
|
|
function onChangeNameInput() {
|
|
isCustomName = nameInputEl.value.trim().length > 0;
|
|
}
|
|
|
|
function onChangeProviderComboBox() {
|
|
var provider = providersList.filter(function(el) { return el.id == providerNameCmbEl.value })[0] || null;
|
|
|
|
providerUrlInputEl.value = provider ? provider.url : '';
|
|
providerKeyInputEl.value = provider ? provider.key : '';
|
|
|
|
if (providerUrlInputEl.value === "[external]") {
|
|
providerUrlInputEl.setAttribute('disabled', true);
|
|
providerKeyInputEl.setAttribute('disabled', true);
|
|
}
|
|
else {
|
|
providerUrlInputEl.removeAttribute('disabled');
|
|
providerKeyInputEl.removeAttribute('disabled');
|
|
}
|
|
|
|
if (providerUrlInputEl.value) {
|
|
updateModelsList();
|
|
}
|
|
|
|
providerKeyInput.setMasked(!!providerKeyInputEl.value);
|
|
}
|
|
|
|
function onOpenProviderComboBox() {
|
|
const searchField = $(providerNameCmbEl).data('select2').$dropdown.find('.select2-search__field')[0];
|
|
if (searchField) {
|
|
function onKeydownSearchInput(event) {
|
|
//Keydown "Tab"
|
|
if(event.keyCode == 9) {
|
|
//Blocked "keydown" handler in select2 so that the menu is not hidden
|
|
event.stopPropagation();
|
|
|
|
//Triggering Enter keydown
|
|
var enterEvent = new KeyboardEvent('keydown', {
|
|
key: 'Enter',
|
|
code: 'Enter',
|
|
keyCode: 13,
|
|
which: 13,
|
|
bubbles: true,
|
|
cancelable: true
|
|
});
|
|
event.target.dispatchEvent(enterEvent);
|
|
|
|
setTimeout(function() {
|
|
providerUrlInputEl.focus();
|
|
}, 0);
|
|
}
|
|
};
|
|
searchField.addEventListener('keydown', onKeydownSearchInput, { capture: true });
|
|
}
|
|
}
|
|
|
|
function onChangeProviderUrlInput() {
|
|
updateModelsList();
|
|
}
|
|
|
|
function onChangeProviderKeyInput() {
|
|
updateModelsList();
|
|
}
|
|
|
|
function onChangeModelComboBox() {
|
|
if(type == 'add' || !isFirstLoadOfModels) {
|
|
var modelObj = providerModelsList.filter(function(model) { return model.name == modelNameCmbEl.value })[0] || null;
|
|
updateCapabilitiesBtns(modelObj ? modelObj.capabilities : 0);
|
|
|
|
if (modelObj && modelObj.name) {
|
|
let providerObj = providersList.filter(function(provider) { return provider.id == providerNameCmbEl.value })[0] || null;
|
|
let providerName = providerObj ? providerObj.name : providerNameCmbEl.value;
|
|
if (providerName)
|
|
nameInputEl.value = providerName + ' [' + modelObj.name + ']';
|
|
else
|
|
nameInputEl.value = modelObj.name;
|
|
}
|
|
}
|
|
}
|
|
|
|
function onToggleCapability() {
|
|
let isActiveAll = true;
|
|
for (const capability in capabilitiesElements) {
|
|
const isActive = capabilitiesElements[capability].btn.getValue();
|
|
if(!isActive) {
|
|
isActiveAll = false;
|
|
break;
|
|
}
|
|
}
|
|
useAllBtn.setValue(isActiveAll);
|
|
}
|
|
|
|
function getCapabilities() {
|
|
var result = 0;
|
|
for (const key in capabilitiesElements) {
|
|
var itemProps = capabilitiesElements[key];
|
|
itemProps.btn.getValue() && (result += itemProps.capabilities);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function updateCapabilitiesBtns(capabilities) {
|
|
if(capabilities === undefined) return;
|
|
|
|
for (const key in capabilitiesElements) {
|
|
var itemProps = capabilitiesElements[key];
|
|
itemProps.btn.setValue((capabilities & itemProps.capabilities) !== 0);
|
|
}
|
|
|
|
onToggleCapability();
|
|
}
|
|
|
|
function updateModelsList() {
|
|
var updateHtmlElements = function() {
|
|
modelNameCmbEl.removeAttribute('disabled');
|
|
updateModelComboBox();
|
|
};
|
|
|
|
var startLoader = function() {
|
|
updateModelsLoader && (updateModelsLoader.remove ? updateModelsLoader.remove() : $('#update-models-loader-container')[0].removeChild(updateModelsLoader));
|
|
updateModelsLoader = showLoader($('#update-models-loader-container')[0], window.Asc.plugin.tr('Updating'));
|
|
$(updateModelsBtnEl).hide();
|
|
$(updateModelsErrorEl).hide();
|
|
};
|
|
var endLoader = function(errorText) {
|
|
updateModelsLoader && (updateModelsLoader.remove ? updateModelsLoader.remove() : $('#update-models-loader-container')[0].removeChild(updateModelsLoader));
|
|
updateModelsLoader = null;
|
|
|
|
|
|
$(updateModelsBtnEl).show();
|
|
if(errorText && (type == 'edit' || !isFirstLoadOfModels)) {
|
|
$(updateModelsErrorEl).show();
|
|
updateModelsErrorTip.setText(errorText);
|
|
} else {
|
|
$(updateModelsErrorEl).hide();
|
|
}
|
|
|
|
isFirstLoadOfModels = false;
|
|
};
|
|
|
|
startLoader();
|
|
$(updateModelsBtnEl).hide();
|
|
modelNameCmbEl.setAttribute('disabled', true);
|
|
fetchModelsForProvider({
|
|
name : providerNameCmbEl.value,
|
|
url : providerUrlInputEl.value,
|
|
key: providerKeyInputEl.value
|
|
}).then(function(data) {
|
|
if (providerNameCmbEl.value == data.provider) {
|
|
providerModelsList = data.models;
|
|
updateHtmlElements();
|
|
endLoader();
|
|
}
|
|
}).catch(function(error) {
|
|
if (providerNameCmbEl.value == error.provider) {
|
|
providerModelsList = [];
|
|
updateHtmlElements();
|
|
endLoader(error.message);
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateProviderComboBox(isInit) {
|
|
var cmbEl = $('#provider-name-cmb');
|
|
cmbEl.select2({
|
|
data : providersList.map(function(model) {
|
|
return {
|
|
id: model.id,
|
|
text: model.name
|
|
}
|
|
}),
|
|
tags: true,
|
|
dropdownAutoWidth: true
|
|
});
|
|
cmbEl.on('select2:select', onChangeProviderComboBox);
|
|
if(isInit) {
|
|
cmbEl.val(aiModel.provider);
|
|
} else if(providersList.length > 0) {
|
|
cmbEl.val(providersList[0].id);
|
|
providerKeyInputEl.value = providersList[0].key;
|
|
}
|
|
cmbEl.trigger('select2:select');
|
|
cmbEl.trigger('change');
|
|
}
|
|
|
|
function updateModelComboBox() {
|
|
var cmbEl = $('#model-name-cmb');
|
|
cmbEl.select2().empty();
|
|
cmbEl.select2({
|
|
data : providerModelsList.map(function(model) {
|
|
return {
|
|
id: model.name,
|
|
text: model.name
|
|
}
|
|
}),
|
|
language: {
|
|
noResults: function() {
|
|
return window.Asc.plugin.tr("Models not found");
|
|
}
|
|
},
|
|
width: '100%',
|
|
minimumResultsForSearch: Infinity,
|
|
dropdownAutoWidth: true
|
|
});
|
|
cmbEl.on('select2:select', onChangeModelComboBox);
|
|
if(modelNameValidator.getState().value == false) {
|
|
modelNameValidator.validate();
|
|
}
|
|
|
|
if(isModelCmbInit && aiModel) {
|
|
cmbEl.val(aiModel.id);
|
|
} else {
|
|
cmbEl.val(providerModelsList[0] ? providerModelsList[0].name : null);
|
|
}
|
|
isModelCmbInit = false;
|
|
cmbEl.trigger('select2:select');
|
|
cmbEl.trigger('change');
|
|
}
|
|
|
|
function fetchModelsForProvider(provider) {
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
resolveModels = resolve;
|
|
rejectModels = reject;
|
|
window.Asc.plugin.sendToPlugin("onGetModels", provider);
|
|
|
|
});
|
|
}
|
|
|
|
function MaskedInput(options) {
|
|
this._init = function() {
|
|
// Default parameters
|
|
var defaults = {
|
|
el: null, //HTML field element
|
|
};
|
|
// Merge user options with defaults
|
|
this.options = Object.assign({}, defaults, options);
|
|
|
|
// Masked state
|
|
this.isMasked = true;
|
|
|
|
if (this.options.el) {
|
|
var me = this;
|
|
|
|
// Create HTML elements
|
|
this.containerEl = document.createElement('div');
|
|
this.containerEl.style.display = 'flex';
|
|
this.containerEl.style.position = 'relative';
|
|
this.options.el.parentNode.insertBefore(this.containerEl, this.options.el);
|
|
this.options.el.style.paddingRight = '20px';
|
|
this.containerEl.appendChild(this.options.el);
|
|
|
|
this.iconEl = document.createElement('img');
|
|
this.iconEl.className = 'icon';
|
|
this.iconEl.style.position = 'absolute';
|
|
this.iconEl.style.width = '20px';
|
|
this.iconEl.style.height = '20px';
|
|
this.iconEl.style.top = '1px';
|
|
this.iconEl.style.right = '0px';
|
|
this.iconEl.style.display = 'block';
|
|
this.iconEl.style.cursor = 'pointer';
|
|
this.updateFieldView();
|
|
this.iconEl.addEventListener('click', function() {
|
|
me.setMasked(!me.isMasked);
|
|
});
|
|
this.containerEl.appendChild(this.iconEl);
|
|
} else {
|
|
console.error("Field not found.");
|
|
}
|
|
};
|
|
|
|
this.updateFieldView = function() {
|
|
this.iconEl.src = this.isMasked
|
|
? 'resources/icons/' + themeType + '/' + 'btn-password' + getZoomSuffixForImage() + '.png'
|
|
: 'resources/icons/' + themeType + '/' + 'btn-password-hide' + getZoomSuffixForImage() + '.png';
|
|
|
|
this.options.el.setAttribute(
|
|
'type',
|
|
this.isMasked ? 'password' : 'text'
|
|
);
|
|
};
|
|
|
|
this.getMasked = function() {
|
|
return this.isMasked;
|
|
};
|
|
this.setMasked = function(value) {
|
|
this.isMasked = !!value;
|
|
this.updateFieldView();
|
|
};
|
|
|
|
this._init();
|
|
}
|
|
|
|
|
|
function ValidatorWrapper(options) {
|
|
this._init = function() {
|
|
// Default parameters
|
|
var defaults = {
|
|
fieldEl: null, //HTML field element
|
|
borderedEl: null, //HTML element with a border that will change color. For fields consisting of several HTML elements. (Example: select2)
|
|
getValue: function(fieldEl) {
|
|
return fieldEl.value;
|
|
},
|
|
validator: function(value) {
|
|
return value.trim().length > 1 ? '' : window.Asc.plugin.tr('This field is required');
|
|
},
|
|
errorIconSrc: 'resources/icons/light/error.png'
|
|
};
|
|
// Merge user options with defaults
|
|
this.options = Object.assign({}, defaults, options);
|
|
|
|
this.state = {
|
|
value: true,
|
|
message: ''
|
|
}
|
|
|
|
// Create HTML elements
|
|
this.containerEl = document.createElement('div');
|
|
this.containerEl.style.display = 'flex';
|
|
this.containerEl.style.position = 'relative';
|
|
this.options.fieldEl.parentNode.insertBefore(this.containerEl, this.options.fieldEl);
|
|
this.containerEl.appendChild(this.options.fieldEl);
|
|
|
|
this.errorIconEl = document.createElement('img');
|
|
this.errorIconEl.src = this.options.errorIconSrc;
|
|
this.errorIconEl.className = 'icon';
|
|
this.errorIconEl.style.position = 'absolute';
|
|
this.errorIconEl.style.width = '20px';
|
|
this.errorIconEl.style.height = '20px';
|
|
this.errorIconEl.style.top = '1px';
|
|
this.errorIconEl.style.right = '0px';
|
|
this.errorIconEl.style.display = 'none';
|
|
|
|
this.errorTooltip = new Tooltip(this.errorIconEl, {
|
|
xAnchor: 'right',
|
|
align: 'right'
|
|
});
|
|
|
|
|
|
if (this.options.fieldEl) {
|
|
this.containerEl.appendChild(this.errorIconEl);
|
|
} else {
|
|
console.error("Field with ID '" + this.options.id + "' not found.");
|
|
}
|
|
};
|
|
|
|
this.getState = function() {
|
|
return this.state;
|
|
};
|
|
|
|
this.validate = function() {
|
|
if(typeof this.options.validator != 'function') {
|
|
console.error("Validator is not a function");
|
|
return;
|
|
}
|
|
|
|
var validateMessage = this.options.validator(this.options.getValue(this.options.fieldEl));
|
|
|
|
if(validateMessage != null && typeof validateMessage != 'string') {
|
|
console.error("Validator must return a string value or null");
|
|
return;
|
|
}
|
|
|
|
this._setValidateState(validateMessage);
|
|
return !validateMessage;
|
|
};
|
|
this._setValidateState = function(message) {
|
|
this.state.value = !message;
|
|
this.state.message = message;
|
|
this.errorTooltip.setText(message);
|
|
|
|
var borderedEl = this.options.fieldEl;
|
|
if(this.options.borderedEl){
|
|
if(typeof this.options.borderedEl == 'function') {
|
|
borderedEl = this.options.borderedEl();
|
|
} else {
|
|
borderedEl = this.options.borderedEl;
|
|
}
|
|
}
|
|
|
|
if(this.state.value) {
|
|
this.errorIconEl.style.display = 'none';
|
|
borderedEl.style.borderColor = '';
|
|
this.options.fieldEl.style.paddingRight = '';
|
|
} else {
|
|
this.errorIconEl.style.display = 'block';
|
|
borderedEl.style.cssText += 'border-color: #f62211 !important;';
|
|
this.options.fieldEl.style.paddingRight = '20px';
|
|
}
|
|
};
|
|
|
|
this._init();
|
|
}
|
|
|
|
//Toggle button component
|
|
function ToggleButton(options) {
|
|
this._init = function() {
|
|
// Default parameters
|
|
var defaults = {
|
|
id: '',
|
|
label: '',
|
|
value: false,
|
|
disabled: false,
|
|
onToggle: function (state) {}
|
|
};
|
|
|
|
// Merge user options with defaults
|
|
this.options = Object.assign({}, defaults, options);
|
|
|
|
// Button state
|
|
this.value = false;
|
|
this.disabled = false;
|
|
|
|
this.$button = $('<button class="toggle-button">' + this.options.label + '</button>');
|
|
|
|
this.setValue(this.options.value);
|
|
this.setDisabled(this.options.disabled);
|
|
|
|
// Add click event listener
|
|
var self = this; // To preserve context
|
|
this.$button.on('click', function () {
|
|
self.setValue(!self.value);
|
|
self.options.onToggle && self.options.onToggle(self.value); // Call the callback
|
|
});
|
|
|
|
// Add button to the container
|
|
var $container = $('#' + this.options.id);
|
|
if ($container) {
|
|
$container.append(this.$button);
|
|
} else {
|
|
console.error("Container with ID '" + this.options.id + "' not found.");
|
|
}
|
|
};
|
|
|
|
this.setValue = function(value) {
|
|
this.value = value;
|
|
this.$button.toggleClass('active', value);
|
|
};
|
|
this.getValue = function() {
|
|
return this.value;
|
|
};
|
|
|
|
this.setLabel = function(label) {
|
|
this.options.label = label;
|
|
this.$button.text(label);
|
|
};
|
|
this.getLabel = function() {
|
|
return this.options.label;
|
|
};
|
|
|
|
this.setDisabled = function(value) {
|
|
this.disabled = value;
|
|
if(value) {
|
|
this.$button.attr('disabled', true);
|
|
} else {
|
|
this.$button.removeAttr('disabled');
|
|
}
|
|
};
|
|
this.getDisabled = function() {
|
|
return this.disabled;
|
|
};
|
|
|
|
this._init();
|
|
}
|