Skip to content
Snippets Groups Projects
useValidation.tsx 3.16 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { useActions } from '../../../overmind';
    
    import { useAtomValue, useSetAtom } from 'jotai';
    import { useTranslation } from 'react-i18next';
    import { currentContentAtom, xmlValidityAtom } from '../store';
    
    const {XMLValidator} = require('fast-xml-parser');
    
    
    export type XMLValidity =
      | { valid: true }
      | {
          valid: false;
          error: {
            message: string;
            positions?: {
              line: number;
              col: number;
            }[];
          };
        };
    
    export const useValidation = () => {
      const { openDialog } = useActions().ui;
      const { t } = useTranslation('leafwriter');
      const currentContent = useAtomValue(currentContentAtom);
      const setXmlValidity = useSetAtom(xmlValidityAtom);
    
      const checkValidity = () => {
    
        // Use fast-xml-parser to determine validty of XML document instead of canadian solution using DOM-Parser because
        // the return values of DOMParser are not cross-browser compatible, the canadian way of interpreting them works only
        // on chrom(e/ium)-based browser, we, however, test against Firefox first and foremost.
        // One cavecat of using fast-xml-parser is, that the error message is not translated. However, persons directly editing XML
        // should understand english well enough to at least understand the error message.
        /*
    
        const parser = new DOMParser();
        const doc = parser.parseFromString(currentContent, 'application/xml');
        const errorNode = doc.querySelector('parsererror');
        const errorString = errorNode?.querySelector('div')?.textContent;
    
        if (!errorString) {
          const validity: XMLValidity = { valid: true };
          setXmlValidity(validity);
          return validity;
        }
    
        const lines = [...errorString.matchAll(/line ([0-9]*)/g)];
        const column = [...errorString.matchAll(/column ([0-9]*)/g)];
    
        */
        const result = XMLValidator.validate(currentContent, {
          allowBooleanAttributes: true
        });
    
        //console.log(result)
    
        if (result === true) {
          const validity: XMLValidity = { valid: true };
          setXmlValidity(validity);
          return validity;
        }
    
        const positions = [{
          line: result["err"]["line"],
          col: result["err"]["col"],
        }];
    
            message: result["err"]["msg"],
    
            positions: positions,
          },
        };
    
        setXmlValidity(validity);
    
        return validity;
      };
    
      const handleValidationWarning = async (message: string): Promise<boolean> => {
        return new Promise((resolve) => {
          openDialog({
            type: 'simple',
            props: {
              maxWidth: 'xs',
              severity: 'warning',
              title: t('leafwriter:xml_document_invalid'),
              Body: () => message,
              actions: [
                { action: 'cancel', label: t('leafwriter:commons.cancel') },
                {
                  action: 'discard',
                  label: t('leafwriter:commons.discard_changes'),
                  variant: 'outlined',
                },
              ],
              onClose: async (action) => {
                if (action === 'discard') return resolve(true);
                return resolve(false);
              },
            },
          });
        });
      };
    
      return {
        checkValidity,
        handleValidationWarning,
      };
    };