Browse Source

Add `parse:html:before` and `parse:css:before` events

pull/6397/head
Artur Arseniev 2 years ago
parent
commit
5d41c1f7da
  1. 10
      packages/core/src/parser/model/ParserCss.ts
  2. 9
      packages/core/src/parser/model/ParserHtml.ts
  3. 22
      packages/core/src/parser/types.ts
  4. 25
      packages/core/test/specs/parser/model/ParserCss.ts
  5. 16
      packages/core/test/specs/parser/model/ParserHtml.ts

10
packages/core/src/parser/model/ParserCss.ts

@ -8,15 +8,19 @@ import { ParserEvents } from '../types';
const ParserCss = (em?: EditorModel, config: ParserConfig = {}) => ({
/**
* Parse CSS string to a desired model object
* @param {String} input CSS string
* @param {String} str CSS string
* @return {Array<Object>}
*/
parse(input: string, opts: { throwOnError?: boolean } = {}) {
parse(str: string, opts: { throwOnError?: boolean } = {}) {
let output: CssRuleJSON[] = [];
const { parserCss } = config;
const editor = em?.Editor;
let nodes: CssRuleJSON[] | ParsedCssRule[] = [];
let error: unknown;
const Parser = em?.Parser;
const inputOptions = { input: str };
Parser?.__emitEvent(ParserEvents.cssBefore, inputOptions);
const { input } = inputOptions;
try {
nodes = parserCss ? parserCss(input, editor!) : BrowserCssParser(input);
@ -26,7 +30,7 @@ const ParserCss = (em?: EditorModel, config: ParserConfig = {}) => ({
}
nodes.forEach((node) => (output = output.concat(this.checkNode(node))));
em?.Parser?.__emitEvent(ParserEvents.css, { input, output, nodes, error });
Parser?.__emitEvent(ParserEvents.css, { input, output, nodes, error });
return output;
},

9
packages/core/src/parser/model/ParserHtml.ts

@ -312,6 +312,7 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo
*/
parse(str: string, parserCss?: any, opts: HTMLParserOptions = {}) {
const conf = em?.get('Config') || {};
const Parser = em?.Parser;
const res: HTMLParseResult = { html: [] };
const cf = { ...config, ...opts };
const preOptions = {
@ -325,7 +326,9 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo
asDocument: this.__checkAsDocument(str, preOptions),
};
const { preParser, asDocument } = options;
const input = isFunction(preParser) ? preParser(str, { editor: em?.getEditor()! }) : str;
const inputOptions = { input: isFunction(preParser) ? preParser(str, { editor: em?.getEditor()! }) : str };
Parser?.__emitEvent(ParserEvents.htmlBefore, inputOptions);
const { input } = inputOptions;
const parseRes = isFunction(cf.parserHtml) ? cf.parserHtml(input, options) : BrowserParserHtml(input, options);
let root = parseRes as HTMLElement;
const docEl = parseRes as Document;
@ -365,7 +368,7 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo
if (styleStr) res.css = parserCss.parse(styleStr);
}
em?.Parser?.__emitEvent(ParserEvents.htmlRoot, { input, root });
Parser?.__emitEvent(ParserEvents.htmlRoot, { input, root });
let resHtml: HTMLParseResult['html'] = [];
if (asDocument) {
@ -379,7 +382,7 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo
}
res.html = resHtml;
em?.Parser?.__emitEvent(ParserEvents.html, { input, output: res, options });
Parser?.__emitEvent(ParserEvents.html, { input, output: res, options });
return res;
},

22
packages/core/src/parser/types.ts

@ -8,6 +8,17 @@ export enum ParserEvents {
html = 'parse:html',
htmlRoot = 'parse:html:root',
/**
* @event `parse:html:before` Event triggered before the HTML parsing starts. An object containing the input is passed as an argument.
* @example
* editor.on('parse:html:before', (options) => {
* console.log('Parser input', options.input);
* // You can also process the input and update `options.input`
* options.input += '<div>Extra content</div>';
* });
*/
htmlBefore = 'parse:html:before',
/**
* @event `parse:css` On CSS parse, an object containing the input and the output of the parser is passed as an argument.
* @example
@ -15,6 +26,17 @@ export enum ParserEvents {
*/
css = 'parse:css',
/**
* @event `parse:css:before` Event triggered before the CSS parsing starts. An object containing the input is passed as an argument.
* @example
* editor.on('parse:css:before', (options) => {
* console.log('Parser input', options.input);
* // You can also process the input and update `options.input`
* options.input += '.my-class { color: red; }';
* });
*/
cssBefore = 'parse:css:before',
/**
* @event `parse` Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
* @example

25
packages/core/test/specs/parser/model/ParserCss.ts

@ -18,16 +18,25 @@ export const CSS_BG_OBJ = {
describe('ParserCss', () => {
let obj: ReturnType<typeof ParserCss>;
let config;
let customParser: any;
let em = {
getCustomParserCss: () => customParser,
trigger: () => {},
} as unknown as EditorModel;
let em: EditorModel;
beforeEach(() => {
config = {};
obj = ParserCss(em, config);
em = new EditorModel({});
obj = ParserCss(em, {});
});
afterEach(() => {
em.destroy();
});
test('Extend parser input', () => {
const str = ' .test1 { color:red; }';
const result = {
selectors: ['test1'],
style: { color: 'red' },
};
em.on(em.Parser.events.cssBefore, (opts) => (opts.input += str));
expect(obj.parse(str)).toEqual([result, result]);
});
describe('parseSelector', () => {

16
packages/core/test/specs/parser/model/ParserHtml.ts

@ -6,9 +6,10 @@ import { CSS_BG_OBJ, CSS_BG_STR } from './ParserCss';
describe('ParserHtml', () => {
let obj: ReturnType<typeof ParserHtml>;
let em: Editor;
beforeEach(() => {
const em = new Editor({});
em = new Editor({});
const dom = new DomComponents(em);
obj = ParserHtml(em, {
textTags: ['br', 'b', 'i', 'u'],
@ -18,6 +19,19 @@ describe('ParserHtml', () => {
obj.compTypes = dom.componentTypes;
});
afterEach(() => {
em.destroy();
});
test('Extend parser input', () => {
const str = '<div></div>';
const result = { tagName: 'div' };
em.on(em.Parser.events.htmlBefore, (opts) => {
opts.input += str;
});
expect(obj.parse(str).html).toEqual([result, result]);
});
test('Simple div node', () => {
const str = '<div></div>';
const result = [{ tagName: 'div' }];

Loading…
Cancel
Save