beefree-sdk-content-dialog

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Beefree SDK content dialog

Beefree SDK Content Dialog

Let the host app supply content to the builder through its own UI. The builder shows a label the app chooses, the user clicks it, the app opens whatever it wants, and hands one value back. One contract for merge tags, links, dynamic content, display conditions, rows, attributes, videos and files.
Requires a working Beefree SDK integration. If the builder does not run yet, use the
beefree-sdk-setup
skill first.
让宿主应用通过自身UI向编辑器提供内容。 编辑器会显示应用选择的标签,用户点击该标签后,应用可打开任意所需界面,并返回一个值。 一套适用于合并标签、链接、动态内容、显示条件、行、属性、视频和文件的统一契约。
需要已正常运行的Beefree SDK集成。 如果编辑器尚未运行,请先使用
beefree-sdk-setup
方案。

Step 1: check the plan

步骤1:检查套餐版本

The Content Dialog is available on Essentials (tier 20) and above. Some handlers extend a feature with a higher plan or a Developer Console switch; Step 3 says which.
  1. Run
    check-credentials.sh path/to/.env
    from the
    beefree-sdk-setup
    skill. Skills are installed as sibling folders, so from this skill's folder the path is
    ../beefree-sdk-setup/scripts/check-credentials.sh
    . It prints the plan read from the token. If that skill is not installed, ask the user which plan the application is on.
  2. Report what the token says. Ask the user to confirm only when the plan could not be read, is unknown, or is below the tier this feature needs.
  3. Tier 20 or above: continue. Free: say the feature is outside the plan. There is no development application on Free, so the only path is an upgrade.
Content Dialog功能适用于Essentials(等级20)及以上套餐。 部分处理程序需要更高套餐版本或开发者控制台开关支持;步骤3会说明具体要求。
  1. beefree-sdk-setup
    方案中运行
    check-credentials.sh path/to/.env
    脚本。 方案以同级文件夹形式安装,因此从本方案的文件夹出发,路径为
    ../beefree-sdk-setup/scripts/check-credentials.sh
    。 该脚本会打印从令牌中读取到的套餐信息。 如果未安装该方案,请询问用户应用所使用的套餐版本。
  2. 告知用户令牌显示的套餐信息。 仅当无法读取套餐信息、套餐未知或套餐等级低于本功能要求时,才需请用户确认。
  3. 等级20及以上:继续操作。 免费版:说明本功能超出套餐范围。免费版无开发应用权限,唯一解决途径是升级套餐。

Step 2: confirm a dialog is the right tool

步骤2:确认对话框是合适的工具

Ask how many items the user has and where they come from, unless the request already says.
  • A short, fixed list of merge tags or special links, say under twenty. No dialog. Put them in the
    mergeTags
    and
    specialLinks
    arrays of
    beeConfig
    and stop. See content-dialog.md for the shapes.
  • Many items, a search, categories, or data that depends on context (the selected campaign, the user's account). The dialog. The docs recommend both together: frequent items in the arrays, the long tail behind the dialog.
  • The app already has a picker users know, and the builder should reuse it. The dialog.
  • Hiding or locking builder features. Not this. Advanced Permissions covers it.
  • Beefree calling the app's file storage server to server. Not this. That is Custom File Storage, a console setting and a backend API. The
    filePicker
    handler here is the opposite direction: host UI that returns a URL.
除非用户的请求中已说明,否则请询问用户拥有多少个项目以及这些项目的来源。
  • 简短的固定列表(例如20个以内的合并标签或特殊链接)。 无需使用对话框。将它们放入
    beeConfig
    mergeTags
    specialLinks
    数组即可,操作到此结束。 可参考content-dialog.md中的结构说明。
  • 大量项目、需要搜索/分类,或数据依赖上下文(如所选活动、用户账户)。 使用对话框。文档建议两者结合使用:常用项目放入数组,长尾项目通过对话框获取。
  • 应用已有用户熟悉的选择器,编辑器应复用该选择器。 使用对话框。
  • 隐藏或锁定编辑器功能。本方案不适用,应使用高级权限设置。
  • Beefree调用应用的文件存储服务器(服务器到服务器)。本方案不适用,这属于自定义文件存储功能,需要控制台设置和后端API支持。 此处的
    filePicker
    处理程序方向相反:通过宿主UI返回URL。

Step 3: pick the handlers

步骤3:选择处理程序

HandlerEnd user seesResolve withNeeds beyond Essentials
mergeTags
A button with your label in the text toolbar, next to Merge tags
{ name, value }
specialLinks
A link with your label next to Special links under the Url field of buttons, images and text links
{ type, label, link }
mergeContents
A button in the dynamic content properties
{ name, value }
One item in
mergeContents
so the tile exists
rowDisplayConditions
A button in the row's display condition widget
{ type, label, description, before, after }
Core, console Services → Display Conditions on
externalContentURLs
A last item in the Rows drop-down
{ name, value }
, a rows URL
Core. Use
beefree-sdk-custom-rows
saveRow
,
onEditRow
,
onDeleteRow
,
editSyncedRow
Save icon and row card menumetadata,
true
Core. Use
beefree-sdk-self-hosted-saved-rows
manageForm
A button in the form block propertiesa form structurePage or Popup builder
customAttribute
A button in link and image attribute editors
{ key, name, value, target }
Core, Custom Attributes
addVideo
A custom source in the video block
{ videoSrc, thumbSrc, thumbAlt }
filePicker
The Browse button of image and file fields
{ url }
Superpowers, Custom File Picker
Every handler, its
args
and the exact value shape are in content-dialog.md. Start with one or two. Adding a handler later is one more key in the same object.
处理程序终端用户看到的内容返回值格式超出Essentials套餐的额外要求
mergeTags
文本工具栏中合并标签旁带有自定义标签的按钮
{ name, value }
specialLinks
按钮、图片和文本链接的Url字段下,特殊链接旁带有自定义标签的链接
{ type, label, link }
mergeContents
动态内容属性面板中的按钮
{ name, value }
mergeContents
数组中需至少有一个元素,以确保该功能模块存在
rowDisplayConditions
行显示条件组件中的按钮
{ type, label, description, before, after }
核心功能,需在控制台开启服务 → 显示条件开关
externalContentURLs
行下拉菜单中的最后一项
{ name, value }
(行的URL)
核心功能,需使用
beefree-sdk-custom-rows
方案
saveRow
,
onEditRow
,
onDeleteRow
,
editSyncedRow
保存图标和行卡片菜单元数据、
true
核心功能,需使用
beefree-sdk-self-hosted-saved-rows
方案
manageForm
表单块属性面板中的按钮表单结构需使用页面或弹窗编辑器
customAttribute
链接和图片属性编辑器中的按钮
{ key, name, value, target }
核心功能,需开启自定义属性功能
addVideo
视频块中的自定义来源
{ videoSrc, thumbSrc, thumbAlt }
filePicker
图片和文件字段的浏览按钮
{ url }
Superpowers套餐,需开启自定义文件选择器功能
每个处理程序的
args
和精确值结构可参考content-dialog.md。 建议先添加1-2个处理程序,后续添加只需在同一对象中新增一个键即可。

Step 4: the contract

步骤4:契约示例

javascript
contentDialog: {
  mergeTags: {
    label: 'Search all merge tags',
    handler: function (resolve, reject) {
      openYourPicker()
        .then(item => resolve(item))   // { name, value }
        .catch(() => reject())         // cancel, the builder resumes
    },
  },
},
Rules that matter in practice:
  • Always end with
    resolve
    or
    reject
    .
    The builder blocks editing while it waits. A handler that throws, or a modal closed without calling either, leaves it blocked. Wrap the logic and call
    reject()
    on any error and on cancel.
  • The value must have the shape of one entry of the matching
    beeConfig
    array. A wrong shape logs
    Error getting content <handler>, the item is malformed.
    in the console, shows nothing in the UI, and inserts nothing.
  • The handler runs in the host page. Any UI works, and a fetch to the app's backend carries the app's session. No CORS or
    localhost
    trouble, unlike a rows URL.
  • label
    is the text the user clicks. Use the words of the app, not "content dialog".
  • Set
    loadingSpinnerDisableOnDialog: true
    in
    beeConfig
    if the builder's spinner gets in the way of the app's modal.
javascript
contentDialog: {
  mergeTags: {
    label: 'Search all merge tags',
    handler: function (resolve, reject) {
      openYourPicker()
        .then(item => resolve(item))   // { name, value }
        .catch(() => reject())         // cancel, the builder resumes
    },
  },
},
实际使用中的重要规则:
  • 必须以
    resolve
    reject
    结束
    。编辑器会在等待时阻止编辑。如果处理程序抛出异常,或模态框关闭时未调用这两个方法之一,编辑器会一直处于阻塞状态。 请包裹所有逻辑,在出现任何错误或取消操作时调用
    reject()
  • 返回值必须符合对应
    beeConfig
    数组中单个条目的结构。结构错误会在控制台记录
    Error getting content <handler>, the item is malformed.
    ,UI中不会显示任何内容,也不会插入任何值。
  • 处理程序在宿主页面中运行。任何UI都可使用,向应用后端发起的请求会携带应用的会话信息。与行URL不同,不会有CORS或
    localhost
    问题。
  • label
    是用户点击的文本。请使用应用的术语,而非“content dialog”。
  • 如果编辑器的加载 spinner 影响应用模态框的显示,请在
    beeConfig
    中设置
    loadingSpinnerDisableOnDialog: true

Step 5A: add it to the setup demo

步骤5A:添加到设置演示

Ready-made file in
assets/demo/
, written for the
beefree-sdk-setup
demo. A native
<dialog>
with a filter box over a static catalog of ten merge tags and six special links. Nothing changes in
server.js
.
  1. Copy
    assets/demo/public/content-dialog.js
    into
    public/
    .
  2. Load it in
    public/index.html
    , before
    app.js
    :
    html
    <script src="content-dialog.js"></script>
  3. In
    public/app.js
    , wrap the config where the builder is created:
    javascript
    BeePlugin.create(token, withContentDialog(beeConfig), function (instance) {
    With other feature skills installed, chain the wrappers:
    withContentDialog(withSavedRows(beeConfig))
    . Each one merges into
    contentDialog
    and keeps what is already there.
  4. npm start
    , open http://localhost:3000.
The file also puts the first two catalog items into
mergeTags
and
specialLinks
, so the toolbar buttons exist and the frequent items are one click away. To use the app's own data, replace the two catalog arrays with a fetch inside the handler; the dialog code stays.
assets/demo/
目录下有现成文件,专为
beefree-sdk-setup
演示编写。 这是一个原生
<dialog>
组件,带有筛选框,展示10个合并标签和6个特殊链接的静态目录。 无需修改
server.js
  1. assets/demo/public/content-dialog.js
    复制到
    public/
    目录下。
  2. public/index.html
    中,在
    app.js
    之前加载该文件:
    html
    <script src="content-dialog.js"></script>
  3. public/app.js
    中,在创建编辑器的地方包裹配置:
    javascript
    BeePlugin.create(token, withContentDialog(beeConfig), function (instance) {
    如果已安装其他功能方案,可链式调用包装器:
    withContentDialog(withSavedRows(beeConfig))
    。 每个包装器都会合并到
    contentDialog
    中,并保留已有的内容。
  4. 运行
    npm start
    ,打开http://localhost:3000
该文件还会将目录中的前两个条目放入
mergeTags
specialLinks
数组,这样工具栏按钮会显示出来,常用项目可一键获取。 如需使用应用自身的数据,只需将处理程序中的两个目录数组替换为后端请求即可,对话框代码无需改动。

Step 5B: existing app

步骤5B:现有应用集成

Stay framework-neutral and port the demo file.
  • Where the UI hooks in. The handler is the bridge: it opens the app's modal, and the modal's confirm and cancel call
    resolve
    and
    reject
    . In React, keep the two functions in state or a ref and build
    contentDialog
    inside the component, as the official display conditions example does.
  • Backend search. Fetch from the handler with the text the user typed. The request runs in the page, so cookies and app auth apply.
  • Frequent items stay in the arrays. Keep the arrays and the dialog fed from the same source so a picked item can be shown by name when the design is reloaded.
  • Display conditions. Turn the feature on in the Developer Console first (Services → Display Conditions), then add
    rowDisplayConditions
    . The third handler argument is the row's current condition, pass it to the builder UI so the user edits instead of starting over.
保持框架中立,移植演示文件即可。
  • UI接入点。处理程序是桥梁:它打开应用的模态框,模态框的确认和取消按钮分别调用
    resolve
    reject
    。 在React中,可将这两个函数保存在状态或ref中,并在组件内部构建
    contentDialog
    ,官方显示条件示例就是这样实现的。
  • 后端搜索。在处理程序中根据用户输入的文本发起请求。请求在页面中运行,因此会携带cookie和应用的认证信息。
  • 常用项目保留在数组中。确保数组和对话框的数据源一致,这样重新加载设计时,已选择的项目可按名称显示。
  • 显示条件。先在开发者控制台开启该功能(服务 → 显示条件),再添加
    rowDisplayConditions
    处理程序。处理程序的第三个参数是行当前的条件,需将其传递给编辑器UI,以便用户编辑而非重新创建。

Step 6: verify

步骤6:验证

Verified on 2026-09-03 with a Superpowers application, Chrome, Node 20.
  1. The builder loads. Click into a text block or a button label. The text toolbar shows Merge tags and, next to it, Search all merge tags. In a narrow toolbar the second one sits under More.
  2. Click Search all merge tags. The dialog opens, type
    order
    , press Enter.
    {{ last_order.date }}
    appears at the cursor.
  3. Select a button. Under the Url field the panel shows Special links | Link file | Find a link. Click Find a link, type
    rocket
    , press Enter. The Url field fills with the product link.
  4. Click Search all merge tags again and press Escape. The dialog closes and the builder is editable at once.
  5. Click Save. The placeholder and the link are in the JSON and the HTML output.
The builder's own Merge tags menu and Special links menu list only the items from the config arrays. The dialog label is a separate control, never an entry inside those menus.
SymptomLikely cause and fix
No Merge tags button at allNo items in
mergeTags
. Keep at least one in the array; the dialog entry alone is not confirmed to show the button.
Looking for the label inside the Merge tags menuIt is not there. The label is its own toolbar button, or under More when the toolbar is narrow.
No label button anywherePlan below Essentials (Step 1), or
contentDialog
not in the config passed at creation.
Builder stays blocked after the dialogThe handler never called
resolve
or
reject
. Check every path, including errors and closing the modal.
Console says
the item is malformed
Wrong value shape. Compare with the table in Step 3, key names matter.
Dialog picked, nothing inserted, no errorText cursor was not in a text block, or the link editor was closed before the resolve. Retry with the field open.
Own modal hidden behind the builderGive it a
z-index
above the builder container. The demo's native
<dialog>
is in the top layer already.
本方案已于2026年9月3日在Superpowers应用、Chrome浏览器、Node 20环境下验证通过。
  1. 编辑器加载完成后,点击文本块或按钮标签。 文本工具栏会显示合并标签,旁边是Search all merge tags。 在窄工具栏中,第二个按钮会位于更多下方。
  2. 点击Search all merge tags。对话框打开后,输入
    order
    并按回车。
    {{ last_order.date }}
    会插入到光标位置。
  3. 选择一个按钮。Url字段下方的面板会显示Special links | Link file | Find a link。 点击Find a link,输入
    rocket
    并按回车。Url字段会填充产品链接。
  4. 再次点击Search all merge tags并按Esc键。对话框关闭,编辑器立即恢复可编辑状态。
  5. 点击保存。占位符和链接会出现在JSON和HTML输出中。
编辑器自带的合并标签菜单和特殊链接菜单仅显示配置数组中的项目。 对话框标签是一个独立控件,不会出现在这些菜单中。
症状可能原因及修复方案
完全没有合并标签按钮
mergeTags
数组中没有项目。数组中至少保留一个项目;仅靠对话框条目无法确保按钮显示。
在合并标签菜单中寻找自定义标签它不在那里。自定义标签是独立的工具栏按钮,窄工具栏下会位于更多下方。
任何地方都没有标签按钮套餐等级低于Essentials(步骤1),或创建编辑器时传入的配置中没有
contentDialog
对话框关闭后编辑器仍处于阻塞状态处理程序未调用
resolve
reject
。检查所有路径,包括错误和模态框关闭的情况。
控制台提示
the item is malformed
返回值结构错误。对比步骤3中的表格,键名必须完全匹配。
对话框已选择项目,但未插入任何内容,也无错误文本光标不在文本块中,或在调用resolve前已关闭链接编辑器。请在打开对应字段后重试。
自定义模态框被编辑器遮挡为其设置高于编辑器容器的
z-index
。演示中的原生
<dialog>
已位于顶层。

References

参考资料