From 3ad21d2c82c81abf6b8dd1a29fb93f453e697d30 Mon Sep 17 00:00:00 2001 From: rdbsolutions Date: Tue, 28 Jan 2025 12:57:52 +0000 Subject: [PATCH] questionnaire defect 67, enf 16,reps 42 --- components/case/representation/index.js | 7 +- .../representation/representationElements.js | 4 +- components/utils/index.js | 112 +++++++++--------- package.json | 1 + 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/components/case/representation/index.js b/components/case/representation/index.js index bd8b4a37..9ec3af74 100644 --- a/components/case/representation/index.js +++ b/components/case/representation/index.js @@ -865,6 +865,7 @@ let MakeRepresentation = (props) => { ? (Object.assign(values, { "filesList": props.currentView.fileList, }), + (values = updateLinks(values)), uploadRepresentationFiles(values), router.replace( router.locale != "en" @@ -875,6 +876,7 @@ let MakeRepresentation = (props) => { "filesList": props.currentView.fileList, }), console.log("Rep Updated - ", props.caseReference), + (values = updateLinks(values)), uploadRepresentationFiles(values); }; @@ -1046,7 +1048,8 @@ let MakeRepresentation = (props) => { ).then((data) => { console.log(data); data.status == "success" && - (uploadRepresentationFiles(values), + ((values = updateLinks(values)), + uploadRepresentationFiles(values), setRepresentationSubmit(true), setRepresentationSubmitConfirmation(true)); }); @@ -1100,8 +1103,6 @@ let MakeRepresentation = (props) => { ? cleanFilesList(values) : values; - values = updateLinks(values); - // get filelists from values object let fileListObj = _.filter(values, function (v, key) { return _.includes(key, "representationDocuments"); diff --git a/components/case/representation/representationElements.js b/components/case/representation/representationElements.js index fd97ae60..8de8e02b 100644 --- a/components/case/representation/representationElements.js +++ b/components/case/representation/representationElements.js @@ -2,7 +2,7 @@ import useTranslation from "next-translate/useTranslation"; import dynamic from "next/dynamic"; import Link from "next/link"; import router from "next/router"; -import React, { useMemo, useState } from "react"; +import React, { useMemo, useState, useRef } from "react"; import DatePicker from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; import Dropzone from "react-dropzone"; @@ -726,7 +726,7 @@ export const RenderMultiline = ({ toolbar: [ [{ "header": [1, 2, false] }], ["bold", "italic", "underline", "blockquote"], - [{ "list": "ordered" }, { "list": "bullet" }, "link"], + [{ "list": "ordered" }, { "list": "bullet" }], ["clean"], ], }; diff --git a/components/utils/index.js b/components/utils/index.js index 51280560..296d8f4d 100644 --- a/components/utils/index.js +++ b/components/utils/index.js @@ -551,66 +551,72 @@ export const getDocumentTypeFromFilename = (filename) => { return doctypeCode; }; -export const updateLinks = (jsonObject) => { - const wrapPlainUrlsInAnchorTags = (htmlString) => { - return htmlString - .replace( - /(?<=^|>|\s)(?=\S)(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(?:\/[^\s]*)?(?=\s|<|$)/g, - (match) => { - // If the match is already wrapped in tag, return it as is - if (match.includes(' { + const parser = new DOMParser(); + + // Function to process the HTML string and replace URLs with tags + const processHtmlString = (htmlString) => { + const doc = parser.parseFromString(htmlString, "text/html"); + + // Find all text nodes in the document + const walk = (node) => { + if (node.nodeType === Node.TEXT_NODE) { + // Check if the text node contains a URL (simple check for a URL pattern) + const urlRegex = + /(?:https?:\/\/)?(?:www\.)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/[^\s]*)?/g; + let match; + + // Process the text node if it contains a URL + while ((match = urlRegex.exec(node.textContent)) !== null) { + // Construct the full URL by adding the protocol if missing, and the domain and path + let fullUrl = match[0]; + if ( + !fullUrl.startsWith("http://") && + !fullUrl.startsWith("https://") + ) { + fullUrl = `https://${match[1]}${match[2] || ""}`; // Default to https } - // Check if the URL starts with http:// or https://, else prepend http:// - const url = - match.startsWith("http://") || - match.startsWith("https://") - ? match - : "https://" + match; - // Return the URL wrapped in tag - return `${match}`; + // Check if the match is already inside an tag, if so, skip it + if (node.parentNode.tagName !== "A") { + const anchor = document.createElement("a"); + anchor.href = fullUrl; + anchor.textContent = match[0]; + + // Add rel="noopener noreferrer" for security + anchor.setAttribute("rel", "noopener noreferrer"); + + // Replace the URL with the anchor element in the text node + const range = document.createRange(); + range.selectNodeContents(node); + range.deleteContents(); + range.insertNode(anchor); + } } - ) - .replace( - /]*>]*>(.*?)<\/a><\/a>/g, - (match, innerContent) => { - return `${innerContent}`; - } - ); - }; - // Helper function to ensure that any href attributes in tags have https/http - const ensureHttpsInLinks = (inputString) => { - // Match tags with href attributes and check if they lack a scheme (http:// or https://) - return inputString.replace( - /]*href=["']([^"']*)["'][^>]*>/g, - (match, url) => { - // If the URL doesn't already have a scheme (http:// or https://), add https:// - if (!/^https?:\/\//.test(url)) { - const newUrl = `https://${url}`; - return match.replace(url, newUrl); - } - return match; // Return the unchanged anchor tag if it already has a scheme } - ); + + // Traverse child nodes + for (let i = 0; i < node.childNodes.length; i++) { + walk(node.childNodes[i]); + } + }; + + walk(doc.body); + + return doc.body.innerHTML; }; - // Iterate through all properties of the JSON object - Object.keys(jsonObject).forEach((key) => { - const value = jsonObject[key]; + // Iterate over the JSON object and process values that are strings (HTML content) + for (const key in jsonObj) { + if (jsonObj.hasOwnProperty(key)) { + const value = jsonObj[key]; - // If the value is a string and contains plain URLs that are not wrapped - if (typeof value === "string") { - // Step 1: Wrap plain URLs in anchor tags if not already wrapped - let updatedValue = wrapPlainUrlsInAnchorTags(value); - - // Step 2: Ensure that hrefs in anchor tags have https:// or http:// - updatedValue = ensureHttpsInLinks(updatedValue); - - // Assign the updated value back to the key - jsonObject[key] = updatedValue; + // If the value is a string and contains HTML, process it + if (typeof value === "string" && /<[^>]*>/g.test(value)) { + jsonObj[key] = processHtmlString(value); + } } - }); + } - return jsonObject; + return jsonObj; }; diff --git a/package.json b/package.json index d588389c..3bc3b484 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-leaflet": "^4.2.1", "react-pdf": "^7.6.0", "react-pdf-html": "^1.1.18", + "react-quill": "^2.0.0", "react-quill-new": "^3.3.3", "react-redux": "^7.2.6", "redux": "^4.2.1",