-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Twitter plugin * Add to changelog + readme + demo * Add more tests for URL variants
- Loading branch information
Showing
9 changed files
with
545 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -323,6 +323,19 @@ <h3 id="asciinema"><a class="hash-anchor" href="#asciinema" aria-hidden="true">< | |
<noscript> | ||
<a href="https://asciinema.org/a/239367" target="_blank">View asciinema recording</a> | ||
</noscript> | ||
<h3 id="twitter"><a class="hash-anchor" href="#twitter" aria-hidden="true"></a>Twitter</h3> | ||
<p>You can also embed a tweet from Twitter by passing the URL for the tweet:</p> | ||
<div class="twitter"> | ||
<blockquote class="twitter-tweet" data-dnt="true" data-width="550" data-theme="light"> | ||
<a href="https://twitter.com/MattIPv4/status/1576415168426573825">View tweet by @MattIPv4</a> | ||
</blockquote> | ||
</div> | ||
<p>Like a few other embeds, you can also pass optional flags to customize the embed:</p> | ||
<ul> | ||
<li>Pass any integer value (between 250 and 550) to set a custom width for the embed (e.g. <code>[twitter https://twitter.com/MattIPv4/status/1576415168426573825 400]</code>)</li> | ||
<li>Pass <code>light</code> or <code>dark</code> to switch the theme of the embed (e.g. <code>[twitter https://twitter.com/MattIPv4/status/1576415168426573825 dark]</code>)</li> | ||
<li>Pass <code>left</code>, <code>center</code>, or <code>right</code> to align the embed (e.g. <code>[twitter https://twitter.com/MattIPv4/status/1576415168426573825 left]</code>)</li> | ||
</ul> | ||
<h2 id="step-6-tutorials"><a class="hash-anchor" href="#step-6-tutorials" aria-hidden="true"></a>Step 6 — Tutorials</h2> | ||
<p>Certain features of our Markdown engine are designed specifically for our tutorial content-types. | ||
These may not be enabled in all contexts in the DigitalOcean community, but are enabled by default in the do-markdownit plugin.</p> | ||
|
@@ -336,3 +349,4 @@ <h2 id="conclusion"><a class="hash-anchor" href="#conclusion" aria-hidden="true" | |
<script async defer src="https://do-community.github.io/dns-tool-embed/bundle.js" type="text/javascript" onload="window.DNSToolEmbeds()"></script> | ||
<script async defer src="https://static.codepen.io/assets/embed/ei.js" type="text/javascript"></script> | ||
<script async defer src="https://cdn.jsdelivr.net/gh/ireade/[email protected]/public/caniuse-embed.min.js" type="text/javascript"></script> | ||
<script async defer src="https://platform.twitter.com/widgets.js" type="text/javascript"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/* | ||
Copyright 2023 DigitalOcean | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
/** | ||
* @module rules/embeds/twitter | ||
*/ | ||
|
||
const safeObject = require('../../util/safe_object'); | ||
|
||
/** | ||
* Add support for [Twitter](https://twitter.com/) embeds in Markdown, as block syntax. | ||
* | ||
* The basic syntax is `[twitter <tweet>]`. E.g. `[twitter https://twitter.com/MattIPv4/status/1576415168426573825]`. | ||
* After the tweet, assorted space-separated flags can be added (in any combination/order): | ||
* | ||
* - Add `light` or `dark` to set the card theme (default is `light`). | ||
* - Add `left`, `center`, or `right` to set the alignment of the embed (default is `left`). | ||
* - Add any set of digits to set the width of the embed (in pixels, between 250 and 550, default is 550). | ||
* | ||
* If two or more alignments are selected, `left` will be preferred, followed by `center`, then `right`. | ||
* | ||
* If both `light` and `dark` are selected, `dark` will be preferred. | ||
* | ||
* If a width outside the range of 250-550 is selected, a clamped value will be used. | ||
* | ||
* @example | ||
* [twitter https://twitter.com/MattIPv4/status/1576415168426573825] | ||
* | ||
* [twitter https://twitter.com/MattIPv4/status/1576415168426573825 left 400 dark] | ||
* | ||
* <div class="twitter"> | ||
* <blockquote class="twitter-tweet" data-dnt="true" data-width="550" data-theme="light"> | ||
* <a href="https://twitter.com/MattIPv4/status/1576415168426573825">View tweet by @MattIPv4</a> | ||
* </blockquote> | ||
* </div> | ||
* | ||
* <div class="twitter" align="left"> | ||
* <blockquote class="twitter-tweet" data-dnt="true" data-width="400" data-theme="dark"> | ||
* <a href="https://twitter.com/MattIPv4/status/1576415168426573825">View tweet by @MattIPv4</a> | ||
* </blockquote> | ||
* </div> | ||
* <script async defer src="https://platform.twitter.com/widgets.js" type="text/javascript"></script> | ||
* | ||
* @type {import('markdown-it').PluginSimple} | ||
*/ | ||
module.exports = md => { | ||
/** | ||
* Parsing rule for Twitter markup. | ||
* | ||
* @type {import('markdown-it/lib/parser_block').RuleBlock} | ||
* @private | ||
*/ | ||
const twitterRule = (state, startLine, endLine, silent) => { | ||
// If silent, don't replace | ||
if (silent) return false; | ||
|
||
// Get current string to consider (just current line) | ||
const pos = state.bMarks[startLine] + state.tShift[startLine]; | ||
const max = state.eMarks[startLine]; | ||
const currentLine = state.src.substring(pos, max); | ||
|
||
// Perform some non-regex checks for speed | ||
if (currentLine.length < 11) return false; // [twitter a/status/b] | ||
if (currentLine.slice(0, 9) !== '[twitter ') return false; | ||
if (currentLine[currentLine.length - 1] !== ']') return false; | ||
|
||
// Check for Twitter match | ||
// https://www.twitter.com/<user>/status/<id> (treat everything prior to <user> as optional, ish) | ||
const alignment = [ 'left', 'center', 'right' ]; | ||
const settings = [ 'light', 'dark' ]; | ||
const match = currentLine.match(`^\\[twitter (?:(?:(?:(?:https?:)?\\/\\/)?(?:www\\.)?twitter\\.com)?\\/)?(\\w+)\\/status\\/(\\d+)((?: (?:${alignment.concat(settings).join('|')}|\\d+))*)\\]$`); | ||
if (!match) return false; | ||
|
||
// Get the user | ||
const user = match[1]; | ||
if (!user) return false; | ||
|
||
// Get the id | ||
const id = match[2]; | ||
if (!id) return false; | ||
|
||
// Get the raw flags | ||
const flags = match[3]; | ||
|
||
// Get the width | ||
const widthMatch = flags.match(/\d+/); | ||
const width = widthMatch ? Math.max(Math.min(Number(widthMatch[0]), 550), 250) : 550; | ||
|
||
// Get the theme | ||
const theme = flags.includes('dark') ? 'dark' : 'light'; | ||
|
||
// Get the alignment | ||
const align = alignment.find(t => flags.includes(t)) || 'center'; | ||
|
||
// Update the pos for the parser | ||
state.line = startLine + 1; | ||
|
||
// Add token to state | ||
const token = state.push('twitter', 'twitter', 0); | ||
token.block = true; | ||
token.markup = match[0]; | ||
token.twitter = { user, id, width, theme, align }; | ||
|
||
// Track that we need the script | ||
state.env.twitter = safeObject(state.env.twitter); | ||
state.env.twitter.tokenized = true; | ||
|
||
// Done | ||
return true; | ||
}; | ||
|
||
md.block.ruler.before('paragraph', 'twitter', twitterRule); | ||
|
||
/** | ||
* Parsing rule to inject the Twitter script. | ||
* | ||
* @type {import('markdown-it').RuleCore} | ||
* @private | ||
*/ | ||
const twitterScriptRule = state => { | ||
if (state.inlineMode) return; | ||
|
||
// Check if we need to inject the script | ||
if (state.env.twitter && state.env.twitter.tokenized && !state.env.twitter.injected) { | ||
// Set that we've injected it | ||
state.env.twitter.injected = true; | ||
|
||
// Inject the token | ||
const token = new state.Token('html_block', '', 0); | ||
token.content = '<script async defer src="https://platform.twitter.com/widgets.js" type="text/javascript"></script>\n'; | ||
state.tokens.push(token); | ||
} | ||
}; | ||
|
||
md.core.ruler.push('twitter_script', twitterScriptRule); | ||
|
||
/** | ||
* Rendering rule for Twitter markup. | ||
* | ||
* @type {import('markdown-it/lib/renderer').RenderRule} | ||
* @private | ||
*/ | ||
md.renderer.rules.twitter = (tokens, index) => { | ||
const token = tokens[index]; | ||
|
||
// Construct the attrs | ||
const attrWidth = ` data-width="${md.utils.escapeHtml(token.twitter.width)}"`; | ||
const attrTheme = ` data-theme="${md.utils.escapeHtml(token.twitter.theme)}"`; | ||
const attrAlign = token.twitter.align !== 'center' ? ` align="${md.utils.escapeHtml(token.twitter.align)}"` : ''; | ||
|
||
// Escape some HTML | ||
const user = md.utils.escapeHtml(token.twitter.user); | ||
const id = md.utils.escapeHtml(token.twitter.id); | ||
|
||
// Return the HTML | ||
// Apply the alignment to the parent div, as Twitter does float-based alignment | ||
return `<div class="twitter"${attrAlign}> | ||
<blockquote class="twitter-tweet" data-dnt="true"${attrWidth}${attrTheme}> | ||
<a href="https://twitter.com/${user}/status/${id}">View tweet by @${user}</a> | ||
</blockquote> | ||
</div>\n`; | ||
}; | ||
}; |
Oops, something went wrong.