js/CustomFields.js


// ===========================================================
// Custom field class
// ===========================================================
/**
 * CustomFields class for handling custom form fields.
 * @extends require("www/js/BasicEventHandler.js")
 */
class CustomFields extends require("www/js/BasicEventHandler.js") {
    /**
     * Constructor for CustomFields class.
     * @param {jQuery|Object} $form - jQuery object or object representing form.
     * @param {Object} [options={}] - Options for customization.
     */
    constructor($form, options = {}) {
        super($form);


        // Warns about creation
        console.warn("Creating custom fields", arguments);

        // Handling different argument scenarios
        // if (arguments.length == 1 && typeof $form == "object" && $form.constructor.name !== "jQuery") {
        //     options = {
        //         jsonForm: $form
        //     }
        //     $form = $("<form></form>");
        //     $form.submit(false);
        // }
		if (arguments.length == 1) {
			options = CustomFields.sanitize(arguments[0]);
			$form = $("<form class='autogenerateForm'></form>");
		} else {
			options = CustomFields.sanitize(options);
			$form ||= $("<form></form>");
		}

        /**
         * jQuery form element.
         * @type {jQuery}
         */
        this.$elm = $form;
		this.$elm.on("submit", (e)=> {
			e.preventDefault();
		});

		this.getElm = function() {
			return this.$elm;
		}


        /**
         * Initialize the CustomFields instance.
         */
        this.init = (value) => {
			this.$elm.empty();
			if (value) {
				if (options.jsonForm) {
					options.jsonForm.value = value;
				}
			}
            if (options.jsonForm) this.addJSONForm(options.jsonForm);
            if (options.html) this.addHTML(options.html);
            console.warn("CustomFields rendered", this);
            this.resolveState("ready");
        };

        this.init();
    }

    /**
     * Adds JSON form to the form element.
     * @param {Object} [settings={}] - Settings for the JSON form.
     */
    addJSONForm(settings = {}) {
        console.log("Adding jsonform", settings);
        try {
            this.$elm.jsonForm(settings);
        } catch (e) {
            console.warn("Invalid jsonForm options", e);
        }
    }

    /**
     * Gets the JSON form tree.
     * @returns {Object} - JSON form tree data.
     */
    getJsonFormTree() {
        return this.$elm.data("jsonformTree");
    }

    /**
     * Validates the form.
     * @returns {boolean} - Validation result.
     */
    validate() {
        const ft = this.getJsonFormTree();
        if (!ft) return;
        return ft.validate();
    }

    /**
     * Adds HTML content to the form.
     * @param {jQuery} $elm - jQuery object representing HTML content.
     */
    addHTML($elm) {
        this.$elm.append($elm);
    }

    /**
     * Gets values from the form.
     * @returns {Object} - Form field values.
     */
    getValues() {
        let fd = new FormData(this.$elm[0]);
        return Object.fromEntries(fd);
    }

    /**
     * set values from the form.
     * @param {Object} values - Form field values.
     */
	setValues(values) {
		if (!values) return;
		this.init(values);
	}

	/**
     * Gets JSONForm's value.
     * @returns {Object} - Form field values.
     */
	getFormValues() {
		const jsonForm = this.getJsonFormTree();
		if (!jsonForm) throw new Error("Not a jsonform");
		return jsonForm.root.getFormValues()
	}

    /**
     * Sets value for a field by its name.
     * @param {string} name - Name of the field.
     * @param {any} val - Value to set.
     */
    setValueByName(name, val) {
        console.log("Updating value", name, val, "of", this);
        const $fld = this.$elm.find(`[name="${name}"]`);
        $fld.val(val);
    }
}

/**
 * Sanitizes options for CustomFields class.
 * @param {Object} option - Options object.
 * @returns {Object} - Sanitized options.
 */
CustomFields.sanitize = function(option) {
	console.log("CustomFields - sanitizing option", option);
	if (typeof option == "function") {
		option = option();
	}
    if (common.isHTMLNode(option)) return {
        html: option
    }
    if (CustomFields.isJsonForm(option)) return {
        jsonForm: option
    }
    return option;
};

/**
 * Checks if the data represents a JSON form.
 * @param {Object|string|function} [data={}] - Data to check.
 * @returns {boolean} - Whether the data represents a JSON form.
 */
CustomFields.isJsonForm = function(data = {}) {
    if (typeof data == "string") {
        if (common.isJSON(data)) data = JSON.parse(data);
    } else if (typeof data == "function") {
        data = data() || {};
    }
    if (!data) return false;
    if (data.constructor.name !== "Object") return false;
    if (!data?.schema && !data?.form) return false;
    return true;
};

module.exports = CustomFields;