/* eslint-disable prefer-const */ import type { IActivityHandler } from "@vertigis/workflow"; import html2canvas from 'html2canvas'; /** An interface that defines the inputs of the activity. */ interface HTMLextractorInputs { /** * @displayName CSS Selector * @description The string of css selector. * @required */ selector: string; /** * @displayName Request * @description Chose one from the following requests: "getImage","getProperty" */ request?: "getImage" | "getProperty"; /** * @displayName Additional Value(optional) * @description Additional value: If request is getProperty, put in property name like width; If request is getImage, put in whiteBackground to force background to be white */ value?: string; } /** An interface that defines the outputs of the activity. */ interface HTMLextractorOutputs { /** * @description The result of the activity. */ result: string; } /** * @displayName Extract HTML Element by CSS Selector * @category EBTA Utilities * @description Extract screenshot or attribute of HTML component by a css selector */ function convertSVGTagstoIMG(container) { let svgElements: NodeListOf = container.querySelectorAll('svg[role="img"]'); let SVGDom = Array.from(svgElements).filter(svg => { let svgElement = svg; let gTag = svgElement.querySelector('g'); return gTag && gTag.querySelector('image'); }); SVGDom.forEach(svg => { let svgElement = svg; // Create a new element let img = document.createElement('img'); let imageDOM = svgElement.querySelector('image'); if (imageDOM) { let imageurl = imageDOM.getAttribute('href'); // Transfer the relevant attributes img.alt = imageDOM.getAttribute('alt') || ''; img.src = imageurl || ''; // Use xlink:href for the src img.width = parseInt(imageDOM.getAttribute('width') || '0'); img.height = parseInt(imageDOM.getAttribute('height') || '0'); svg.parentNode!.replaceChild(img, svg); } else { console.log('No image found inside svg.'); } }); console.log('IMG conversion finished'); } async function captureElementByCSSToFile(css: string,mode?:string): Promise { // Query the DOM for the first element with the specified class name const element :HTMLElement = document.querySelector(css)!; if (!element) { throw new Error(`Element with selector ${css} not found`); } // Ensure all external images have the crossOrigin attribute set try { convertSVGTagstoIMG(element) const images:NodeListOf = element.querySelectorAll('img[src]') ; images.forEach((img) => { if (!img.crossOrigin) { img.crossOrigin = 'anonymous'; } }); let originalStyles let children : NodeListOf = element.querySelectorAll('*'); let originalChildStyles:{element: HTMLElement, backgroundColor: string, color: string}[] = []; if (mode=='whiteBackground'){ originalStyles= { backgroundColor: element.style.backgroundColor, color: element.style.color }; // Reverse the dark mode styles element.style.backgroundColor = 'white'; element.style.color = 'black'; // Apply the same style changes to all children, and backup the original children.forEach(child => { originalChildStyles.push({ element: child, backgroundColor: child.style.backgroundColor, color: child.style.color }); child.style.backgroundColor = 'white'; child.style.color = 'black'; }); } // Capture the element using html2canvas with useCORS option const canvas = await html2canvas(element, { useCORS: true, logging: true, backgroundColor: '#ffffff', allowTaint: true , scale:2.5 }); // Convert the canvas to Base64 image let imageBase64 = canvas.toDataURL("image/jpeg"); if (mode=='whiteBackground'){ // Revert to the original styles element.style.backgroundColor = originalStyles.backgroundColor; element.style.color = originalStyles.color; // Revert the styles of all children originalChildStyles.forEach(({ element, backgroundColor, color }) => { element.style.backgroundColor = backgroundColor; element.style.color = color; }); } return imageBase64; } catch (error) { throw new Error(`Failed to capture legend screenshot: ${(error as Error).message}`); } } /** * @displayName HTMLextractor * @category Custom Activities * @description Extract screenshot or attribute of HTML component by a css selector */ export default class HTMLextractorActivity implements IActivityHandler { /** Perform the execution logic of the activity. */ async execute(inputs: HTMLextractorInputs): Promise { const element :HTMLElement = document.querySelector(inputs.selector)!; console.log('HTML element:') console.log(element) let result if (!element) { throw new Error(`Element with query: ' ${inputs.selector} ' not found`); } if(inputs.request=='getProperty'){ const computedStyle = window.getComputedStyle(element); result=inputs.value? computedStyle[inputs.value]:'cannot get property' } else if(inputs.request=='getImage'){ result = await captureElementByCSSToFile(inputs.selector,inputs.value); } return { result: result }; } }