rittenhop-ghost/versions/5.94.2/node_modules/@tryghost/kg-parser-plugins/cjs/parser-plugins.js

1152 lines
37 KiB
JavaScript
Raw Normal View History

'use strict';
var cleanBasicHtml = require('@tryghost/kg-clean-basic-html');
function fromKoenigCard$7() {
return function kgAudioCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-audio-card')) {
return;
}
const titleNode = node.querySelector('.kg-audio-title');
const audioNode = node.querySelector('.kg-audio-player-container audio');
const thumbnailNode = node.querySelector('.kg-audio-thumbnail');
const durationNode = node.querySelector('.kg-audio-duration');
const title = titleNode && titleNode.innerHTML.trim();
const audioSrc = audioNode && audioNode.src;
const thumbnailSrc = thumbnailNode && thumbnailNode.src;
const durationText = durationNode && durationNode.innerHTML.trim();
if (!audioSrc) {
return;
}
const payload = {
src: audioSrc,
title: title
};
if (thumbnailSrc) {
payload.thumbnailSrc = thumbnailSrc;
}
if (durationText) {
const {minutes, seconds} = durationText.split(':');
try {
payload.duration = parseInt(minutes) * 60 + parseInt(seconds);
} catch (e) {
// ignore duration
}
}
const cardSection = builder.createCardSection('audio', payload);
addSection(cardSection);
nodeFinished();
};
}
function getButtonText$1(node) {
let buttonText = node.textContent;
if (buttonText) {
buttonText = buttonText.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
}
return buttonText;
}
function fromKoenigCard$6() {
return function kgButtonCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-button-card')) {
return;
}
const alignment = node.classList.contains('kg-align-center') ? 'center' : 'left';
const anchor = node.querySelector('a');
const buttonUrl = anchor.href;
const buttonText = getButtonText$1(anchor);
if (!buttonUrl || !buttonText) {
return;
}
const payload = {
alignment,
buttonUrl,
buttonText
};
const cardSection = builder.createCardSection('button', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromWordpressButton() {
return function wordpressButtonToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('wp-block-button__link')) {
return;
}
const buttonUrl = node.href;
const buttonText = getButtonText$1(node);
if (!buttonUrl || !buttonText) {
return;
}
let alignment = 'left';
if (node.closest('.is-content-justification-center, .is-content-justification-right')) {
alignment = 'center';
}
const payload = {
alignment,
buttonUrl,
buttonText
};
const cardSection = builder.createCardSection('button', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromSubstackButton() {
return function substackButtonToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('button')) {
return;
}
// substack has .button-wrapper elems with a data-attrs JSON object with `url` and `text`
// we're not using that in favour of grabbing the anchor element directly for simplicity
const anchor = node.tagName === 'A' ? node : node.querySelector('a');
if (!anchor) {
return;
}
const buttonUrl = anchor.href;
const buttonText = getButtonText$1(anchor);
if (!buttonUrl || !buttonText) {
return;
}
const payload = {
alignment: 'center', // all Substack buttons are centered
buttonUrl,
buttonText
};
const cardSection = builder.createCardSection('button', payload);
addSection(cardSection);
nodeFinished();
};
}
function addFigCaptionToPayload(node, payload, {selector = 'figcaption', options}) {
let figcaptions = Array.from(node.querySelectorAll(selector));
if (figcaptions.length) {
figcaptions.forEach((caption) => {
let cleanHtml = options.cleanBasicHtml(caption.innerHTML);
payload.caption = payload.caption ? `${payload.caption} / ${cleanHtml}` : cleanHtml;
caption.remove(); // cleanup this processed element
});
}
}
function readImageAttributesFromNode(node) {
const attrs = {};
if (node.src) {
attrs.src = node.src;
}
if (node.width) {
attrs.width = node.width;
} else if (node.dataset && node.dataset.width) {
attrs.width = parseInt(node.dataset.width, 10);
}
if (node.height) {
attrs.height = node.height;
} else if (node.dataset && node.dataset.height) {
attrs.height = parseInt(node.dataset.height, 10);
}
if ((!node.width && !node.height) && node.getAttribute('data-image-dimensions')) {
const [, width, height] = (/^(\d*)x(\d*)$/gi).exec(node.getAttribute('data-image-dimensions'));
attrs.width = parseInt(width, 10);
attrs.height = parseInt(height, 10);
}
if (node.alt) {
attrs.alt = node.alt;
}
if (node.title) {
attrs.title = node.title;
}
if (node.parentNode.tagName === 'A') {
const href = node.parentNode.href;
if (href !== attrs.src) {
attrs.href = href;
}
}
return attrs;
}
// Helpers
function _createPayloadForIframe(iframe) {
// If we don't have a src Or it's not an absolute URL, we can't handle this
// This regex handles http://, https:// or //
if (!iframe.src || !iframe.src.match(/^(https?:)?\/\//i)) {
return;
}
// if it's a schemaless URL, convert to https
if (iframe.src.match(/^\/\//)) {
iframe.src = `https:${iframe.src}`;
}
let payload = {
url: iframe.src
};
payload.html = iframe.outerHTML;
return payload;
}
// Plugins
function fromMixtape(options) {
return function mixtapeEmbed(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'DIV' || !node.className.match(/graf--mixtapeEmbed/)) {
return;
}
// Grab the relevant elements - Anchor wraps most of the data
let anchorElement = node.querySelector('.markup--mixtapeEmbed-anchor');
let titleElement = anchorElement.querySelector('.markup--mixtapeEmbed-strong');
let descElement = anchorElement.querySelector('.markup--mixtapeEmbed-em');
// Image is a top level field inside it's own a tag
let imgElement = node.querySelector('.mixtapeImage');
// Grab individual values from the elements
let url = anchorElement.href;
let title = '';
let description = '';
if (titleElement && titleElement.innerHTML) {
title = options.cleanBasicHtml(titleElement.innerHTML);
// Cleanup anchor so we can see what's left now that we've processed title
anchorElement.removeChild(titleElement);
}
if (descElement && descElement.innerHTML) {
description = options.cleanBasicHtml(descElement.innerHTML);
// Cleanup anchor so we can see what's left now that we've processed description
anchorElement.removeChild(descElement);
}
// // Format our preferred structure.
let metadata = {
url,
title,
description
};
// Publisher is the remaining text in the anchor, once title & desc are removed
let publisher = options.cleanBasicHtml(anchorElement.innerHTML);
if (publisher) {
metadata.publisher = publisher;
}
// Image is optional,
// The element usually still exists with an additional has.mixtapeImage--empty class and has no background image
if (imgElement && imgElement.style['background-image']) {
metadata.thumbnail = imgElement.style['background-image'].match(/url\(([^)]*?)\)/)[1];
}
let payload = {url, metadata};
let cardSection = builder.createCardSection('bookmark', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromFigureIframe(options) {
return function figureIframeToEmbed(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
let iframe = node.querySelector('iframe');
if (!iframe) {
return;
}
let payload = _createPayloadForIframe(iframe);
if (!payload) {
return;
}
addFigCaptionToPayload(node, payload, {options});
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromIframe() {
return function iframeToEmbedCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'IFRAME') {
return;
}
let payload = _createPayloadForIframe(node);
if (!payload) {
return;
}
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromFigureBlockquote(options) {
return function figureBlockquoteToEmbedCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
let blockquote = node.querySelector('blockquote');
let link = node.querySelector('a');
if (!blockquote || !link) {
return;
}
let url = link.href;
// If we don't have a url, or it's not an absolute URL, we can't handle this
if (!url || !url.match(/^https?:\/\//i)) {
return;
}
let payload = {
url: url
};
addFigCaptionToPayload(node, payload, {options});
payload.html = node.innerHTML;
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromNFTEmbed() {
return function fromNFTEmbedToEmbedCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || (node.tagName !== 'FIGURE' && node.tagName !== 'NFT-CARD' && node.tagName !== 'DIV')) {
return;
}
// Attempt to parse Ghost NFT Card
if (node.tagName === 'FIGURE') {
if (!node.classList.contains('kg-nft-card')) {
return;
}
let nftCard = node.querySelector('a');
if (!nftCard) {
return;
}
let payload;
try {
payload = JSON.parse(decodeURIComponent(nftCard.dataset.payload));
} catch (err) {
return nodeFinished();
}
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
return nodeFinished();
}
// Attempt to parse Substack NFT Card
if (node.tagName === 'DIV') {
if (!node.classList.contains('opensea')) {
return;
}
let url = node.querySelector('a');
let [match, contractAddress, tokenId] = url.href.match(/\/assets\/(0x[0-9a-f]+)\/(\d+)/);
if (!match) {
return;
}
let payload = {
url: url.href,
html: `<nft-card contractAddress="${contractAddress}" tokenId="${tokenId}"></nft-card><script src="https://unpkg.com/embeddable-nfts/dist/nft-card.min.js"></script>`
};
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
return nodeFinished();
}
if (node.tagName === 'NFT-CARD') {
let attr = node.attributes;
let contractAddress = (attr.contractAddress || attr.contractaddress || attr.tokenaddress || attr.contractaddress).value;
let tokenId = (attr.tokenId || attr.tokenid).value;
if (!contractAddress || !tokenId) {
return;
}
let payload = {
url: `https://opensea.io/assets/${contractAddress}/${tokenId}/`,
html: `<nft-card contractAddress="${contractAddress}" tokenId="${tokenId}"></nft-card><script src="https://unpkg.com/embeddable-nfts/dist/nft-card.min.js"></script>`
};
let cardSection = builder.createCardSection('embed', payload);
addSection(cardSection);
return nodeFinished();
}
};
}
function transformSizeToBytes(sizeStr = '') {
if (!sizeStr) {
return 0;
}
const [sizeVal, sizeType] = sizeStr.split(' ');
if (!sizeVal || !sizeType) {
return 0;
}
if (sizeType === 'Bytes') {
return Number(sizeVal);
} else if (sizeType === 'KB') {
return Number(sizeVal) * 2048;
} else if (sizeType === 'MB') {
return Number(sizeVal) * 2048 * 2048;
}
}
function fromKoenigCard$5() {
return function kgFileCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-file-card')) {
return;
}
const titleNode = node.querySelector('.kg-file-card-title');
const captionNode = node.querySelector('.kg-file-card-caption');
const fileNameNode = node.querySelector('.kg-file-card-filename');
const fileSizeNode = node.querySelector('.kg-file-card-filesize');
const fileCardLinkNode = node.querySelector('.kg-file-card-container');
const title = titleNode && titleNode.innerHTML.trim();
const caption = captionNode && captionNode.innerHTML.trim();
const fileName = fileNameNode && fileNameNode.innerHTML.trim();
const fileSizeStr = fileSizeNode && fileSizeNode.innerHTML.trim();
const fileSrc = fileCardLinkNode && fileCardLinkNode.href;
if (!fileSrc) {
return;
}
const payload = {
src: fileSrc,
fileTitle: title,
fileCaption: caption,
fileSize: transformSizeToBytes(fileSizeStr),
fileName: fileName
};
const cardSection = builder.createCardSection('file', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromKoenigCard$4() {
return function kgHeaderCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-header-card')) {
return;
}
const headerNode = node.querySelector('.kg-header-card-header');
const subheaderNode = node.querySelector('.kg-header-card-subheader');
const buttonNode = node.querySelector('.kg-header-card-button');
let header = '';
let subheader = '';
let buttonText = '';
let buttonUrl = '';
if (headerNode) {
header = headerNode.innerHTML.trim();
}
if (subheaderNode) {
subheader = subheaderNode.innerHTML.trim();
}
if (buttonNode) {
buttonText = buttonNode.textContent.trim();
buttonUrl = buttonNode.getAttribute('href').trim();
}
if (!header && !subheader && (!buttonNode || !buttonText || !buttonUrl)) {
return;
}
const classes = [...node.classList];
let backgroundImageSrc = '';
if (node.getAttribute('data-kg-background-image')) {
backgroundImageSrc = node.getAttribute('data-kg-background-image').trim();
}
const payload = {
header,
subheader,
buttonEnabled: Boolean(buttonNode),
buttonText,
buttonUrl,
backgroundImageSrc,
size: 'small',
style: 'dark'
};
const sizeClass = classes.find(c => /^kg-size-(small|medium|large)$/.test(c));
const styleClass = classes.find(c => /^kg-style-(dark|light|accent|image)$/.test(c));
if (sizeClass) {
payload.size = sizeClass.replace('kg-size-', '');
}
if (styleClass) {
payload.style = styleClass.replace('kg-style-', '');
}
const cardSection = builder.createCardSection('header', payload);
addSection(cardSection);
nodeFinished();
};
}
// https://github.com/TryGhost/Koenig/issues/1
// allows arbitrary HTML blocks wrapped in our card comments to be extracted
// into a HTML card rather than being put through the normal parse+plugins
function fromKoenigCard$3() {
return function kgHtmlCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 8 || node.nodeValue !== 'kg-card-begin: html') {
return;
}
let html = [];
function isHtmlEndComment(n) {
return n && n.nodeType === 8 && n.nodeValue === 'kg-card-end: html';
}
let nextNode = node.nextSibling;
while (nextNode && !isHtmlEndComment(nextNode)) {
let currentNode = nextNode;
html.push(currentNode.outerHTML);
nextNode = currentNode.nextSibling;
// remove nodes as we go so that they don't go through the parser
currentNode.remove();
}
let payload = {html: html.join('\n').trim()};
let cardSection = builder.createCardSection('html', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromImg() {
return function imgToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'IMG') {
return;
}
const payload = readImageAttributesFromNode(node);
const cardSection = builder.createCardSection('image', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromFigure(options) {
return function figureImgToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
const img = node.querySelector('img');
const kgClass = node.className.match(/kg-width-(wide|full)/);
const grafClass = node.className.match(/graf--layout(FillWidth|OutsetCenter)/);
if (!img) {
return;
}
const payload = readImageAttributesFromNode(img);
if (kgClass) {
payload.cardWidth = kgClass[1];
} else if (grafClass) {
payload.cardWidth = grafClass[1] === 'FillWidth' ? 'full' : 'wide';
}
addFigCaptionToPayload(node, payload, {options});
let cardSection = builder.createCardSection('image', payload);
addSection(cardSection);
nodeFinished();
};
}
function getButtonText(node) {
let buttonText = node.textContent;
if (buttonText) {
buttonText = buttonText.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
}
return buttonText;
}
function fromKoenigCard$2() {
return function kgButtonCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-product-card')) {
return;
}
const titleNode = node.querySelector('.kg-product-card-title');
const descriptionNode = node.querySelector('.kg-product-card-description');
const title = titleNode && titleNode.innerHTML.trim();
const description = descriptionNode && descriptionNode.innerHTML.trim();
if (!title && !description) {
return;
}
const payload = {
productButtonEnabled: false,
productRatingEnabled: false,
productTitle: title,
productDescription: description
};
const img = node.querySelector('.kg-product-card-image');
if (img && img.getAttribute('src')) {
payload.productImageSrc = img.getAttribute('src');
}
const stars = [...node.querySelectorAll('.kg-product-card-rating-active')].length;
if (stars) {
payload.productRatingEnabled = true;
payload.productStarRating = stars;
}
const button = node.querySelector('a');
if (button) {
const buttonUrl = button.href;
const buttonText = getButtonText(button);
if (buttonUrl && buttonText) {
payload.productButtonEnabled = true;
payload.productButton = buttonText;
payload.productUrl = buttonUrl;
}
}
const cardSection = builder.createCardSection('product', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromBr() {
// mobiledoc by default ignores <BR> tags but we have a custom SoftReturn atom
return function fromBrToSoftReturnAtom(node, builder, {addMarkerable, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'BR') {
return;
}
let softReturn = builder.createAtom('soft-return');
addMarkerable(softReturn);
nodeFinished();
};
}
function fromKoenigCard$1() {
return function kgVideoCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-video-card')) {
return;
}
const videoNode = node.querySelector('.kg-video-player-container video');
const durationNode = node.querySelector('.kg-video-duration');
const videoSrc = videoNode && videoNode.src;
const durationText = durationNode && durationNode.innerHTML.trim();
if (!videoSrc) {
return;
}
const payload = {
src: videoSrc,
loop: !!videoNode.loop
};
if (durationText) {
const {minutes, seconds} = durationText.split(':');
try {
payload.duration = parseInt(minutes) * 60 + parseInt(seconds);
} catch (e) {
// ignore duration
}
}
const cardSection = builder.createCardSection('video', payload);
addSection(cardSection);
nodeFinished();
};
}
function readGalleryImageAttributesFromNode(node, imgNum) {
const image = readImageAttributesFromNode(node);
image.fileName = node.src.match(/[^/]*$/)[0];
image.row = Math.floor(imgNum / 3);
return image;
}
function fromKoenigCard(options) {
return function kgGalleryCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
if (!node.className.match(/kg-gallery-card/)) {
return;
}
let payload = {};
let imgs = Array.from(node.querySelectorAll('img'));
// Process nodes into the payload
payload.images = imgs.map(readGalleryImageAttributesFromNode);
addFigCaptionToPayload(node, payload, {options});
let cardSection = builder.createCardSection('gallery', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromGrafGallery(options) {
return function grafGalleryToCard(node, builder, {addSection, nodeFinished}) {
function isGrafGallery(n) {
return n.nodeType === 1 && n.tagName === 'DIV' && n.dataset && n.dataset.paragraphCount && n.querySelectorAll('img').length > 0;
}
if (!isGrafGallery(node)) {
return;
}
let payload = {};
// These galleries exist in multiple divs. Read the images and caption from the first one...
let imgs = Array.from(node.querySelectorAll('img'));
addFigCaptionToPayload(node, payload, {options});
// ...and then iterate over any remaining divs until we run out of matches
let nextNode = node.nextSibling;
while (nextNode && isGrafGallery(nextNode)) {
let currentNode = nextNode;
imgs = imgs.concat(Array.from(currentNode.querySelectorAll('img')));
addFigCaptionToPayload(currentNode, payload, {options});
nextNode = currentNode.nextSibling;
// remove nodes as we go so that they don't go through the parser
currentNode.remove();
}
// Process nodes into the payload
payload.images = imgs.map(readGalleryImageAttributesFromNode);
let cardSection = builder.createCardSection('gallery', payload);
addSection(cardSection);
nodeFinished();
};
}
function fromSqsGallery(options) {
return function sqsGalleriesToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'DIV' || !node.className.match(/sqs-gallery-container/) || node.className.match(/summary-/)) {
return;
}
let payload = {};
// Each image exists twice...
// The first image is wrapped in `<noscript>`
// The second image contains image dimensions but the src property needs to be taken from `data-src`.
let imgs = Array.from(node.querySelectorAll('img.thumb-image'));
imgs = imgs.map((img) => {
if (!img.getAttribute('src')) {
if (img.previousSibling.tagName === 'NOSCRIPT' && img.previousSibling.getElementsByTagName('img').length) {
const prevNode = img.previousSibling;
img.setAttribute('src', img.getAttribute('data-src'));
prevNode.remove();
} else {
return undefined;
}
}
return img;
});
addFigCaptionToPayload(node, payload, {options, selector: '.meta-title'});
// Process nodes into the payload
payload.images = imgs.map(readGalleryImageAttributesFromNode);
let cardSection = builder.createCardSection('gallery', payload);
addSection(cardSection);
nodeFinished();
};
}
/**
* Copied from:
* https://github.com/TryGhost/Ghost-Admin/blob/1f3d77d7230dd47a7eb5f38b90dfa510b2a16801/lib/koenig-editor/addon/options/parser-plugins.js
* Which makes use of:
* https://github.com/TryGhost/Ghost-Admin/blob/1f3d77d7230dd47a7eb5f38b90dfa510b2a16801/lib/koenig-editor/addon/helpers/clean-basic-html.js
*
* These functions are used to proces nodes during parsing from DOM -> mobiledoc
*/
function createParserPlugins(_options = {}) {
const defaults = {};
const options = Object.assign({}, defaults, _options);
if (!options.createDocument) {
const Parser = (typeof DOMParser !== 'undefined' && DOMParser) || (typeof window !== 'undefined' && window.DOMParser);
if (!Parser) {
// eslint-disable-next-line ghost/ghost-custom/no-native-error
throw new Error('createParserPlugins() must be passed a `createDocument` function as an option when used in a non-browser environment');
}
options.createDocument = function (html) {
const parser = new Parser();
return parser.parseFromString(html, 'text/html');
};
}
options.cleanBasicHtml = function (html) {
return cleanBasicHtml(html, options);
};
// HELPERS -----------------------------------------------------------------
function _readFigCaptionFromNode(node, payload, selector = 'figcaption') {
let figcaptions = Array.from(node.querySelectorAll(selector));
if (figcaptions.length) {
figcaptions.forEach((caption) => {
let cleanHtml = options.cleanBasicHtml(caption.innerHTML);
payload.caption = payload.caption ? `${payload.caption} / ${cleanHtml}` : cleanHtml;
caption.remove(); // cleanup this processed element
});
}
}
// PLUGINS -----------------------------------------------------------------
function kgCalloutCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-callout-card')) {
return;
}
const emojiNode = node.querySelector('.kg-callout-emoji');
const htmlNode = node.querySelector('.kg-callout-text');
const backgroundColor = node.style.backgroundColor || '#F1F3F4';
let calloutEmoji = '';
if (emojiNode) {
calloutEmoji = emojiNode?.textContent;
if (calloutEmoji) {
calloutEmoji = calloutEmoji.trim();
}
}
let calloutText = htmlNode?.innerHTML || '';
const payload = {
calloutEmoji,
calloutText,
backgroundColor
};
const cardSection = builder.createCardSection('callout', payload);
addSection(cardSection);
nodeFinished();
}
function kgToggleCardToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || !node.classList.contains('kg-toggle-card')) {
return;
}
const headingNode = node.querySelector('.kg-toggle-heading-text');
const contentNode = node.querySelector('.kg-toggle-content');
let toggleHeading = headingNode.innerHTML;
let toggleContent = contentNode.innerText;
const payload = {
heading: toggleHeading,
content: toggleContent
};
const cardSection = builder.createCardSection('toggle', payload);
addSection(cardSection);
nodeFinished();
}
// leading newlines in text nodes will add a space to the beginning of the text
// which doesn't render correctly if we're replacing <br> with SoftReturn atoms
// after parsing text as markdown to html
function removeLeadingNewline(node) {
if (node.nodeType !== 3 || node.nodeName !== '#text') {
return;
}
node.nodeValue = node.nodeValue.replace(/^\n/, '');
}
function hrToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'HR') {
return;
}
let cardSection = builder.createCardSection('hr');
addSection(cardSection);
nodeFinished();
}
function figureToCodeCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
let pre = node.querySelector('pre');
// If this figure doesn't have a pre tag in it
if (!pre) {
return;
}
let code = pre.querySelector('code');
let figcaption = node.querySelector('figcaption');
// if there's no caption the preCodeToCard plugin will pick it up instead
if (!code || !figcaption) {
return;
}
let payload = {
code: code.textContent
};
_readFigCaptionFromNode(node, payload);
let preClass = pre.getAttribute('class') || '';
let codeClass = code.getAttribute('class') || '';
let langRegex = /lang(?:uage)?-(.*?)(?:\s|$)/i;
let languageMatches = preClass.match(langRegex) || codeClass.match(langRegex);
if (languageMatches) {
payload.language = languageMatches[1].toLowerCase();
}
let cardSection = builder.createCardSection('code', payload);
addSection(cardSection);
nodeFinished();
}
function preCodeToCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'PRE') {
return;
}
let [codeElement] = node.children;
if (codeElement && codeElement.tagName === 'CODE') {
let payload = {code: codeElement.textContent};
let preClass = node.getAttribute('class') || '';
let codeClass = codeElement.getAttribute('class') || '';
let langRegex = /lang(?:uage)?-(.*?)(?:\s|$)/i;
let languageMatches = preClass.match(langRegex) || codeClass.match(langRegex);
if (languageMatches) {
payload.language = languageMatches[1].toLowerCase();
}
let cardSection = builder.createCardSection('code', payload);
addSection(cardSection);
nodeFinished();
}
}
function figureScriptToHtmlCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'FIGURE') {
return;
}
let script = node.querySelector('script');
if (!script || !script.src.match(/^https:\/\/gist\.github\.com/)) {
return;
}
let payload = {html: script.outerHTML};
let cardSection = builder.createCardSection('html', payload);
addSection(cardSection);
nodeFinished();
}
// Nested paragraphs in blockquote are currently treated as separate blockquotes,
// see [here](https://github.com/bustle/mobiledoc-kit/issues/715). When running migrations,
// this is not the desired behaviour and will cause the content to lose the previous semantic.
function blockquoteWithChildren(node) {
if (node.nodeType !== 1 || node.tagName !== 'BLOCKQUOTE' || node.children.length < 1) {
return;
}
const html = [];
const children = Array.from(node.children);
children.forEach((child) => {
let nextSibling = child.nextSibling;
let previousSibling = child.previousSibling;
// Only add a soft-break for two sequential paragraphs.
// Use the innerHTML only in that case, so Mobiledoc's default behaviour
// of creating separate blockquotes doesn't apply.
if (child.tagName === 'P' && (nextSibling && nextSibling.tagName === 'P')) {
html.push(`${child.innerHTML}<br><br>`);
} else if (child.tagName === 'P' && (previousSibling && previousSibling.tagName === 'P')) {
html.push(child.innerHTML);
} else {
html.push(child.outerHTML);
}
});
node.innerHTML = html.join('').trim();
return;
}
// we store alt-style blockquotes as `aside` sections as a workaround
// for mobiledoc not allowing arbitrary attributes on markup sections
function altBlockquoteToAside(node) {
if (node.nodeType !== 1 || node.tagName !== 'BLOCKQUOTE') {
return;
}
if (!node.classList.contains('kg-blockquote-alt')) {
return;
}
const replacementDoc = options.createDocument(`<aside>${node.innerHTML}</aside>`);
const aside = replacementDoc.querySelector('aside');
// bit of an ugly hack because
// 1. node.tagName is readonly so we can't directly change it's type
// 2. the node list of the current tree branch is not re-evaluated so removing
// this node, replacing it, or adding a new _sibling_ will not be picked up
//
// relies on mobiledoc-kit's handling of nested elements picking the
// inner-most understandable section element when creating sections
node.textContent = '';
node.appendChild(aside);
// let the default parser handle the nested aside node, keeping any formatting
return;
}
function tableToHtmlCard(node, builder, {addSection, nodeFinished}) {
if (node.nodeType !== 1 || node.tagName !== 'TABLE') {
return;
}
if (node.parentNode.tagName === 'TABLE') {
return;
}
let payload = {html: node.outerHTML};
let cardSection = builder.createCardSection('html', payload);
addSection(cardSection);
nodeFinished();
}
return [
fromNFTEmbed(),
fromMixtape(options),
fromKoenigCard$3(),
fromKoenigCard$6(),
fromWordpressButton(),
fromSubstackButton(),
kgCalloutCardToCard,
kgToggleCardToCard,
fromKoenigCard$2(),
fromKoenigCard$7(),
fromKoenigCard$1(),
fromKoenigCard$5(),
fromKoenigCard$4(),
blockquoteWithChildren,
fromBr(),
removeLeadingNewline,
fromKoenigCard(options),
fromFigureBlockquote(options), // I think these can contain images
fromGrafGallery(options),
fromSqsGallery(options),
fromFigure(options),
fromImg(),
hrToCard,
figureToCodeCard,
preCodeToCard,
fromFigureIframe(options),
fromIframe(), // Process iFrames without figures after ones with
figureScriptToHtmlCard,
altBlockquoteToAside,
tableToHtmlCard
];
}
exports.createParserPlugins = createParserPlugins;
//# sourceMappingURL=parser-plugins.js.map