From 2042e2365a32db3b7a425f48d1000e2726d405ee Mon Sep 17 00:00:00 2001
From: Ali <010109ali@gmail.com>
Date: Sat, 5 Apr 2025 00:53:03 +0400
Subject: [PATCH] fixed bug when multiple formulas or windows appeared
---
.../doctype/formula_editor/formula_editor.js | 291 +++++++++++++-----
1 file changed, 207 insertions(+), 84 deletions(-)
diff --git a/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js b/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js
index 421529b..082b338 100644
--- a/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js
+++ b/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js
@@ -1342,29 +1342,29 @@ return formula;
}
function addTokenHandlers($container) {
-// Удаление токенов
-$container.find('.token-remove').off('click').on('click', function(e) {
- e.stopPropagation();
- $(this).parent().remove();
-});
+ // Удаление токенов
+ $container.find('.token-remove').off('click').on('click', function(e) {
+ e.stopPropagation();
+ $(this).parent().remove();
+ });
-// Перетаскивание токенов
-$container.find('.formula-token').each(function() {
- $(this).attr('draggable', 'true');
-
- $(this).off('dragstart').on('dragstart', function(e) {
- e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify({
- type: 'token',
- value: $(this).data('value'),
- html: $(this)[0].outerHTML
- }));
- window.draggedElement = this;
+ // Перетаскивание токенов
+ $container.find('.formula-token').each(function() {
+ $(this).attr('draggable', 'true');
+
+ $(this).off('dragstart').on('dragstart', function(e) {
+ e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify({
+ type: 'token',
+ value: $(this).data('value'),
+ html: $(this)[0].outerHTML
+ }));
+ window.draggedElement = this;
+ });
+
+ $(this).off('dragend').on('dragend', function() {
+ window.draggedElement = null;
+ });
});
-
- $(this).off('dragend').on('dragend', function() {
- window.draggedElement = null;
- });
-});
}
// Функции для создания модальных окон
@@ -1698,18 +1698,21 @@ function createUniversalFieldsModal() {
// Обработчики событий редактора формул
function attachFormulaBuilderEvents(frm, fields, grouped_fields) {
-// Сделаем поля ввода формул редактируемыми
-$(frm.wrapper).find('.formula-input').prop('readonly', false);
+ // Сделаем поля ввода формул редактируемыми
+ $(frm.wrapper).find('.formula-input').prop('readonly', false);
-// Обработчик для кнопок открытия визуального редактора
-$(frm.wrapper).on('click', '.open-formula-builder', function() {
- const fieldname = $(this).data('fieldname');
- const isTableField = $(this).data('is-table') === true;
- const currentFormula = $(frm.wrapper).find(`.formula-input[data-fieldname="${fieldname}"]`).val();
-
- openFormulaBuilder(frm, fieldname, isTableField, currentFormula, fields, grouped_fields);
- return false;
-});
+ // Сначала удаляем существующие обработчики событий
+ $(frm.wrapper).off('click', '.open-formula-builder');
+
+ // Обработчик для кнопок открытия визуального редактора
+ $(frm.wrapper).on('click', '.open-formula-builder', function() {
+ const fieldname = $(this).data('fieldname');
+ const isTableField = $(this).data('is-table') === true;
+ const currentFormula = $(frm.wrapper).find(`.formula-input[data-fieldname="${fieldname}"]`).val();
+
+ openFormulaBuilder(frm, fieldname, isTableField, currentFormula, fields, grouped_fields);
+ return false;
+ });
}
function openFormulaBuilder(frm, targetFieldname, isTableField, currentFormula, fields, grouped_fields) {
@@ -1719,6 +1722,8 @@ function openFormulaBuilder(frm, targetFieldname, isTableField, currentFormula,
// Очистка предыдущих обработчиков и данных
$modal.off('click', '.field-btn');
$modal.off('click', '.universal-field-btn');
+ $modal.off('click', '.operator-btn');
+ $modal.find('.apply-formula').off('click');
$resultContainer.empty();
$modal.find(".field-groups-container").empty();
@@ -1749,13 +1754,13 @@ function openFormulaBuilder(frm, targetFieldname, isTableField, currentFormula,
});
// Обработчики для кнопок полей - используем делегирование событий
- $modal.on('click', '.field-btn', function() {
+ $modal.off('click', '.field-btn').on('click', '.field-btn', function() {
const fieldname = $(this).data('fieldname');
addTokenToFormula(fieldname, 'field', $resultContainer, isTableField, $(this).data('group'));
});
// Обработчики для кнопок универсальных полей
- $modal.on('click', '.universal-field-btn', function() {
+ $modal.off('click', '.universal-field-btn').on('click', '.universal-field-btn', function() {
const fieldId = $(this).data('field-id');
const universalFields = JSON.parse(frm.doc.universal_fields_storage || "{}");
const field = universalFields[fieldId];
@@ -1976,7 +1981,7 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
setupTokenDragging($resultContainer);
// Настраиваем перетаскивание полей из панели
- $modal.find('.field-btn').on('dragstart', function(e) {
+ $modal.find('.field-btn').off('dragstart').on('dragstart', function(e) {
const fieldname = $(this).data('fieldname');
const label = $(this).data('label');
const group = $(this).data('group');
@@ -1995,7 +2000,7 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
});
// Настраиваем перетаскивание универсальных полей
- $modal.find('.universal-field-btn').on('dragstart', function(e) {
+ $modal.find('.universal-field-btn').off('dragstart').on('dragstart', function(e) {
const fieldId = $(this).data('field-id');
const fieldname = $(this).data('fieldname');
const label = $(this).data('label');
@@ -2009,7 +2014,7 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
});
// Настраиваем перетаскивание операторов
- $modal.find('.operator-btn').on('dragstart', function(e) {
+ $modal.find('.operator-btn').off('dragstart').on('dragstart', function(e) {
const operator = $(this).data('operator');
e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify({
@@ -2019,7 +2024,7 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
});
// Обработчики для целевого контейнера
- $resultContainer.on('dragover', function(e) {
+ $resultContainer.off('dragover').on('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).addClass('drag-hover');
@@ -2027,12 +2032,12 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
updateDropMarker(e, $(this));
});
- $resultContainer.on('dragleave', function(e) {
+ $resultContainer.off('dragleave').on('dragleave', function(e) {
$(this).removeClass('drag-hover');
$(this).find('.drop-marker').remove();
});
- $resultContainer.on('drop', function(e) {
+ $resultContainer.off('drop').on('drop', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).removeClass('drag-hover');
@@ -2043,32 +2048,32 @@ function initDragAndDrop($modal, $resultContainer, isTableField, frm) {
}
function setupTokenDragging($container) {
-$container.find('.formula-token').each(function() {
- $(this).attr('draggable', 'true');
-
- $(this).off('dragstart').on('dragstart', function(e) {
- // Сохраняем ссылку на текущий элемент
- window.draggedElement = this;
+ $container.find('.formula-token').each(function() {
+ $(this).attr('draggable', 'true');
- // Добавляем данные для переноса
- e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify({
- type: 'token',
- value: $(this).data('value'),
- html: $(this)[0].outerHTML
- }));
+ $(this).off('dragstart').on('dragstart', function(e) {
+ // Сохраняем ссылку на текущий элемент
+ window.draggedElement = this;
+
+ // Добавляем данные для переноса
+ e.originalEvent.dataTransfer.setData('text/plain', JSON.stringify({
+ type: 'token',
+ value: $(this).data('value'),
+ html: $(this)[0].outerHTML
+ }));
+
+ // Добавляем класс перетаскивания
+ $(this).addClass('dragging');
+
+ return true;
+ });
- // Добавляем класс перетаскивания
- $(this).addClass('dragging');
-
- return true;
+ // При завершении перетаскивания
+ $(this).off('dragend').on('dragend', function(e) {
+ $(this).removeClass('dragging');
+ window.draggedElement = null;
+ });
});
-
- // При завершении перетаскивания
- $(this).off('dragend').on('dragend', function(e) {
- $(this).removeClass('dragging');
- window.draggedElement = null;
- });
-});
}
function updateDropMarker(e, $container) {
@@ -2327,6 +2332,9 @@ function setupEditableContainer($container) {
// Функции для работы с полями изменения (триггерами)
function attachTriggerEditorEvents(frm, fields, grouped_fields) {
+ // Сначала удаляем существующие обработчики событий
+ $(frm.wrapper).off('click', '.open-trigger-editor');
+
// Обработчик для кнопок открытия редактора полей изменения
$(frm.wrapper).on('click', '.open-trigger-editor', function() {
const fieldname = $(this).data('fieldname');
@@ -2343,6 +2351,8 @@ function openTriggerFieldsEditor(frm, targetFieldname, currentTriggers, fields,
// Очистка предыдущих обработчиков и данных
$modal.off('click', '.trigger-field-btn');
+ $modal.off('click', '.select-table-row-trigger-field');
+ $modal.find('.apply-triggers').off('click');
$resultContainer.empty();
$modal.find(".trigger-field-groups-container").empty();
@@ -2383,7 +2393,7 @@ function openTriggerFieldsEditor(frm, targetFieldname, currentTriggers, fields,
});
// Обработчики для кнопок полей
- $modal.on('click', '.trigger-field-btn', function() {
+ $modal.off('click', '.trigger-field-btn').on('click', '.trigger-field-btn', function() {
const fieldname = $(this).data('fieldname');
// Определяем тип поля по классу кнопки
@@ -2400,7 +2410,7 @@ function openTriggerFieldsEditor(frm, targetFieldname, currentTriggers, fields,
});
// Обработчик для кнопки выбора полей строк табличных частей
- $modal.on('click', '.select-table-row-trigger-field', function() {
+ $modal.off('click', '.select-table-row-trigger-field').on('click', '.select-table-row-trigger-field', function() {
openTableRowFieldSelector(frm, $resultContainer, true);
});
@@ -2705,10 +2715,18 @@ function initTriggerDragAndDrop($modal, $triggerContainer) {
});
// Настраиваем перетаскивание полей из панели в триггер-контейнер
- $modal.find('.field-btn, .universal-field-btn').off('dragstart').on('dragstart', function(e) {
+ $modal.find('.field-btn, .universal-field-btn, .trigger-field-btn').off('dragstart').on('dragstart', function(e) {
const fieldname = $(this).data('fieldname');
const label = $(this).data('label');
- const fieldType = $(this).hasClass('universal-field-btn') ? 'universal' : 'field';
+ let fieldType = 'field';
+
+ if ($(this).hasClass('universal-field-btn')) {
+ fieldType = 'universal';
+ } else if ($(this).hasClass('highlight-event')) {
+ fieldType = 'event';
+ } else if ($(this).hasClass('table-field-btn')) {
+ fieldType = 'table';
+ }
const fieldData = {
type: 'trigger-field',
@@ -2721,7 +2739,7 @@ function initTriggerDragAndDrop($modal, $triggerContainer) {
});
// Обработка dragover для триггер-контейнера
- $triggerContainer.on('dragover', function(e) {
+ $triggerContainer.off('dragover').on('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).addClass('drag-hover');
@@ -2731,14 +2749,14 @@ function initTriggerDragAndDrop($modal, $triggerContainer) {
});
// Обработка dragleave для триггер-контейнера
- $triggerContainer.on('dragleave', function(e) {
+ $triggerContainer.off('dragleave').on('dragleave', function(e) {
e.preventDefault();
$(this).removeClass('drag-hover');
$(this).find('.drop-marker').remove();
});
// Обработка drop для триггер-контейнера
- $triggerContainer.on('drop', function(e) {
+ $triggerContainer.off('drop').on('drop', function(e) {
e.preventDefault();
e.stopPropagation();
$(this).removeClass('drag-hover');
@@ -2998,6 +3016,11 @@ function addUniversalFieldsStyles() {
}
function attachUniversalFieldsEvents(frm) {
+ // Сначала удаляем существующие обработчики событий
+ $(frm.wrapper).off('click', '.add-universal-field');
+ $(frm.wrapper).off('click', '.edit-universal-field');
+ $(frm.wrapper).off('click', '.delete-universal-field');
+
// Обработчик нажатия на кнопку "Добавить поле"
$(frm.wrapper).on('click', '.add-universal-field', function() {
openUniversalFieldModal(frm);
@@ -3019,6 +3042,10 @@ function attachUniversalFieldsEvents(frm) {
}
function openUniversalFieldModal(frm, fieldId = null) {
+ // Закрываем предыдущее окно, если оно открыто
+ if ($("#universal_fields_modal").is(":visible")) {
+ $("#universal_fields_modal").modal('hide');
+ }
// Получаем значения для редактирования (если указан fieldId)
let fieldValues = {};
@@ -3053,6 +3080,13 @@ function openUniversalFieldModal(frm, fieldId = null) {
const selectedDoctype = d.get_value('doctype');
if (selectedDoctype) {
+ // Очищаем таблицу фильтров перед загрузкой новых полей
+ if (d.fields_dict.filters && d.fields_dict.filters.grid) {
+ d.fields_dict.filters.grid.grid_rows.forEach(row => {
+ row.remove();
+ });
+ }
+
// Загружаем поля выбранного DocType
frappe.model.with_doctype(selectedDoctype, function() {
const meta = frappe.get_meta(selectedDoctype);
@@ -3106,14 +3140,50 @@ function openUniversalFieldModal(frm, fieldId = null) {
// Сохраняем информацию о полях для использования в фильтрах
d.docFields = meta.fields;
-
- // ВАЖНО: Сохраняем docFields также в глобальной переменной
window.docFields = meta.fields;
// Обновляем опции для фильтров
if (d.fields_dict.filters && d.fields_dict.filters.grid) {
d.fields_dict.filters.grid.update_docfield_property('field', 'options', filterFieldOptions);
}
+
+ // Если редактируем существующее поле и есть фильтры, добавляем их
+ if (fieldId && fieldValues.filters && fieldValues.filters.length) {
+ setTimeout(() => {
+ // Вручную добавляем каждый фильтр
+ fieldValues.filters.forEach(filter => {
+ if (!filter || !filter.field) return;
+
+ // Добавляем строку в таблицу фильтров
+ d.fields_dict.filters.grid.add_new_row();
+ const lastRow = d.fields_dict.filters.grid.grid_rows[d.fields_dict.filters.grid.grid_rows.length - 1];
+
+ // Устанавливаем значения фильтра
+ lastRow.doc.field = filter.field;
+ lastRow.doc.operator = filter.operator || '=';
+ lastRow.doc.value = filter.value || '';
+
+ // Дополнительные свойства из оригинального фильтра
+ if (filter.__is_special_ay_field) {
+ lastRow.doc.__is_special_ay_field = true;
+ }
+
+ // Обновляем отображение строки
+ lastRow.refresh();
+
+ // Находим информацию о поле для настройки типа значения
+ const fieldInfo = d.docFields.find(f => f.fieldname === filter.field);
+ if (fieldInfo) {
+ setTimeout(() => {
+ handleFilterFieldChange(d, lastRow, fieldInfo);
+ }, 100);
+ }
+ });
+
+ // Обновляем всю таблицу
+ d.fields_dict.filters.grid.refresh();
+ }, 500);
+ }
});
}
}
@@ -3149,9 +3219,7 @@ function openUniversalFieldModal(frm, fieldId = null) {
if (fieldInfo) {
// Изменяем тип поля значения
handleFilterFieldChange(d, grid_row, fieldInfo);
- } else {
}
- } else {
}
}
},
@@ -3184,7 +3252,7 @@ function openUniversalFieldModal(frm, fieldId = null) {
columns: 4
}
],
- default: fieldValues.filters || []
+ default: []
}
],
primary_action_label: fieldId ? 'Обновить' : 'Создать',
@@ -3208,11 +3276,6 @@ function openUniversalFieldModal(frm, fieldId = null) {
}
});
- // Если редактируем и есть фильтры, заполняем их
- if (fieldId && fieldValues.filters && fieldValues.filters.length) {
- d.set_value('filters', fieldValues.filters);
- }
-
// Безопасно инициализируем обработчики для строк фильтров
try {
if (d.fields_dict.filters && d.fields_dict.filters.grid) {
@@ -3224,12 +3287,20 @@ function openUniversalFieldModal(frm, fieldId = null) {
// Добавляем обработчик на событие добавления строки
d.fields_dict.filters.grid.on('row-added', function(row) {
if (d.docFields) {
- // Копируем docFields в window для доступа из обработчиков
window.docFields = d.docFields;
}
});
}
} catch (error) {
+ console.error("Ошибка при инициализации обработчиков фильтров:", error);
+ }
+
+ // Если редактируем существующее поле, вызываем событие изменения doctype для загрузки полей
+ if (fieldId && fieldValues.doctype) {
+ // Даем время на инициализацию компонентов
+ setTimeout(() => {
+ d.fields_dict.doctype.df.onchange.call(d.fields_dict.doctype);
+ }, 200);
}
// Показываем диалог
@@ -4584,7 +4655,15 @@ function openTableRowFormulaModal(frm, formulaId = null) {
const $resultContainer = $modal.find(".table-row-formula");
const $triggerContainer = $modal.find(".table-row-trigger");
- // Очистка предыдущих данных
+ // Очистка предыдущих обработчиков и данных
+ $modal.off('click', '.field-btn');
+ $modal.off('click', '.universal-field-btn');
+ $modal.off('click', '.operator-btn');
+ $modal.off('click', '.save-table-row-formula');
+ $modal.off('click', '.add-predefined-event');
+ $modal.off('click', '.open-trigger-editor-in-row');
+ $modal.off('click', '.select-table-row-trigger-field');
+
$resultContainer.empty();
$triggerContainer.empty();
$modal.find(".field-groups-container").empty();
@@ -4687,6 +4766,34 @@ function openTableRowFormulaModal(frm, formulaId = null) {
$modal.modal('hide');
});
+ // Обработчик для кнопки "При открытии документа"
+ $modal.find('.add-predefined-event').off('click').on('click', function() {
+ addTokenToTriggers("При открытии документа", $triggerContainer, 'event');
+ });
+
+ // Обработчик для кнопки "Выбрать поле"
+ $modal.find('.open-trigger-editor-in-row').off('click').on('click', function() {
+ openTriggerFieldsEditorForTableRow(frm, $triggerContainer);
+ });
+
+ // Обработчик для кнопки выбора поля строки табличной части
+ $modal.find('.select-table-row-trigger-field').off('click').on('click', function() {
+ openTableRowFieldSelector(frm, $triggerContainer, true);
+ });
+
+ // Обработчики для кнопок полей (используем делегирование событий)
+ $modal.off('click', '.field-btn, .universal-field-btn').on('click', '.field-btn, .universal-field-btn', function() {
+ const fieldText = $(this).text().trim();
+ const fieldType = $(this).hasClass('universal-field-btn') ? 'universal-field' : 'field';
+
+ // Добавляем в формулу
+ const $token = $(`${fieldText}×`);
+ $resultContainer.append($token).append(' ');
+
+ // Добавляем обработчики для токенов
+ addTokenHandlers($resultContainer);
+ });
+
// Настраиваем перетаскивание и редактирование
initDragAndDrop($modal, $resultContainer, true, frm);
setupEditableContainer($resultContainer);
@@ -4699,6 +4806,7 @@ function openTableRowFormulaModal(frm, formulaId = null) {
$modal.find(".modal-overlay").remove();
})
.catch((error) => {
+ console.error("Ошибка при открытии модального окна формулы строки таблицы:", error);
$modal.find(".modal-overlay").remove();
frappe.msgprint({
title: __('Ошибка'),
@@ -5226,6 +5334,11 @@ function initTableRowFormulas(frm) {
// Создаем модальное окно, если его еще нет
createTableRowFormulaModal();
+ // Удаляем существующие обработчики
+ $(frm.wrapper).off('click', '.add-table-row-formula');
+ $(frm.wrapper).off('click', '.edit-table-row-formula');
+ $(frm.wrapper).off('click', '.delete-table-row-formula');
+
// Обработчик для кнопки добавления новой формулы
$(frm.wrapper).on('click', '.add-table-row-formula', function() {
openTableRowFormulaModal(frm);
@@ -5588,6 +5701,9 @@ function openTableRowFieldSelector(frm, targetContainer, isForTrigger = false) {
$("#row_field_name").empty().append('').prop('disabled', true);
$("#row_field_index").val(1);
+ // Удаляем старые обработчики
+ $modal.find('.add-table-row-field').off('click');
+
// Загружаем список табличных частей
loadTablesListForSelector(frm);
@@ -5597,7 +5713,7 @@ function openTableRowFieldSelector(frm, targetContainer, isForTrigger = false) {
$modal.data("frm", frm);
// Обработчик для кнопки добавления
- $modal.find('.add-table-row-field').off('click').on('click', function() {
+ $modal.find('.add-table-row-field').on('click', function() {
const tableName = $("#row_field_table").val();
const fieldName = $("#row_field_name").val();
const rowIndex = $("#row_field_index").val();
@@ -6494,6 +6610,8 @@ function openTriggerFieldsEditorForTableRow(frm, $triggerContainer) {
// Очистка предыдущих обработчиков и данных
$modal.off('click', '.trigger-field-btn');
+ $modal.off('click', '.select-table-row-trigger-field');
+ $modal.find('.apply-triggers').off('click');
$modal.find(".trigger-result").empty();
$modal.find(".trigger-field-groups-container").empty();
@@ -6536,7 +6654,7 @@ function openTriggerFieldsEditorForTableRow(frm, $triggerContainer) {
});
// Обработчики для кнопок полей
- $modal.on('click', '.trigger-field-btn', function() {
+ $modal.off('click', '.trigger-field-btn').on('click', '.trigger-field-btn', function() {
const fieldname = $(this).data('fieldname');
// Определяем тип поля по классу кнопки
@@ -6552,6 +6670,11 @@ function openTriggerFieldsEditorForTableRow(frm, $triggerContainer) {
addTokenToTriggers(fieldname, $modal.find(".trigger-result"), fieldType);
});
+ // Обработчик для кнопки выбора поля строки табличной части
+ $modal.off('click', '.select-table-row-trigger-field').on('click', '.select-table-row-trigger-field', function() {
+ openTableRowFieldSelector(frm, $modal.find(".trigger-result"), true);
+ });
+
// Увеличиваем z-index модального окна, чтобы оно было поверх других
$modal.css('z-index', 1100);