MCPcopy
hub / github.com/tinymce/tinymce / whitespaceCleaner

Function whitespaceCleaner

modules/tinymce/src/core/main/ts/api/html/DomParser.ts:176–283  ·  view source on GitHub ↗
(root: AstNode, schema: Schema, settings: DomParserSettings, args: ParserArgs)

Source from the content-addressed store, hash-verified

174//
175// Returns [ preprocess, postprocess ]
176const whitespaceCleaner = (root: AstNode, schema: Schema, settings: DomParserSettings, args: ParserArgs): [WalkerCallback, WalkerCallback] => {
177 const validate = settings.validate;
178 const nonEmptyElements = schema.getNonEmptyElements();
179 const whitespaceElements = schema.getWhitespaceElements();
180 const blockElements: Record<string, string> = extend(makeMap(extraBlockLikeElements), schema.getBlockElements());
181 const textRootBlockElements = getTextRootBlockElements(schema);
182 const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
183 const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
184 const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
185
186 const hasWhitespaceParent = (node: AstNode) => {
187 let tempNode = node.parent;
188 while (Type.isNonNullable(tempNode)) {
189 if (tempNode.name in whitespaceElements) {
190 return true;
191 } else {
192 tempNode = tempNode.parent;
193 }
194 }
195 return false;
196 };
197
198 const isTextRootBlockEmpty = (node: AstNode) => {
199 let tempNode: AstNode | null | undefined = node;
200 while (Type.isNonNullable(tempNode)) {
201 if (tempNode.name in textRootBlockElements) {
202 return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
203 } else {
204 tempNode = tempNode.parent;
205 }
206 }
207 return false;
208 };
209
210 const isBlock = (node: AstNode) =>
211 node.name in blockElements || TransparentElements.isTransparentAstBlock(schema, node) || (Namespace.isNonHtmlElementRootName(node.name) && node.parent === root);
212
213 const isAtEdgeOfBlock = (node: AstNode, start: boolean): boolean => {
214 const neighbour = start ? node.prev : node.next;
215 if (Type.isNonNullable(neighbour) || Type.isNullable(node.parent)) {
216 return false;
217 }
218
219 // Make sure our parent is actually a block, and also make sure it isn't a temporary "context" element
220 // that we're probably going to unwrap as soon as we insert this content into the editor
221 return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
222 };
223
224 const preprocess = (node: AstNode) => {
225 if (node.type === 3) {
226 // Remove leading whitespace here, so that all whitespace in nodes to the left of us has already been fixed
227 if (!hasWhitespaceParent(node)) {
228 let text = node.value ?? '';
229 text = text.replace(allWhiteSpaceRegExp, ' ');
230
231 if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
232 text = text.replace(startWhiteSpaceRegExp, '');
233 }

Callers 1

parseFunction · 0.85

Calls 3

getTextRootBlockElementsFunction · 0.90
extendFunction · 0.85
makeMapFunction · 0.50

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…