forked from FINAKON/HelpProject
1. Initial Commit - a boiler plate code and POC to realize the concept of context sensitive help 2. Frontend code written in ReactJS 3. Backend code written in Java, Spring Boot Framework 4. Frontend Start: pre-requisites : node, npm npm run dev ==> to start the frontend vite server 5. Backend Start: pre-requisites : java, mvn mvn spring-boot:run ==> to start the backend server 6. Visit http://localhost:5173/ for basic demo of help, press F1 in textboxes 7. Visit http://localhost:5173/editor and enter "admin123" to add/modify texts. Happy Coding !!! Thank you, Bhargava.
169 lines
5.1 KiB
JavaScript
169 lines
5.1 KiB
JavaScript
import { TAG_NAMES as $, NS, hasUnescapedText } from '../common/html.js';
|
|
import { escapeText, escapeAttribute } from 'entities/escape';
|
|
import { defaultTreeAdapter } from '../tree-adapters/default.js';
|
|
// Sets
|
|
const VOID_ELEMENTS = new Set([
|
|
$.AREA,
|
|
$.BASE,
|
|
$.BASEFONT,
|
|
$.BGSOUND,
|
|
$.BR,
|
|
$.COL,
|
|
$.EMBED,
|
|
$.FRAME,
|
|
$.HR,
|
|
$.IMG,
|
|
$.INPUT,
|
|
$.KEYGEN,
|
|
$.LINK,
|
|
$.META,
|
|
$.PARAM,
|
|
$.SOURCE,
|
|
$.TRACK,
|
|
$.WBR,
|
|
]);
|
|
function isVoidElement(node, options) {
|
|
return (options.treeAdapter.isElementNode(node) &&
|
|
options.treeAdapter.getNamespaceURI(node) === NS.HTML &&
|
|
VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
|
|
}
|
|
const defaultOpts = { treeAdapter: defaultTreeAdapter, scriptingEnabled: true };
|
|
/**
|
|
* Serializes an AST node to an HTML string.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* const parse5 = require('parse5');
|
|
*
|
|
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
|
|
*
|
|
* // Serializes a document.
|
|
* const html = parse5.serialize(document);
|
|
*
|
|
* // Serializes the <html> element content.
|
|
* const str = parse5.serialize(document.childNodes[1]);
|
|
*
|
|
* console.log(str); //> '<head></head><body>Hi there!</body>'
|
|
* ```
|
|
*
|
|
* @param node Node to serialize.
|
|
* @param options Serialization options.
|
|
*/
|
|
export function serialize(node, options) {
|
|
const opts = { ...defaultOpts, ...options };
|
|
if (isVoidElement(node, opts)) {
|
|
return '';
|
|
}
|
|
return serializeChildNodes(node, opts);
|
|
}
|
|
/**
|
|
* Serializes an AST element node to an HTML string, including the element node.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* const parse5 = require('parse5');
|
|
*
|
|
* const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
|
|
*
|
|
* // Serializes the <div> element.
|
|
* const str = parse5.serializeOuter(document.childNodes[0]);
|
|
*
|
|
* console.log(str); //> '<div>Hello, <b>world</b>!</div>'
|
|
* ```
|
|
*
|
|
* @param node Node to serialize.
|
|
* @param options Serialization options.
|
|
*/
|
|
export function serializeOuter(node, options) {
|
|
const opts = { ...defaultOpts, ...options };
|
|
return serializeNode(node, opts);
|
|
}
|
|
function serializeChildNodes(parentNode, options) {
|
|
let html = '';
|
|
// Get container of the child nodes
|
|
const container = options.treeAdapter.isElementNode(parentNode) &&
|
|
options.treeAdapter.getTagName(parentNode) === $.TEMPLATE &&
|
|
options.treeAdapter.getNamespaceURI(parentNode) === NS.HTML
|
|
? options.treeAdapter.getTemplateContent(parentNode)
|
|
: parentNode;
|
|
const childNodes = options.treeAdapter.getChildNodes(container);
|
|
if (childNodes) {
|
|
for (const currentNode of childNodes) {
|
|
html += serializeNode(currentNode, options);
|
|
}
|
|
}
|
|
return html;
|
|
}
|
|
function serializeNode(node, options) {
|
|
if (options.treeAdapter.isElementNode(node)) {
|
|
return serializeElement(node, options);
|
|
}
|
|
if (options.treeAdapter.isTextNode(node)) {
|
|
return serializeTextNode(node, options);
|
|
}
|
|
if (options.treeAdapter.isCommentNode(node)) {
|
|
return serializeCommentNode(node, options);
|
|
}
|
|
if (options.treeAdapter.isDocumentTypeNode(node)) {
|
|
return serializeDocumentTypeNode(node, options);
|
|
}
|
|
// Return an empty string for unknown nodes
|
|
return '';
|
|
}
|
|
function serializeElement(node, options) {
|
|
const tn = options.treeAdapter.getTagName(node);
|
|
return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
|
|
}
|
|
function serializeAttributes(node, { treeAdapter }) {
|
|
let html = '';
|
|
for (const attr of treeAdapter.getAttrList(node)) {
|
|
html += ' ';
|
|
if (attr.namespace) {
|
|
switch (attr.namespace) {
|
|
case NS.XML: {
|
|
html += `xml:${attr.name}`;
|
|
break;
|
|
}
|
|
case NS.XMLNS: {
|
|
if (attr.name !== 'xmlns') {
|
|
html += 'xmlns:';
|
|
}
|
|
html += attr.name;
|
|
break;
|
|
}
|
|
case NS.XLINK: {
|
|
html += `xlink:${attr.name}`;
|
|
break;
|
|
}
|
|
default: {
|
|
html += `${attr.prefix}:${attr.name}`;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
html += attr.name;
|
|
}
|
|
html += `="${escapeAttribute(attr.value)}"`;
|
|
}
|
|
return html;
|
|
}
|
|
function serializeTextNode(node, options) {
|
|
const { treeAdapter } = options;
|
|
const content = treeAdapter.getTextNodeContent(node);
|
|
const parent = treeAdapter.getParentNode(node);
|
|
const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
|
|
return parentTn &&
|
|
treeAdapter.getNamespaceURI(parent) === NS.HTML &&
|
|
hasUnescapedText(parentTn, options.scriptingEnabled)
|
|
? content
|
|
: escapeText(content);
|
|
}
|
|
function serializeCommentNode(node, { treeAdapter }) {
|
|
return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
|
|
}
|
|
function serializeDocumentTypeNode(node, { treeAdapter }) {
|
|
return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
|
|
}
|