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);