Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

TIL:带有 Rails 的 Tiptap 摘录扩展

Posted on 2025-01-17

在构建 Pika 的帖子流布局时,我们需要添加在 Pika 编辑器中管理摘录的功能。这些摘录将用于在帖子流中显示帖子的一小部分,同时提供“继续阅读”链接供读者点击阅读帖子的其余部分。为了添加此功能,我们必须深入研究扩展编辑器Tiptap的基础开源库。

首先是 Tiptap 部分

以下是扩展的完整代码。该扩展主要检测用户是否输入 、 或 WordPress 的<!--more-->并将该文本替换为:

 < div data-type = " excerpt " class = " post-excerpt " contenteditable = " false " draggable = " true " > ↑ Excerpt ↑ </ div >

通过该 HTML,我们可以使用 CSS 来设置样式,如下所示:

Pika 博客文章的摘录在编辑器中通过摘录文本与博客文章其余部分之间的虚线指示

该扩展足够智能,可以知道编辑器中是否已存在摘录,在这种情况下,不允许创建另一个摘录。

扩展名:

 import { Node , InputRule , nodeInputRule , mergeAttributes } from '@tiptap/core'

/**
* Look for on a line by itself, with all the whitespace permutations
*/

export const excerptInputRegex = / ^\s*\s*$ / i

/**
* Look for on a line by itself, with all the whitespace permutations
*/

export const moreInputRegex = / ^\s*\s*$ / i

/**
* Look for classic WordPress <!--more--> tag
*/

export const wpMoreInputRegex = / ^\s*<*![-—]+\s*more\s*[-—]+>\s*$ / i

const excerptText = '↑ Excerpt ↑'

/**
* Used to detect if an excerpt already exists in the editor
*/

const hasExistingExcerpt = ( state ) => {
let hasExcerpt = false
state . doc . descendants ( node => {
if ( node . type . name === 'excerpt' ) {
hasExcerpt = true
return false // stop traversing
}
} )
return hasExcerpt
}

/**
* Disable excerpt button in toolbar if excerpt already exists in
* the editor. Note that we use Tiptap with the Rhino editor for
* Rails, which explains the rhino-editor selectors. Rhino:
* https://rhino-editor.vercel.app/
*/

const setExcerptButtonState = ( editor ) => {
const button = editor . view . dom . closest ( 'rhino-editor' ) . querySelector ( 'rhino-editor button[data-excerpt]' )
if ( button ) {
button . classList . toggle ( 'toolbar__button--disable' , hasExistingExcerpt ( editor . state ) )
button . disabled = hasExistingExcerpt ( editor . state )
}
}

/**
* This custom InputRule allows us to make a singleton excerpt node
* that short-circuits if an excerpt node already exists.
*/

export function excerptInputRule ( config ) {
return new InputRule ( {
find : config . find ,
handler : ( { state , range , match } ) => {
if ( hasExistingExcerpt ( state ) ) {
return
}

const delegate = nodeInputRule ( {
find : config . find ,
type : config . type ,
} )

delegate . handler ( { state , range , match } )
} ,
} )
}

export const Excerpt = Node . create ( {
name : 'excerpt' ,
group : 'block' ,
content : 'inline+' ,
inline : false ,
isolating : true ,
atom : true ,
draggable : true ,
selectable : true ,

onCreate ( ) {
setExcerptButtonState ( this . editor )
} ,

onUpdate ( ) {
setExcerptButtonState ( this . editor )
} ,

parseHTML ( ) {
return [ { tag : 'div[data-type="excerpt"]' } ]
} ,

renderHTML ( { HTMLAttributes } ) {
return [ 'div' , mergeAttributes ( { 'data-type' : 'excerpt' , class : 'post-excerpt' } , HTMLAttributes ) , excerptText ]
} ,

/**
* Add insertExcerpt command that we can call from our custom
* toolbar buttons. This command checks for an existing excerpt
* before inserting a new one.
*/

addCommands ( ) {
return {
insertExcerpt : ( ) => ( { state , commands } ) => {
if ( hasExistingExcerpt ( state ) ) {
return false
}

return commands . insertContent ( {
type : this . name ,
content : [ {
type : 'text' ,
text : excerptText
} ]
} )
} ,
}
} ,

/**
* Set up various detection for etc text.
*/

addInputRules ( ) {
return [
excerptInputRule ( {
find : excerptInputRegex ,
type : this . type ,
} ) ,
excerptInputRule ( {
find : moreInputRegex ,
type : this . type ,
} ) ,
excerptInputRule ( {
find : wpMoreInputRegex ,
type : this . type ,
} ) ,
]
} ,

} )

现在是 Rails 部分

这显然需要根据您的 Tiptap 环境进行修改。在我们的例子中,使用Rhino 编辑器和 Rails,这就是我们所做的……

app/javascript/controllers/extensions/excerpt.js是我们的扩展目录所在的位置。我们使用 importmaps 来管理 JavaScript,因此我们需要将扩展​​目录固定在那里:

 pin_all_from "app/javascript/extensions" , under : "extensions"

我们为所有 Rhino 增强功能提供了一个刺激控制器。我们需要在那里导入我们的扩展:

 import { Excerpt } from "extensions/excerpt"

要添加扩展,我们在用于执行所有 Rhino 初始化的函数中执行此操作(我们将 Rhino 编辑器传递到此函数中):

 initializeEditor ( rhino ) {
// snip
rhino . addExtensions ( Excerpt )
// snip
}

我们添加一个函数,稍后我们将使用新的 Rhino 工具栏按钮调用该函数。该函数调用我们在扩展中定义的insertExcerpt命令。

 insertExcerpt ( ) {
this . element . editor . chain ( ) . focus ( ) . insertExcerpt ( ) . run ( )
}

最后,这是我们添加到 Rhino 工具栏的按钮。注意data-action="click->rhino#insertExcerpt" ,它正在调用上面的函数:

 < button slot = " after-increase-indentation-button " class = " rhino-toolbar-button toolbar__button--excerpt " type = " button " data-role-tooltip = " rhino-insert-excerpt " data-action = " click->rhino#insertExcerpt " data-excerpt data-role = " toolbar-item " tabindex = " -1 " >
< role-tooltip class = " toolbar__tooltip " id = " rhino-insert-excerpt " part = " toolbar__tooltip toolbar__tooltip--create-excerpt " exportparts = " base:toolbar__tooltip__base, arrow:toolbar__tooltip__arrow " >
Create Excerpt
</ role-tooltip >
< svg xmlns = " http://www.w3.org/2000/svg " aria-hidden = " true " fill = " currentColor " part = " toolbar__icon " viewBox = " 0 0 24 24 " width = " 24 " height = " 24 " style = " pointer-events : none ; " >
< path d = " SNIP " />
</ svg >
</ button >

这绝不是一个嵌入式扩展,但希望它可以帮助其他想要将此摘录功能添加到他们的 Tiptap 编辑器中的人。

原文: https://goodenough.us/blog/2025-01-16-til-tiptap-excerpt-extension-with-rails/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme