utils_ui_traverse-component-tree-with-callback.js

/**
 * @callback TraverseComponentTreeCallback
 * @param {nexacro.Component} component
 * 컴포넌트
 * @param {TraverseComponentTreeCallbackContext} context
 * 유틸성 함수
 */

/**
 * @typedef TraverseComponentTreeCallbackContext
 * @property {function} stopChildNodeTraversal
 * 트리 순회를 중단
 */

/**
 * 인수로 받은 컴포넌트의 하위 컴포넌트를 순회하며 callback 함수 호출
 * stopChildNodeTraversal() 함수를 호출 하면 해당 컴포넌트 하위 영역 순환을 중단함.
 *
 * @function traverseComponentTreeWithCallback
 * @param {nexacro.Component} comp
 * - root 컴포넌트
 * @param {TraverseComponentTreeCallback} callback
 * - 실행할 콜백함수
 * @memberof $f
 * @example
 * $f.traverseComponentTreeWithCallback(this.div_search, (comp, ctx) => {
 *     // 모든 컴포넌트의 readonly 속성을 true로 설정
 *     comp.readonly = true;
 *
 *     // div_exclude라는 이름을 가진 컴포넌트를 만나면
 *     if (comp.name === "div_exclude") {
 *         // 해당 컴포넌트의 하위 컴포넌트 순회를 중단
 *         ctx.stopChildNodeTraversal();
 *     }
 * });
 *
 */
export function traverseComponentTreeWithCallback(comp, callback) {
    let isStopTraversal = false;

    const callbackArgs = {
        stopChildNodeTraversal: () => {
            isStopTraversal = true;
        },
    };
    callback(comp, callbackArgs);

    if (isStopTraversal) return;

    if (comp instanceof nexacro.Form) {
        Array.from(comp.all).forEach((v) =>
            traverseComponentTreeWithCallback(v, callback),
        );
    } else if (comp instanceof nexacro.Div) {
        traverseComponentTreeWithCallback(comp.form, callback);
    } else if (comp instanceof nexacro.Tab) {
        Array.from(comp.tabpages).forEach((v) =>
            traverseComponentTreeWithCallback(v, callback),
        );
    } else if (comp instanceof nexacro.Tabpage) {
        traverseComponentTreeWithCallback(comp.form, callback);
    }
}