diff --git a/package.json b/package.json index d644af7f..9a5987ec 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ }, "dependencies": { "@diplodoc/tabs-extension": "^3.3.0", + "@diplodoc/cut-extension": "^0.1.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.12", "css": "^3.0.0", diff --git a/src/js/cut.ts b/src/js/cut.ts deleted file mode 100644 index 25ddd8ad..00000000 --- a/src/js/cut.ts +++ /dev/null @@ -1,57 +0,0 @@ -import {getEventTarget, isCustom} from './utils'; - -const Selector = { - CUT: '.yfm .yfm-cut', - TITLE: '.yfm .yfm-cut-title', - CONTENT: '.yfm .yfm-cut-content', -}; - -const ClassName = { - OPEN: 'open', -}; - -function toggleCut(element: HTMLElement) { - const cutNode = element.parentNode; - - if (!(cutNode instanceof HTMLElement)) { - return; - } - - cutNode.classList.toggle(ClassName.OPEN); -} - -function matchTitle(target: EventTarget | null) { - if (!(target instanceof HTMLElement)) { - return false; - } - - return target?.matches?.(Selector.TITLE); -} - -function findTitleInPath(event: MouseEvent): HTMLElement | undefined { - const target = getEventTarget(event); - - if (matchTitle(target)) { - return target as HTMLElement; - } - - const path = event.composedPath?.(); - - return path?.find(matchTitle) as HTMLElement | undefined; -} - -if (typeof document !== 'undefined') { - document.addEventListener('click', (event) => { - if (isCustom(event)) { - return; - } - - const title = findTitleInPath(event); - - if (!title) { - return; - } - - toggleCut(title); - }); -} diff --git a/src/js/index.ts b/src/js/index.ts index d9a3f412..e28682ce 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -1,8 +1,8 @@ +import '@diplodoc/cut-extension/runtime'; import '@diplodoc/tabs-extension/runtime'; import './polyfill'; import './code'; -import './cut'; import './term'; import './wide-mode'; diff --git a/src/scss/yfm.scss b/src/scss/yfm.scss index c9229b5f..23a3de33 100644 --- a/src/scss/yfm.scss +++ b/src/scss/yfm.scss @@ -3,10 +3,10 @@ @import 'anchor'; @import 'highlight'; @import 'code'; -@import 'cut'; @import 'file'; @import 'term'; @import 'table'; @import 'modal'; +@import '@diplodoc/cut-extension/runtime/styles.css'; @import '@diplodoc/tabs-extension/runtime'; diff --git a/src/transform/plugins/cut.ts b/src/transform/plugins/cut.ts index 22fdff03..561e4623 100644 --- a/src/transform/plugins/cut.ts +++ b/src/transform/plugins/cut.ts @@ -1,98 +1,3 @@ -import type Core from 'markdown-it/lib/parser_core'; -import type Token from 'markdown-it/lib/token'; -import {MarkdownItPluginCb} from './typings'; -import {MatchTokenFunction, nestedCloseTokenIdxFactory as closeTokenFactory} from './utils'; +import {transform} from '@diplodoc/cut-extension'; -const CUT_REGEXP = /^{%\s*cut\s*["|'](.*)["|']\s*%}/; - -const matchCloseToken: MatchTokenFunction = (tokens, i) => { - return ( - tokens[i].type === 'paragraph_open' && - tokens[i + 1].type === 'inline' && - tokens[i + 1].content.trim() === '{% endcut %}' - ); -}; - -const matchOpenToken = (tokens: Token[], i: number) => { - return ( - tokens[i].type === 'paragraph_open' && - tokens[i + 1].type === 'inline' && - tokens[i + 1].content.match(CUT_REGEXP) - ); -}; - -const findCloseTokenIdx = closeTokenFactory('Cut', matchOpenToken, matchCloseToken); - -const cut: MarkdownItPluginCb = (md, {path, log}) => { - const plugin: Core.RuleCore = (state) => { - const tokens = state.tokens; - let i = 0; - - while (i < tokens.length) { - const match = matchOpenToken(tokens, i); - - if (match) { - const closeTokenIdx = findCloseTokenIdx(tokens, i + 4, path, log); - - if (!closeTokenIdx) { - i += 3; - continue; - } - - const newOpenToken = new state.Token('yfm_cut_open', 'details', 1); - newOpenToken.attrSet('class', 'yfm-cut'); - newOpenToken.map = tokens[i].map; - - const titleOpen = new state.Token('yfm_cut_title_open', 'summary', 1); - titleOpen.attrSet('class', 'yfm-cut-title'); - - const titleInline = state.md.parseInline( - match[1] === undefined ? 'ad' : match[1], - state.env, - )[0]; - - const titleClose = new state.Token('yfm_cut_title_close', 'summary', -1); - - const contentOpen = new state.Token('yfm_cut_content_open', 'div', 1); - contentOpen.attrSet('class', 'yfm-cut-content'); - - if (newOpenToken.map) { - const contentOpenStart = newOpenToken.map[0] + 1; - const contentOpenEnd = newOpenToken.map[0] + 2; - - contentOpen.map = [contentOpenStart, contentOpenEnd]; - } - - const contentClose = new state.Token('yfm_cut_content_close', 'div', -1); - - const newCloseToken = new state.Token('yfm_cut_close', 'details', -1); - newCloseToken.map = tokens[closeTokenIdx].map; - - const insideTokens = [ - newOpenToken, - titleOpen, - titleInline, - titleClose, - contentOpen, - ...tokens.slice(i + 3, closeTokenIdx), - contentClose, - newCloseToken, - ]; - - tokens.splice(i, closeTokenIdx - i + 3, ...insideTokens); - - i++; - } else { - i++; - } - } - }; - - try { - md.core.ruler.before('curly_attributes', 'cut', plugin); - } catch (e) { - md.core.ruler.push('cut', plugin); - } -}; - -export = cut; +export = transform({bundle: false});