diff --git a/docs/assets/extra.css b/docs/assets/extra.css index de7a641..4a42324 100644 --- a/docs/assets/extra.css +++ b/docs/assets/extra.css @@ -1,4 +1,8 @@ :root { --md-primary-fg-color: rgb(196, 54, 39); --md-accent-fg-color: rgb(62, 139, 138); +} + +table { + box-sizing: initial; } \ No newline at end of file diff --git a/docs/event-system.md b/docs/event-system.md new file mode 100644 index 0000000..81b85b1 --- /dev/null +++ b/docs/event-system.md @@ -0,0 +1,238 @@ +## Introduction + +The Event System is the basis of the new Listener extensions, replacing the ["old" extension system](extensions.md) altogether. + +In short, the Event System lifecycle looks as follows: + +1. A sub-parser emits an event. + + !!! note "" + Each sub-parser can emit a batch of events (see the list below) + +1. Extension A (which is a _Listener Extension_) registers and listens to a specific event. + + !!! note "" + An extension can only register for a specific event + +1. Extension A receives an event object and modifies it. + + !!! note "" + Certain properties of the event object can be changed, which will change the behavior or output of the sub-parser + +1. Extension A returns the event object to the converter. +1. The converter passes the received event object to the next extension in the chain. + +## Event Object + +### Properties + +#### matches + +**matches** is an object that holds the text captured by the sub-parser. The properties of this object are different for each sub-parser. +Some properties can be read-only: their names start with `_` (underscore). + +!!! example "blockquote `onCapture` event" + + ```js + { + _wholeMatch: "> some awesome quote", + blockquote: "some awesome quote" + } + ``` + + + +## Event types + +Events are emitted when a sub-parser runs (or about to be run). +In the sub-parser, the events follow strict order sequence: [`onStart`](#onstart) -> [`onCapture`](#oncapture) -> [`onHash`](#onhash) -> [`onEnd`](#onend) + +It means that `.before` events always run before `.captureStart`. + +### onStart + +**`..onStart`**: **always runs** except if the sub-parser is disabled. + +Emitted when the sub-parser has started, but no capturing or modifications to the text were done. + +**Always runs** except if the sub-parser is disabled via options. + +!!! hint "When to use `onStart` event" + Use this event when you want to change the input passed to the sub-parser. + +!!! warning "" + Please note that the input is the **full text** that was passed to the converter. + +**Properties** + +| property | type | access | description | +|--------------|----------|---------|----------------------------------------------------------------| +| `input` | `string` | `read` | Full text that was passed to the subparser | +| `output` | `string` | `write` | Full text with modification that will be passed along the chain | +| `regexp` | `null` | | | +| `matches` | `null` | | | +| `attributes` | `null` | | | + +### onCapture + +**`..onCapture`**: *might not be run*. + +Emitted when a regex match is found and capture was successful. +Further normalization and modification of the regex captured groups might be performed. + +Might not be run if no regex match found. + +!!! hint "When to use `onCapture` event" + Use this event if you want to: + + * modify the sub-parser behavior, text; + * modify the HTML output of the sub-parser. + +**Properties** + +| property | type | access | description | +|--------------|----------|--------------|-------------------------------------------------------------------| +| `input` | `string` | `readonly` | The captured text | +| `output` | `string` | `write` | `null` or well-formed HTML (see the Important Note below) | +| `regexp` | `RegExp` | `readonly` | Regular Expression to capture groups | +| `matches` | `object` | `read/write` | Match groups. Changes to this object are reflected in the output. | +| `attributes` | `object` | `read/write` | Attributes to add to the HTML output | + +!!! warning "IMPORTANT NOTE" + Extensions listening to the `onCapture` event **should avoid** changing the output property. + Instead, they should modify the values of the matches and attribute objects. + + The reason is that the **output property takes precedence over the matches objects** and + **prevents showdown from calling other sub-parsers** inside the captured fragment. + + The above means the following: + + 1. If something is passed as the output property, any changes to the matches and attributes objects will be ignored. + 1. Any changes made by other extensions to the matches or attributes objects will be ignored. + 1. Showdown will not call other sub-parsers, such as encode code or span gamut in the text fragment, which may lead to unexpected results. + + **Example** + + !!! example "" + + ```js hl_lines="4" + // Showdown extension 1 that is listening to makehtml.blockquote.onCapture + function extension_1 (showdownEvent) { + // Let's imagine you're a bad person who writes to output + showdownEvent.output = '
foo
'; // must be a well-formed HTML + showdownEvent.matches.blockquote = 'some nice quote'; + } + + // Showdown extension 2 that is also listening to makehtml.blockquote.onCapture + function extension_2 (showdownEvent) { + // I make blockquotes bold + let quote = showdownEvent.matches.blockquote; + showdownEvent.matches.blockquote = '' + quote + ''; + } + ``` + + In the example above, the result will always be `
foo
`, regardless of the order of extension loading and call. + +!!! danger "Infinite loop" + Do not pass the input as output to the `onCapture` event, or you might trigger an infinite loop. + +### onHash + +**`..onHash`**: *always runs*. + +Raised before the output is hashed. + +**Always runs** (except if the sub-parser is disabled via options), even if no hashing is performed. + +!!! hint "When to use `onHash` event" + Use this event when you want to change the sub-parser's raw output before it is hashed. + +**Properties** + +| property | type | access | description | +|--------------|----------|---------|----------------------------------------------| +| `input` | `string` | `read` | The captured text | +| `output` | `string` | `write` | The text that will be passed along the chain | +| `regexp` | `null` | | | +| `matches` | `null` | | | +| `attributes` | `null` | | | + +### onEnd + +**`..onEnd`**: **always runs**; + +Emitted when the sub-parser has finished its work and is about to exit. + +**Always runs** (except if the sub-parser is disabled via options). + +!!! hint "When to use `onEnd` event" + Use this event when you want to run code or perform changes to the text after the subparser has run and its output was hashed. + +!!! warning "" + Please note that the input is the **full text** and might contain hashed elements. + +**Properties** + +| property | type | access | description | +|-----------|----------|---------|-------------------------------------------------------------| +| `input` | `string` | `read` | Full text with the subparser modifications (contains hashes) | +| `output` | `string` | `write` | The text that will be passed to other subparsers | +| `regexp` | `null` | | | +| `matches` | `null` | | | + +## Special Events + +There are special events useful for *"positioning"* a listener extension in the main chain of events. +Usually, these extensions introduce new syntax that, due to precedence + +In contrary, the special events will always be called, regardless of options or circumstances. + +### .before.{subparserName} + +**`.before.{subparserName}`**: **always runs** + +Emitted just before the **`{subparserName}` is about to be entered**. + +**Properties** + +| property | type | access | description | +|-----------|----------|---------|----------------------------------------------------------------| +| `input` | `string` | `read` | Full text that was passed to the subparser | +| `output` | `string` | `write` | Full text with modification that will be passed along the chain | +| `regexp` | `null` | | | +| `matches` | `null` | | | + +!!! note "Difference between `before.{subparserName}` and `{subparserName}.start`" + + 1. **`before.{subparserName}`** is always guaranteed to be called, **even if the subparser is disabled**, + while **{subparserName}.start** isn't. + + For example, `makehtml.before.strikethrough` is always called even if the option `strikethrough` is `false`. + + 1. **`before.{subparserName}`** is only emitted **once** in a span context while **`{subparserName}.start`** is emitted + everytime **`{subparserName}`** is called. + + + +### .after.{subparserName} + +**`.after.{subparserName}`**: **always runs**; + +Emitted when the **`{subparserName}` has exited** and before the next one is called. + +**Properties** + +| property | type | access | description | +|-----------|----------|---------|---------------------------------------------------| +| `input` | `string` | `read` | Partial/full text with the subparser modifications | +| `output` | `string` | `write` | The text that will be passed to other subparsers | +| `regexp` | `null` | | | +| `matches` | `null` | | | + + diff --git a/docs/event_system.md b/docs/event_system.md deleted file mode 100644 index d5002aa..0000000 --- a/docs/event_system.md +++ /dev/null @@ -1,228 +0,0 @@ -# Event System ) - -## Introduction - -The Event System is the basis of the new Listener extensions, replacing the old extension system altogether. - -The life cycle can be summarized as this: - - - A subparsers emmits an event - - Each subparser can emmit a bunch of events (see list below) - - Extension A, which is a _Listener Extension_ registers and listens to a specific event - - An extension can only register to a specific event - - Extension A receives an event object and modifies it - - Certain properties of the event object can be changed, ehich will change the behavior or output of the subparser - - The extension then returns the event object - - The converter passes this event object to the next extension in the chain - - -Note: - -## The Event Object - -### Properties - -#### matches (type: **object**) - -This object holds the text captured by the subparser. The properties of this object -are different for each subparser. - -**Properties whose name starts with `_` are readonly**. - -Example: - -```js -// blockquote onCapture event -{ - _wholeMatch: "> some awesome quote", - blockquote: "some awesome quote" -} -``` - - -## Basic Event - - -## Event Types - -Events are raised when a subparser is run (or about to be run). -Within a subparser, the events always follow a certain order (sequence). For instance, **.before** events always run before **.captureStart**. -Each subparser raises several events sequentially: - -### onStart - -**`..onStart`**: **always runs** except if the subparser is disabled - -Raised when the **subparser has started**, but no capturing or any modification to the text was done. -**Always runs** (except if the subparser is deactivated through options). - -***Properties***: - -| property | type | access | description | -|------------|-----------|------------|--------------------------------------------------------------------| -| input | string | read | The full text that was passed to the subparser | -| output | string | write | The full text with modification that will be passed along the chain| -| regexp | null | | | -| matches | null | | | -| attributes | null | | | - - -Usually you would want to use this event if you wish to change the input to the subparser. Please note, -however, that the input text is the **complete text** that was fed to the converter. - -### onCapture - -**`..onCapture`**: *might not be run*; - -Raised when a regex match is found and a capture was successful. Some normalization and modification -of the regex captured groups might be performed. - -Might not be run if no regex match is found. - -***Properties***: - -| property | type | access | description | -|------------|----------|------------|--------------------------------------------------------------------| -| input | string | readonly | The captured text | -| output | string | write | null or well formed HTML (see note) | -| regexp | RegExp | readonly | Regular Expression used to capture groups | -| matches | object | read/write | Matches groups. Changes to this object are reflected in the output | -| attributes | object | read/write | Attributes to add to the HTML output | - -Usually you would want to use this event if you wish to modify the subparser behavior, text or modify the HTML output -of the subparser. - -**IMPORTANT NOTE**: Extensions listening to onCapture event should try to AVOID changing the output property. -Instead, they should modify the values of the matches and attributes objects. This is because -the **output property takes precedence over the matches objects** and **prevents showdown to call other subparsers** -inside the captured fragment.This means 3 very important things: - - 1. If something is passed as the output property, any changes to the matches and attributes objects will be ignored. - 2. Changes made by other extensions to the matches or attributes objects will also be ignored - 3. Showdown will not call other subparsers, such as encode code or span gamut in the text fragment, which may lead to - weird results. - -```javascript -// showdown extension 1 that is listening to makehtml.blockquote.onCapture -function extension_1 (showdownEvent) { - // i'm bad and write to output - showdownEvent.output = '
foo
'; // must be an well formed html string - showdownEvent.matches.blockquote = 'some nice quote'; -} - -// showdown extension 1 that is also listening to makehtml.blockquote.onCapture -function extension_2 (showdownEvent) { - // I make blockquotes become bold - let quote = showdownEvent.matches.blockquote; - showdownEvent.matches.blockquote = '' + quote + ''; -} - -// the result will always be
foo
, regardless of the order of extension loading and call -``` - - -### onHash - -**`..onHash`**: *always runs*; - -Raised before the output is hashed. **Always runs** (except if the subparser was deactivated through options), -even if no hashing is performed. - -***Properties***: - -| property | type | access | description | -|------------|------------|------------|--------------------------------------------------------------------| -| input | string | read | The captured text | -| output | string | write | The text that will be passed to the subparser/other listeners | -| regexp | null | | | -| matches | null | | | -| attributes | null | | | - -Usually you would want to use this event if you wish change the subparser's raw output before it is hashed. - -### onEnd - -**`..onEnd`**: *always runs*; - -Raised when the subparser has finished its work and is about to exit. - -Always runs (except if the subparser is deactivated through options). - -***Properties***: - -| property | type | access | description | -|----------|-----------|------------|--------------------------------------------------------------------| -| input | string | read | The full text with the subparser modifications (contains hashes) | -| output | string | write | The text that will be passed to other subparsers | -| regexp | null | | | -| matches | null | | | - -Usually you would want to use this event if you want to run code or perform changes to the text after the subparser was -run and it's output was hashed. Keep in mind that the input is the full text and might contain hashed elements. - - -### Special Events - -There are some special events that are useful for *"positioning"* a listener extension in the main chain of events. -Usually these extensions introduce new syntax that, due to precedence -These events are always guaranteed to be called, regardless of options or circumstances. - - 1. **.before_{subparserName}**: *always runs* - - Raised just before the **{subparserName} is about to be entered**. - - ***Properties***: - - | property | type | access | description | - |----------|-----------|------------|--------------------------------------------------------------------| - | input | string | read | The full text that was passed to the subparser | - | output | string | write | The full text with modification that will be passed along the chain| - | regexp | null | | | - | matches | null | | | - - 2. **.after**.{subparserName}: *always runs*; - - Raised when the **{subparserName} has exited** and before the next one is called. - - ***Properties***: - - | property | type | access | description | - |----------|-----------|------------|--------------------------------------------------------------------| - | input | string | read | The partial/full text with the subparser modifications | - | output | string | write | The text that will be passed to other subparsers | - | regexp | null | | | - | matches | null | | | - - -### Notes - - - There are 2 main differences between **before.{subparserName}** and **{subparserName}.start**. - - 1. **before.{subparserName}** is always guaranteed to be called, even if the subparser is disabled, - while **{subparserName}.start** doesn't. - - ex: `makehtml.before.strikethrough` is always called even if the option `strikethrough` is false - - 2. **before.{subparserName}** is only raised once in a span context while **{subparserName}.start** is raised - everytime **{subparserName}** is called. - - As a rule of thumb, - -## Events List - - -### blockquote - -#### - - -### metadata - - - -## Common pitfalls - -### Infinite loop - -If you pass the input as output in a `onCapture` event, you might trigger an infinite loop. - diff --git a/mkdocs.yml b/mkdocs.yml index e516162..1f75413 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ nav: - Flavors: flavors.md - CLI: cli.md - Integrations: integrations.md + - Event system: event-system.md - Extensions: - Overview: extensions.md - Create an extension: create-extension.md