/** * 管理表单页面字段标签处理器模块 * 负责处理 admin 表单页面上的字段和间距标签 */ import { getColumnWidths, safelyInsertLabel, safelyAppendLabel, FieldTypeCheckerForAdminDom } from '../../../utils/dom-utils.js'; import { createFieldWithLabels, createFieldLabels } from './dom.js'; import { FieldTypeChecker } from '../../../utils/field-utils.js'; import { DOM_CLASSES, FIELD_TYPES, LAYOUT_TYPES } from '../../../utils/constants.js'; import { STYLES } from '../../../features/add-field-label/settings.js'; /** * 用于处理 admin 表单页面上字段和间距标签的字段标签处理器类 */ export class AdminFieldLabelProcessor { /** * 构造函数 * @param {Object} options - 配置选项 * @param {number} options.appId - App ID * @param {string} options.pageType - 页面类型上下文(例如,'admin') */ constructor(options = {}) { this.appId = options.appId; this.pageType = options.pageType; this.id = 0; this.buildDomLayout(); } /** * 返回是否为预览模式 * @returns {boolean} 是否预览 */ isPreview() { return true; } buildDomLayout() { this.domLayout = []; this.fieldMap = []; this.groupLayoutMap = {}; this.spacerMap = {}; const rows = document.querySelector(`.${DOM_CLASSES.CANVAS_ELEMENT} > .${DOM_CLASSES.CONTENT_ELEMENT}`).children; this._buildDomLayout(this.domLayout, rows); } _buildDomLayout(layout, rowElements, parentGroupLayout) { for (const row of rowElements) { const rowLayout = { id: ++this.id, dom: row, fields: [] }; row.setAttribute("data-kintone-helper-id", this.id) layout.push(rowLayout); this.fieldMap[rowLayout.id] = rowLayout if (!!parentGroupLayout) { delete this.fieldMap[rowLayout.id] } else if (FieldTypeCheckerForAdminDom.isGroup(row)) { rowLayout.isGroup = true; const groupField = { id: this.id, dom: row, isGroup: true, layout: [] }; const rows = row.querySelector(`.${DOM_CLASSES.GROUP} .${DOM_CLASSES.CONTENT_ELEMENT}`).children; this._buildDomLayout(groupField.layout, rows, groupField); this.groupLayoutMap[groupField.id] = groupField; continue; } else if (FieldTypeCheckerForAdminDom.isSubtable(row)) { rowLayout.isSubtable = true; } else if (FieldTypeCheckerForAdminDom.isReferenceTable(row)) { rowLayout.isReferenceTable = true; delete this.fieldMap[rowLayout.id] } for (const field of row.children) { if (!FieldTypeCheckerForAdminDom.isFieldElement(field)) { continue; } const fieldLayout = { id: ++this.id, dom: field, }; field.setAttribute("data-kintone-helper-id", this.id) if (FieldTypeCheckerForAdminDom.isHr(field)) { fieldLayout.isHr = true; } else if (FieldTypeCheckerForAdminDom.isLabel(field)) { fieldLayout.isLabel = true; } else if (FieldTypeCheckerForAdminDom.isSpacer(field)) { fieldLayout.isSpacer = true; this.spacerMap[this.id] = fieldLayout; } if (!rowLayout.isSubtable && !parentGroupLayout) { this.fieldMap[fieldLayout.id] = fieldLayout } rowLayout.fields.push(fieldLayout); } } } beforeProcess(rawFieldsMap, rawLayout, fields, spacers, targetLayout = this.domLayout) { if (rawLayout.length !== targetLayout.length) { // TODO throw error return; }; for (let i = 0; i < rawLayout.length; i++) { const layoutRow = rawLayout[i]; const domLayoutRow = targetLayout[i]; const { fields: rawFields, ...layoutRowWithoutFields } = layoutRow; Object.assign(domLayoutRow, layoutRowWithoutFields); if (layoutRow.type === LAYOUT_TYPES.GROUP && domLayoutRow.isGroup) { const domGroupLayoutRow = this.groupLayoutMap[domLayoutRow.id]; const { layout, ...layoutRowWithoutLayout } = layoutRow; Object.assign(domGroupLayoutRow, layoutRowWithoutLayout); this.beforeProcess(rawFieldsMap, layoutRow.layout, fields, spacers, domGroupLayoutRow.layout); continue; } this.processFields(layoutRow.fields, domLayoutRow.fields, rawFieldsMap); } } processFields(rowFields, domFields, rawFieldsMap) { if (!rowFields || !domFields || rowFields.length !== domFields.length) { // TODO error return } for (let i = 0; i < rowFields.length; i++) { Object.assign(domFields[i], rowFields[i]); switch (rowFields[i].type) { case FIELD_TYPES.REFERENCE_TABLE: Object.assign(domFields[i], rawFieldsMap[rowFields[i].code]); break; } } } /** * 为子表字段元素添加标签 * @param {Object} field - 字段配置信息 * @param {HTMLElement} fieldElement - 字段 DOM 元素 */ addSubtableLabel(field, fieldElement) { try { // 在表上方添加字段代码标签 const tableCodeLabel = createFieldWithLabels({ code: field.code, type: field.type, }); tableCodeLabel.style.display = 'block'; safelyInsertLabel(fieldElement, tableCodeLabel); for (const col of field.fields) { const fieldLabel = createFieldWithLabels({ code: col.code, type: col.type, }); fieldLabel.style.top = STYLES.SUBTABLE_LABEL_TOP; safelyAppendLabel(col.dom.querySelector(`.${DOM_CLASSES.INSERT_LABEL_ELEMENT}`), fieldLabel); } } catch (error) { console.error(`Failed to add label for subtable field ${field.code}:`, error); } } /** * 为引用表字段元素添加标签 * @param {Object} field - 字段配置信息 * @param {HTMLElement} fieldElement - 字段 DOM 元素 */ addReferenceTableLabel(field, fieldElement) { try { // 在引用表上方添加字段代码标签 const tableCodeLabel = createFieldWithLabels({ code: field.code, type: field.type, }); tableCodeLabel.style.display = 'block'; safelyInsertLabel(fieldElement, tableCodeLabel); // 如果可用,添加显示字段标签 // if (field.referenceTable?.displayFields) { // const displayFields = field.referenceTable.displayFields; // const columnWidths = getColumnWidths(fieldElement, field.type); // const dataExist = !!fieldElement.querySelector('tbody > tr'); // const displayLabels = createFieldLabels(displayFields, columnWidths, field.type, dataExist); // safelyInsertLabel(fieldElement, displayLabels); // } } catch (error) { console.error(`Failed to add label for reference table field ${field.code}:`, error); } } /** * 为组字段元素添加标签 * @param {Object} field - 字段配置信息 * @param {HTMLElement} fieldElement - 字段 DOM 元素 */ addGroupLabel(field, fieldElement) { try { // 在组的父元素之前添加标签 const parentElement = field.dom.querySelector(`.${DOM_CLASSES.INSERT_GROUP_LABEL_ELEMENT}`); if (!parentElement) { // TODO error return; } const groupLabel = createFieldWithLabels({ code: field.code, type: field.type, }); groupLabel.style.top = STYLES.GROUP_LABEL_TOP; safelyAppendLabel(parentElement, groupLabel); const subLayout = this.groupLayoutMap[field.id]?.layout || []; for (const subRow of subLayout) { for (const subField of subRow.fields) { const subFieldElement = subField.dom.querySelector(`.${DOM_CLASSES.INSERT_LABEL_ELEMENT}`); this.addStandardFieldLabel(subField, subFieldElement); } } } catch (error) { console.error(`Failed to add label for group field ${field.code}:`, error); } } /** * 为标准字段元素添加标签 * @param {Object} field - 字段配置信息 * @param {HTMLElement} fieldElement - 字段 DOM 元素 */ addStandardFieldLabel(field, fieldElement) { if (!fieldElement) { return; } try { const fieldLabel = createFieldWithLabels({ code: field.code, type: field.type, }); safelyAppendLabel(fieldElement, fieldLabel); } catch (error) { console.error(`Failed to add label for standard field ${field.code}:`, error); } } /** * 处理并为页面上的所有字段元素添加标签 * @param {Array} fieldsWithLabels - 已处理的字段对象数组 */ processFieldLabels(fieldsWithLabels) { try { for (const field of Object.values(this.fieldMap)) { try { // 获取字段元素 const fieldElement = field.dom.querySelector(`.${DOM_CLASSES.INSERT_LABEL_ELEMENT}`); // 根据字段类型选择合适的标签添加方法 if (FieldTypeChecker.isSubtable(field)) { this.addSubtableLabel(field, fieldElement); } else if (FieldTypeChecker.isReferenceTable(field)) { this.addReferenceTableLabel(field, fieldElement); } else if (FieldTypeChecker.isGroup(field)) { this.addGroupLabel(field, fieldElement); } else { this.addStandardFieldLabel(field, fieldElement); } } catch (fieldError) { console.error(`Error occurred while processing label for field ${field.code}:`, fieldError); } } } catch (error) { console.error('Error occurred while processing field labels:', error); throw error; } } /** * 处理并为页面上的间距元素添加标签 * @param {Array} spacerElements - 间距元素配置数组 */ processSpacerLabels() { try { for (const spacer of Object.values(this.spacerMap)) { const spacerElement = spacer.dom.querySelector(`.${DOM_CLASSES.INSERT_SPACER_LABEL_ELEMENT}`); // 添加标签并设置边框 const spacerLabel = createFieldWithLabels({ code: spacer.elementId, type: spacer.type, }); safelyAppendLabel(spacerElement, spacerLabel); } } catch (error) { console.error('Error occurred while processing spacer element labels:', error); throw error; } } }