article-content-renderer-vue2 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -78
- package/dist/article-content-renderer-vue2.css +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +425 -739
- package/dist/types/components/ArticleContentRenderer.vue.d.ts +4 -8
- package/dist/types/index.d.ts +1 -1
- package/dist/types/protocols/types.d.ts +4 -8
- package/dist/types/types.d.ts +26 -16
- package/package.json +1 -1
- package/protocol/article-content-protocol-v1.json +82 -13
- package/dist/types/components/AdManagerAd.d.ts +0 -39
- package/dist/types/components/AdSenseAd.d.ts +0 -18
package/README.md
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
- 使用 Vue 2 `CreateElement` 和 `VNodeData`,不是 Vue 3 兼容层。
|
|
11
11
|
- 支持严格模式和非严格容错渲染。
|
|
12
12
|
- 拦截危险链接和图片 URL。
|
|
13
|
-
- articleButton
|
|
13
|
+
- articleButton 的 text/button 完整 href 由使用者回调生成。
|
|
14
|
+
- articleButton 的 link 样式直接使用协议节点中的 href,不调用 resolver。
|
|
14
15
|
- 支持 Vue 2 SSR。
|
|
15
16
|
- 提供 TypeScript 类型、结构化错误和 CSS Variables。
|
|
16
17
|
- Vue 作为 peer dependency,不会打入组件包。
|
|
@@ -110,92 +111,103 @@ import 'article-content-renderer-vue2/style.css'
|
|
|
110
111
|
Vue.use(ArticleContentRendererPlugin)
|
|
111
112
|
```
|
|
112
113
|
|
|
113
|
-
##
|
|
114
|
+
## 自定义插槽与图片地址
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
通过 `customSlots` 描述插槽位置,再使用与 `id` 同名的具名插槽传入任意 Vue 内容:
|
|
116
117
|
|
|
117
118
|
```ts
|
|
118
|
-
interface
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
loc: readonly number[]
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interface PubId {
|
|
125
|
-
adm: string
|
|
126
|
-
ads: string
|
|
119
|
+
interface CustomSlot {
|
|
120
|
+
id: string
|
|
121
|
+
location: number
|
|
127
122
|
}
|
|
128
123
|
```
|
|
129
124
|
|
|
130
125
|
```vue
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
adm: ['banner-1', 'banner-2'],
|
|
135
|
-
ads: ['123', '456'],
|
|
136
|
-
loc: [2, 5],
|
|
137
|
-
}"
|
|
138
|
-
:pubid="{
|
|
139
|
-
adm: '/23054585162/newsflowly/',
|
|
140
|
-
ads: '3887371527059481',
|
|
141
|
-
}"
|
|
142
|
-
ad-title="Advertisement"
|
|
143
|
-
image-base-url="https://cdn.example.com/"
|
|
144
|
-
@render-error="handleRenderError"
|
|
145
|
-
/>
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
`loc` 使用从 1 开始的 `document.content` 顶层位置,广告会插入在对应元素前面。位置超出文档长度时直接忽略。每个非空 `adm`/`ads` 数组的长度都必须与 `loc` 一致,否则不生成广告占位,并通过 `render-error` 上报 `AD_CONFIG_LENGTH_MISMATCH`。
|
|
149
|
-
|
|
150
|
-
广告选择规则:
|
|
151
|
-
|
|
152
|
-
- 同一位置同时有 `adm` 和 `ads`:先请求 ADM;只有 ADM 返回空广告时才请求对应 AdSense。
|
|
153
|
-
- 只有 `adm`:只请求 ADM,空广告也不回退。
|
|
154
|
-
- 只有 `ads`:直接请求 AdSense。
|
|
155
|
-
|
|
156
|
-
宿主项目需要分别加载一次 Google Publisher Tag 和 Google AdSense SDK。组件通过 `googletag.cmd` 和 `adsbygoogle` 队列请求广告,不会为每个广告位重复插入 `<script>`。
|
|
157
|
-
|
|
158
|
-
ADM 和 AdSense 共用稳定的全局 class,样式由宿主项目覆盖:
|
|
126
|
+
<script lang="ts">
|
|
127
|
+
import Vue from 'vue'
|
|
128
|
+
import type { CustomSlot } from 'article-content-renderer-vue2'
|
|
159
129
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
130
|
+
export default Vue.extend({
|
|
131
|
+
data() {
|
|
132
|
+
return {
|
|
133
|
+
customSlots: [
|
|
134
|
+
{ id: 'article-ad-1', location: 2 },
|
|
135
|
+
{ id: 'recommendation', location: 5 },
|
|
136
|
+
{ id: 'article-ad-2', location: 5 },
|
|
137
|
+
] as CustomSlot[],
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
</script>
|
|
166
142
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
143
|
+
<template>
|
|
144
|
+
<ArticleContentRenderer
|
|
145
|
+
:document="article"
|
|
146
|
+
:custom-slots="customSlots"
|
|
147
|
+
>
|
|
148
|
+
<template #article-ad-1>
|
|
149
|
+
<MyAd slot-id="top" />
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<template #recommendation>
|
|
153
|
+
<RecommendationCard />
|
|
154
|
+
</template>
|
|
155
|
+
|
|
156
|
+
<template #article-ad-2>
|
|
157
|
+
<MyAd slot-id="middle" />
|
|
158
|
+
</template>
|
|
159
|
+
</ArticleContentRenderer>
|
|
160
|
+
</template>
|
|
173
161
|
```
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
`adTitle` 默认为 `Advertisement`。`imageBaseUrl` 默认为 `https://www.doitme.link/`;传入新地址时,只替换文档图片中该默认前缀,其他图片 URL 保持不变。
|
|
163
|
+
插槽规则:
|
|
178
164
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
165
|
+
- `location` 从 1 开始;`location: 5` 表示插入到 `document.content[4]` 之前。
|
|
166
|
+
- 同一个 `location` 可以配置多个不同 `id`,并按照数组中的顺序渲染。
|
|
167
|
+
- `id` 应当唯一,并且必须与具名插槽名称一致。
|
|
168
|
+
- 非正整数或超过 `document.content` 长度的位置会被忽略。
|
|
169
|
+
- 渲染器不会为插槽额外创建包装 DOM,样式和生命周期由插槽组件自行控制。
|
|
170
|
+
- 具名插槽会收到 `{ id, location }` 作为作用域参数。
|
|
182
171
|
|
|
183
|
-
|
|
184
|
-
interface ArticleButtonAttrs {
|
|
185
|
-
id: string
|
|
186
|
-
title?: string
|
|
187
|
-
text: string
|
|
188
|
-
style: 'text' | 'button'
|
|
189
|
-
}
|
|
190
|
-
```
|
|
172
|
+
广告组件也通过具名插槽传入,并自行负责 SDK 加载、广告请求、空广告回退、唯一 DOM ID 和卸载清理。
|
|
191
173
|
|
|
192
|
-
|
|
174
|
+
`imageBaseUrl` 默认为 `https://www.doitme.link/`;传入新地址时,只替换文档图片中该默认前缀,其他图片 URL 保持不变。
|
|
175
|
+
## articleButton 链接
|
|
193
176
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
177
|
+
`style: "button"`、`style: "text"` 和 `style: "link"` 都使用 `<a>` 渲染。它们的链接来源不同:
|
|
178
|
+
|
|
179
|
+
- text/button:必须提供 `id`,通过 `resolveArticleButtonLink` 生成完整 `href`。
|
|
180
|
+
- link:`id` 可省略,直接使用节点的 `href`,不会调用 `resolveArticleButtonLink`。
|
|
181
|
+
|
|
182
|
+
对应的 TypeScript 类型是可辨识联合:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
interface ArticleButtonActionAttrs {
|
|
186
|
+
id: string
|
|
187
|
+
title?: string
|
|
188
|
+
text: string
|
|
189
|
+
style: 'text' | 'button'
|
|
190
|
+
href?: never
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface ArticleButtonLinkAttrs {
|
|
194
|
+
id?: string
|
|
195
|
+
title?: string
|
|
196
|
+
text: string
|
|
197
|
+
style: 'link'
|
|
198
|
+
href?: string
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
type ArticleButtonAttrs = ArticleButtonActionAttrs | ArticleButtonLinkAttrs
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
resolver 只处理 text/button,因此回调中的 `attrs.id` 始终是 `string`:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
type ResolveArticleButtonLink = (
|
|
208
|
+
attrs: Readonly<ArticleButtonActionAttrs>,
|
|
209
|
+
node: Readonly<ArticleButtonActionNode>,
|
|
210
|
+
) =>
|
|
199
211
|
| string
|
|
200
212
|
| {
|
|
201
213
|
href: string
|
|
@@ -219,7 +231,35 @@ const resolveArticleButtonLink: ResolveArticleButtonLink = (attrs) => {
|
|
|
219
231
|
<a href="/detail/view-more">...</a>
|
|
220
232
|
```
|
|
221
233
|
|
|
222
|
-
组件不会自动添加 `?`,也不会自动把节点属性转换成查询参数。
|
|
234
|
+
组件不会自动添加 `?`,也不会自动把节点属性转换成查询参数。
|
|
235
|
+
|
|
236
|
+
### link 样式直接使用 href
|
|
237
|
+
|
|
238
|
+
link 类型的地址完整写在协议节点中,不经过 resolver,也不会被自动改写:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
const article: ArticleDocument = {
|
|
242
|
+
type: 'doc',
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: 'articleButton',
|
|
246
|
+
attrs: {
|
|
247
|
+
text: '查看协议说明',
|
|
248
|
+
style: 'link',
|
|
249
|
+
href: '/docs/article-content-protocol#article-button',
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
最终 DOM:
|
|
257
|
+
|
|
258
|
+
```html
|
|
259
|
+
<a href="/docs/article-content-protocol#article-button">查看协议说明</a>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
协议允许 link 类型省略 `href`;此时会渲染不带 `href` 的禁用态 `<a>`。`javascript:`、`data:` 等不安全地址也会被拦截,并通过 `render-error` 事件报告 `UNSAFE_URL`。
|
|
223
263
|
|
|
224
264
|
### 使用闭包
|
|
225
265
|
|
|
@@ -257,11 +297,9 @@ function handleArticleButtonClick(payload: ArticleButtonClickPayload): void {
|
|
|
257
297
|
| `document` | `unknown` | 必填 | Article Content Protocol 文档 |
|
|
258
298
|
| `protocolVersion` | `number` | `1` | 协议适配器版本 |
|
|
259
299
|
| `strict` | `boolean` | `false` | 校验失败时是否停止整篇正文渲染 |
|
|
260
|
-
| `
|
|
261
|
-
| `pubid` | `PubId` | `{ adm: '', ads: '' }` | ADM/AdSense 发布标识 |
|
|
262
|
-
| `adTitle` | `string` | `"Advertisement"` | ADM 和 AdSense 共用的广告标题 |
|
|
300
|
+
| `customSlots` | `CustomSlot[]` | `[]` | 配置一个或多个具名插槽的顶层正文插入位置 |
|
|
263
301
|
| `imageBaseUrl` | `string` | `"https://www.doitme.link/"` | 替换文档图片的默认地址前缀 |
|
|
264
|
-
| `resolveArticleButtonLink` | `ResolveArticleButtonLink` | `undefined` |
|
|
302
|
+
| `resolveArticleButtonLink` | `ResolveArticleButtonLink` | `undefined` | 为 text/button 生成完整链接;link 类型不调用 |
|
|
265
303
|
|
|
266
304
|
## Events
|
|
267
305
|
|
|
@@ -276,7 +314,7 @@ interface ArticleButtonClickPayload {
|
|
|
276
314
|
}
|
|
277
315
|
```
|
|
278
316
|
|
|
279
|
-
|
|
317
|
+
三种样式都会在原生跳转前同步触发事件。调用 `payload.event.preventDefault()` 可以由 Vue Router 3 接管跳转。
|
|
280
318
|
|
|
281
319
|
### render-error
|
|
282
320
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--acp-color-text: inherit;--acp-color-muted: #667085;--acp-color-border: #d0d5dd;--acp-color-surface: #f8fafc;--acp-color-accent: #2563eb;--acp-color-accent-hover: #1d4ed8;--acp-color-on-accent: #ffffff;--acp-radius: .375rem;--acp-spacing-block: 1rem;--acp-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace}.acp-document{display:contents}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-article-button,.acp-table-wrapper{box-sizing:border-box}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-table-wrapper{margin-block:0 var(--acp-spacing-block)}.acp-paragraph:first-child,.acp-heading:first-child,.acp-blockquote:first-child,.acp-list:first-child,.acp-code-block:first-child,.acp-horizontal-rule:first-child,.acp-image:first-child,.acp-table-wrapper:first-child{margin-block-start:0}.acp-paragraph{color:var(--acp-color-text)}.acp-blockquote{margin-inline:0;padding-inline-start:1rem;border-inline-start:.25rem solid var(--acp-color-border);color:var(--acp-color-muted)}.acp-list{padding-inline-start:1.5rem}.acp-list-item>:last-child{margin-block-end:0}.acp-code-block{overflow-x:auto;padding:1rem;border-radius:var(--acp-radius);background:var(--acp-color-surface);font-family:var(--acp-font-mono);white-space:pre}.acp-mark--code{padding:.1em .25em;border-radius:calc(var(--acp-radius) / 2);background:var(--acp-color-surface);font-family:var(--acp-font-mono)}.acp-horizontal-rule{border:0;border-block-start:1px solid var(--acp-color-border)}.acp-image{display:flex;width:100%}.acp-image--left{justify-content:flex-start}.acp-image--center{justify-content:center}.acp-image--right{justify-content:flex-end}.acp-image__element{display:block;max-width:100%;height:auto}.acp-link,.acp-article-button--text{color:var(--acp-color-accent);text-decoration:underline;text-underline-offset:.15em}.acp-link:hover,.acp-article-button--text:hover{color:var(--acp-color-accent-hover)}.acp-article-button{display:inline-flex;align-items:center;justify-content:center;margin-block:0 var(--acp-spacing-block);cursor:pointer}.acp-article-button--button{min-height:2.5rem;padding:.5rem 1rem;border-radius:var(--acp-radius);background:var(--acp-color-accent);color:var(--acp-color-on-accent);text-decoration:none}.acp-article-button--button:hover{background:var(--acp-color-accent-hover)}.acp-article-button--disabled{cursor:not-allowed;opacity:.55}.acp-table-wrapper{width:100%;overflow-x:auto}.acp-
|
|
1
|
+
:root{--acp-color-text: inherit;--acp-color-muted: #667085;--acp-color-border: #d0d5dd;--acp-color-surface: #f8fafc;--acp-color-accent: #2563eb;--acp-color-accent-hover: #1d4ed8;--acp-color-on-accent: #ffffff;--acp-radius: .375rem;--acp-spacing-block: 1rem;--acp-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace}.acp-document{display:contents}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-article-button,.acp-table-wrapper{box-sizing:border-box}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-table-wrapper{margin-block:0 var(--acp-spacing-block)}.acp-paragraph:first-child,.acp-heading:first-child,.acp-blockquote:first-child,.acp-list:first-child,.acp-code-block:first-child,.acp-horizontal-rule:first-child,.acp-image:first-child,.acp-table-wrapper:first-child{margin-block-start:0}.acp-paragraph{color:var(--acp-color-text)}.acp-blockquote{margin-inline:0;padding-inline-start:1rem;border-inline-start:.25rem solid var(--acp-color-border);color:var(--acp-color-muted)}.acp-list{padding-inline-start:1.5rem}.acp-list-item>:last-child{margin-block-end:0}.acp-code-block{overflow-x:auto;padding:1rem;border-radius:var(--acp-radius);background:var(--acp-color-surface);font-family:var(--acp-font-mono);white-space:pre}.acp-mark--code{padding:.1em .25em;border-radius:calc(var(--acp-radius) / 2);background:var(--acp-color-surface);font-family:var(--acp-font-mono)}.acp-horizontal-rule{border:0;border-block-start:1px solid var(--acp-color-border)}.acp-image{display:flex;width:100%}.acp-image--left{justify-content:flex-start}.acp-image--center{justify-content:center}.acp-image--right{justify-content:flex-end}.acp-image__element{display:block;max-width:100%;height:auto}.acp-link,.acp-article-button--text,.acp-article-button--link{color:var(--acp-color-accent);text-decoration:underline;text-underline-offset:.15em}.acp-link:hover,.acp-article-button--text:hover,.acp-article-button--link:hover{color:var(--acp-color-accent-hover)}.acp-article-button{display:inline-flex;align-items:center;justify-content:center;margin-block:0 var(--acp-spacing-block);cursor:pointer}.acp-article-button--button{min-height:2.5rem;padding:.5rem 1rem;border-radius:var(--acp-radius);background:var(--acp-color-accent);color:var(--acp-color-on-accent);text-decoration:none}.acp-article-button--button:hover{background:var(--acp-color-accent-hover)}.acp-article-button--disabled{cursor:not-allowed;opacity:.55}.acp-table-wrapper{width:100%;overflow-x:auto}.acp-table{width:100%;border-collapse:collapse}.acp-table-cell{padding:.625rem .75rem;border:1px solid var(--acp-color-border);vertical-align:top}.acp-table-cell>:last-child{margin-block-end:0}.acp-render-error{padding:.75rem 1rem;border:1px solid #fda29b;border-radius:var(--acp-radius);background:#fffbfa;color:#b42318}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Y=Object.defineProperty,G=Object.defineProperties;var H=Object.getOwnPropertyDescriptors;var v=Object.getOwnPropertySymbols;var W=Object.prototype.hasOwnProperty,Q=Object.prototype.propertyIsEnumerable;var k=(i,e,t)=>e in i?Y(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,m=(i,e)=>{for(var t in e||(e={}))W.call(e,t)&&k(i,t,e[t]);if(v)for(var t of v(e))Q.call(e,t)&&k(i,t,e[t]);return i},S=(i,e)=>G(i,H(e));var O=(i,e,t)=>k(i,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const N=require("vue"),X=new Set(["http:","https:","mailto:","tel:"]),J=new Set(["http:","https:","blob:"]),Z="https://article-content-renderer.invalid/",I="https://www.doitme.link/";function tt(i,e){if(typeof i!="string")return i;const t=i.trim();if(!t.startsWith(I))return t;const n=(e.trim()||I).replace(/\/+$/u,""),s=t.slice(I.length).replace(/^\/+/,"");return`${n}/${s}`}function E(i,e){if(typeof i!="string")return null;const t=i.trim();if(!t||/[\u0000-\u001F\u007F]/u.test(t))return null;try{const r=new URL(t,Z);return(e==="link"?X:J).has(r.protocol)?t:null}catch(r){return null}}function D(i,e){const t=new Set(typeof i=="string"?i.trim().split(/\s+/u).filter(Boolean):[]);return e==="_blank"&&(t.add("noopener"),t.add("noreferrer")),t.size>0?[...t].join(" "):void 0}function et(i){const e=i.trim();return e?e.startsWith("ca-pub-")?e:`ca-pub-${e}`:""}const x=N.extend({name:"ArticleAdSenseAd",props:{publisherId:{type:String,required:!0},slotId:{type:[String,Number],required:!0},title:{type:String,default:"Advertisement"}},data(){return{observer:null,requestedKey:null}},computed:{adClient(){return et(this.publisherId)},adSlot(){return String(this.slotId).trim()},requestKey(){return`${this.adClient}:${this.adSlot}`}},watch:{requestKey(){this.requestedKey=null,this.stopObserver(),this.$nextTick(()=>this.startObserver())}},mounted(){this.startObserver()},beforeDestroy(){this.stopObserver()},methods:{requestAd(){var i;if(!(!this.adClient||!this.adSlot||this.requestedKey===this.requestKey))try{const e=window;((i=e.adsbygoogle)!=null?i:e.adsbygoogle=[]).push({}),this.requestedKey=this.requestKey}catch(e){console.error("[ArticleContentRenderer] Failed to request AdSense ad:",e)}},startObserver(){const i=this.$refs.root;if(!(!i||!this.adClient||!this.adSlot)){if(typeof IntersectionObserver=="undefined"){this.requestAd();return}this.observer=new IntersectionObserver(e=>{e.some(t=>t.isIntersecting)&&(this.requestAd(),this.stopObserver())},{rootMargin:"200px 0px"}),this.observer.observe(i)}},stopObserver(){var i;(i=this.observer)==null||i.disconnect(),this.observer=null}},render(i){return!this.adClient||!this.adSlot?i():i("div",{ref:"root",staticClass:"article-ad-wrapper",attrs:{"data-google-ad":"true"}},[i("div",{staticClass:"article-ad-title"},this.title),i("ins",{key:this.requestKey,staticClass:"adsbygoogle article-ad-unit",style:{display:"block",width:"100%"},attrs:{"data-ad-client":this.adClient,"data-ad-slot":this.adSlot}})])}});function C(){var e;const i=window;return(e=i.googletag)!=null||(i.googletag={cmd:[]}),i.googletag}function rt(i,e){const t=i.trim().replace(/\/+$/u,""),r=e.replace(/^\/+|\/+$/gu,"");return t&&r?`${t}/${r}`:""}const it=N.extend({name:"ArticleAdManagerAd",props:{publisherId:{type:String,required:!0},slotId:{type:[String,Number],required:!0},title:{type:String,default:"Advertisement"},fallbackPublisherId:{type:String,default:""},fallbackSlotId:{type:[String,Number],default:void 0}},data(){return{observer:null,definedSlot:null,pubAdsService:null,slotRenderEnded:null,emptyAdmKey:null,cancelled:!1}},computed:{admSlotId(){return String(this.slotId).trim()},adsSlotId(){return this.fallbackSlotId===void 0?"":String(this.fallbackSlotId).trim()},adUnitPath(){return rt(this.publisherId,this.admSlotId)},fallbackKey(){return`${this.adUnitPath}:${this.admSlotId}:${this.fallbackPublisherId}:${this.adsSlotId}`},hasAdSenseFallback(){return!!(this.fallbackPublisherId.trim()&&this.adsSlotId)},shouldUseAdSense(){return this.hasAdSenseFallback&&this.emptyAdmKey===this.fallbackKey}},watch:{fallbackKey(){this.restartAdManager()}},mounted(){this.startObserver()},beforeDestroy(){this.cleanupAdManager()},methods:{restartAdManager(){this.cleanupAdManager(),this.emptyAdmKey=null,this.$nextTick(()=>this.startObserver())},startObserver(){const i=this.$refs.root;if(!(!i||!this.adUnitPath||!this.admSlotId||this.shouldUseAdSense)){if(this.cancelled=!1,typeof IntersectionObserver=="undefined"){this.requestAd();return}this.observer=new IntersectionObserver(e=>{var t;e.some(r=>r.isIntersecting)&&(this.requestAd(),(t=this.observer)==null||t.disconnect(),this.observer=null)},{rootMargin:"200px 0px"}),this.observer.observe(i)}},requestAd(){const i=this.$refs.unit;if(!i)return;const e=C();e.cmd.push(()=>{if(this.cancelled)return;const t=i.clientWidth,r=i.clientHeight,n=t>0&&r>0?["fluid",[t,r]]:"fluid",s=e.defineSlot(this.adUnitPath,n,this.admSlotId);if(!s)return;const a=e.pubads(),o=c=>{if(this.cancelled||c.slot!==s||!c.isEmpty||!this.hasAdSenseFallback)return;const d=this.fallbackKey;this.cleanupAdManager(),this.emptyAdmKey=d};this.definedSlot=s,this.pubAdsService=a,this.slotRenderEnded=o,a.addEventListener("slotRenderEnded",o),s.addService(a),e.enableServices(),e.display(this.admSlotId)})},cleanupAdManager(){var n;this.cancelled=!0,(n=this.observer)==null||n.disconnect(),this.observer=null;const i=this.definedSlot,e=this.pubAdsService,t=this.slotRenderEnded;if(this.definedSlot=null,this.pubAdsService=null,this.slotRenderEnded=null,!i&&!t)return;const r=C();r.cmd.push(()=>{var s,a;e&&t&&((s=e.removeEventListener)==null||s.call(e,"slotRenderEnded",t)),i&&((a=r.destroySlots)==null||a.call(r,[i]))})}},render(i){return this.shouldUseAdSense?i(x,{props:{publisherId:this.fallbackPublisherId,slotId:this.adsSlotId,title:this.title}}):!this.adUnitPath||!this.admSlotId?i():i("div",{ref:"root",staticClass:"article-ad-wrapper article-adm-wrapper",attrs:{"data-google-ad-manager":"true","data-ad-unit-path":this.adUnitPath}},[i("div",{staticClass:"article-ad-title"},this.title),i("div",{ref:"unit",staticClass:"article-ad-unit article-adm-unit",attrs:{id:this.admSlotId}})])}}),nt=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]);function g(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function R(i){return g(i)?i:{}}function h(i,e,t,r){var c;const n=g(t)?t:{},s=g(t)?r:t,a={},o={};for(const[d,f]of Object.entries(n))if(d==="class")a.class=f;else if(d==="style")a.style=f;else if(d.startsWith("on")&&typeof f=="function"){const F=d.slice(2).toLowerCase();a.on=S(m({},(c=a.on)!=null?c:{}),{[F]:f})}else f!==void 0&&f!==!1&&(o[d]=f);return Object.keys(o).length>0&&(a.attrs=o),i.createElement(e,a,s)}function y(i){return Array.isArray(i)?i:[]}function p(i,...e){return`${i}/${e.map(String).join("/")}`}function q(i){return i==="left"||i==="center"||i==="right"||i==="justify"}function st(i){return i==="left"||i==="center"||i==="right"}function L(i){return i==="_blank"||i==="_self"}function A(i,e){i.reportIssue(e)}function at(i,e,t){if(!g(i)||i.type!=="text"||typeof i.text!="string"||!i.text)return null;let r=i.text;const n=y(i.marks);for(let s=0;s<n.length;s+=1){const a=n[s];if(!g(a)||typeof a.type!="string")continue;const o=p(e,"marks",s);switch(a.type){case"bold":r=h(t,"strong",{class:"acp-mark acp-mark--bold"},[r]);break;case"italic":r=h(t,"em",{class:"acp-mark acp-mark--italic"},[r]);break;case"strike":r=h(t,"s",{class:"acp-mark acp-mark--strike"},[r]);break;case"underline":r=h(t,"u",{class:"acp-mark acp-mark--underline"},[r]);break;case"code":r=h(t,"code",{class:"acp-mark acp-mark--code"},[r]);break;case"link":{const c=R(a.attrs),d=E(c.href,"link");if(!d){A(t,{code:"UNSAFE_URL",path:p(o,"attrs","href"),message:"The link URL is empty, malformed, or uses a disallowed protocol.",nodeType:"link"});break}const f=L(c.target)?c.target:"_blank";r=h(t,"a",{class:"acp-link",href:d,target:f,rel:D(void 0,f)},[r]);break}}}return r}function w(i,e,t){return y(i).map((r,n)=>at(r,p(e,n),t)).filter(r=>r!==null)}function B(i,e,t){return!g(i)||i.type!=="listItem"?null:h(t,"li",{class:"acp-list-item","data-node-type":"listItem"},P(i.content,p(e,"content"),t))}function ot(i,e,t){return!g(i)||i.type!=="tableCell"?null:h(t,"td",{class:"acp-table-cell","data-node-type":"tableCell"},P(i.content,p(e,"content"),t))}function lt(i,e,t){if(!g(i)||i.type!=="tableRow")return null;const r=y(i.content).map((n,s)=>ot(n,p(e,"content",s),t)).filter(n=>n!==null);return h(t,"tr",{class:"acp-table-row","data-node-type":"tableRow"},r)}function dt(i){var n;if(g(i)&&i.target!==void 0&&!L(i.target)||g(i)&&i.rel!==void 0&&typeof i.rel!="string")return null;const e=typeof i=="string"?{href:i}:g(i)&&typeof i.href=="string"?m(m({href:i.href},L(i.target)?{target:i.target}:{}),typeof i.rel=="string"?{rel:i.rel}:{}):null;if(!e)return null;const t=E(e.href,"link");if(!t)return null;const r=(n=e.target)!=null?n:"_self";return{href:t,target:r,rel:D(e.rel,r)}}function ct(i,e,t){var c;const r=R(i.attrs);if(typeof r.id!="string"||!r.id||typeof r.text!="string"||!r.text||r.style!=="text"&&r.style!=="button")return null;const n=Object.freeze(S(m({id:r.id},typeof r.title=="string"?{title:r.title}:{}),{text:r.text,style:r.style})),s=Object.freeze({type:"articleButton",attrs:n});let a=null;if(!t.resolveArticleButtonLink)A(t,{code:"LINK_RESOLUTION_FAILED",path:e,message:"No resolveArticleButtonLink callback was provided for an articleButton node.",nodeType:"articleButton"});else try{const d=t.resolveArticleButtonLink(n,s);a=dt(d),a||A(t,{code:typeof d=="string"||g(d)&&typeof d.href=="string"?"UNSAFE_URL":"LINK_RESOLUTION_FAILED",path:e,message:"The articleButton link resolver returned no usable safe URL.",nodeType:"articleButton"})}catch(d){A(t,{code:"LINK_RESOLUTION_FAILED",path:e,message:`The articleButton link resolver threw an error: ${d instanceof Error?d.message:String(d)}`,nodeType:"articleButton"})}const o=(c=a==null?void 0:a.href)!=null?c:null;return h(t,"a",{class:["acp-article-button",`acp-article-button--${n.style}`,!o&&"acp-article-button--disabled"],href:o!=null?o:void 0,target:a==null?void 0:a.target,rel:a==null?void 0:a.rel,title:n.title,"data-node-type":"articleButton","data-article-button-id":n.id,"data-article-button-style":n.style,"aria-disabled":o?void 0:"true",onClick:d=>{o||d.preventDefault(),t.emitArticleButtonClick({attrs:n,node:s,href:o,event:d})}},n.text)}function M(i,e,t){if(!g(i)||typeof i.type!="string"||!nt.has(i.type))return null;const r=R(i.attrs);switch(i.type){case"paragraph":{const n=q(r.textAlign)?r.textAlign:void 0;return h(t,"p",{class:"acp-paragraph","data-node-type":"paragraph",style:n?{textAlign:n}:void 0},w(i.content,p(e,"content"),t))}case"heading":{const n=Number.isInteger(r.level)&&Number(r.level)>=1&&Number(r.level)<=6?Number(r.level):1,s=q(r.textAlign)?r.textAlign:void 0;return h(t,`h${n}`,{class:["acp-heading",`acp-heading--${n}`],"data-node-type":"heading",style:s?{textAlign:s}:void 0},w(i.content,p(e,"content"),t))}case"blockquote":return h(t,"blockquote",{class:"acp-blockquote","data-node-type":"blockquote"},P(i.content,p(e,"content"),t));case"bulletList":{const n=y(i.content).map((s,a)=>B(s,p(e,"content",a),t)).filter(s=>s!==null);return h(t,"ul",{class:"acp-list acp-list--bullet","data-node-type":"bulletList"},n)}case"orderedList":{const n=Number.isInteger(r.start)&&Number(r.start)>=1?Number(r.start):1,s=y(i.content).map((a,o)=>B(a,p(e,"content",o),t)).filter(a=>a!==null);return h(t,"ol",{class:"acp-list acp-list--ordered","data-node-type":"orderedList",start:n},s)}case"codeBlock":{const n=typeof r.language=="string"&&r.language?r.language:void 0,s=y(i.content).filter(a=>g(a)&&a.type==="text"&&typeof a.text=="string").map(a=>a.text).join("");return h(t,"pre",{class:"acp-code-block","data-node-type":"codeBlock","data-language":n},[h(t,"code",{class:n?`language-${n}`:void 0},s)])}case"horizontalRule":return h(t,"hr",{class:"acp-horizontal-rule","data-node-type":"horizontalRule"});case"image":{const n=E(tt(r.src,t.imageBaseUrl),"image");if(!n)return A(t,{code:"UNSAFE_URL",path:p(e,"attrs","src"),message:"The image URL is empty, malformed, or uses a disallowed protocol.",nodeType:"image"}),null;const s=st(r.imageAlign)?r.imageAlign:"center",a=Number.isInteger(r.width)&&Number(r.width)>=1&&Number(r.width)<=1e4?Number(r.width):void 0,o=Number.isInteger(r.height)&&Number(r.height)>=1&&Number(r.height)<=1e4?Number(r.height):void 0;return h(t,"div",{class:["acp-image",`acp-image--${s}`],"data-node-type":"image","data-image-align":s},[h(t,"img",{class:"acp-image__element",src:n,alt:typeof r.alt=="string"?r.alt:"",title:typeof r.title=="string"?r.title:void 0,width:a,height:o,"data-image-align":s})])}case"articleButton":return ct(i,e,t);case"table":{const n=y(i.content).map((s,a)=>lt(s,p(e,"content",a),t)).filter(s=>s!==null);return h(t,"div",{class:"acp-table-wrapper","data-node-type":"table"},[h(t,"table",{class:"acp-table"},[h(t,"tbody",n)])])}}return null}function P(i,e,t){return y(i).map((r,n)=>M(r,p(e,n),t)).filter(r=>r!==null)}function $(i){return typeof i=="string"||typeof i=="number"?i:void 0}function ut(i,e){const t=$(i.adm),r=$(i.ads),n=t!==void 0&&e.admPublisherId?e.createElement(it,{key:`adm:${i.index}:${String(t)}`,props:{publisherId:e.admPublisherId,slotId:t,title:e.adTitle,fallbackPublisherId:r!==void 0?e.adsPublisherId:void 0,fallbackSlotId:r}}):r!==void 0&&e.adsPublisherId?e.createElement(x,{key:`ads:${i.index}:${String(r)}`,props:{publisherId:e.adsPublisherId,slotId:r,title:e.adTitle}}):null;return e.createElement("div",{key:`/adConf/${i.index}`,staticClass:"acp-ad-slot",attrs:{"data-node-type":"adSlot","data-ad-slot":"true","data-ad-index":i.index,"data-ad-location":i.location,"data-adm":t,"data-ads":r}},n?[n]:[])}function ht(i,e){const t=y(i.content),r=new Map;e.adSlots.forEach(s=>{var o;if(s.location>t.length)return;const a=(o=r.get(s.location))!=null?o:[];a.push(s),r.set(s.location,a)});const n=[];return t.forEach((s,a)=>{var d;const o=a+1;(d=r.get(o))==null||d.forEach(f=>n.push(ut(f,e)));const c=M(s,p("/content",a),e);c&&typeof c!="string"&&n.push(c)}),n}function ft(i,e){return!g(i)||i.type!=="doc"?[]:ht(i,e)}const pt=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]),gt=new Set(["left","center","right","justify"]),yt=new Set(["left","center","right"]),mt=new Set(["bold","italic","strike","underline","code"]);function b(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function l(i,e){return`${i}/${String(e).replaceAll("~","~0").replaceAll("/","~1")}`}function u(i,...e){let t=i;for(const r of e)t=l(t,r);return t}class bt{constructor(){O(this,"issues",[])}validate(e){if(!b(e))return this.add("INVALID_ROOT","","The document must be an object."),this.result();this.checkProperties(e,"",["type","content"],["type","content"]),e.type!=="doc"&&this.add("INVALID_ROOT","/type",'The root node type must be "doc".');const t=this.requireArray(e.content,"/content");return t==null||t.forEach((r,n)=>this.validateBlock(r,l("/content",n))),this.result()}result(){return{valid:this.issues.length===0,issues:this.issues}}add(e,t,r,n){this.issues.push(m({code:e,path:t,message:r},n?{nodeType:n}:{}))}checkProperties(e,t,r,n=[],s){const a=new Set(r);for(const o of Object.keys(e))a.has(o)||this.add("UNKNOWN_PROPERTY",l(t,o),`Property "${o}" is not allowed.`,s);for(const o of n)o in e||this.add("MISSING_PROPERTY",l(t,o),`Required property "${o}" is missing.`,s)}requireArray(e,t,r){return Array.isArray(e)?e:(this.add("INVALID_TYPE",t,"Expected an array.",r),null)}optionalArray(e,t,r){return e===void 0?[]:this.requireArray(e,t,r)}requireNonEmptyArray(e,t,r){const n=this.requireArray(e,t,r);return n&&n.length===0&&this.add("INVALID_CONTENT",t,`Node "${r}" must contain at least one child.`,r),n}requireRecord(e,t,r){return b(e)?e:(this.add("INVALID_TYPE",t,"Expected an object.",r),null)}optionalRecord(e,t,r){return e===void 0?{}:this.requireRecord(e,t,r)}requireString(e,t,r,n={}){return typeof e!="string"?(this.add("INVALID_TYPE",t,"Expected a string.",r),!1):!n.allowEmpty&&e.length===0?(this.add("INVALID_VALUE",t,"The string must not be empty.",r),!1):n.maxLength!==void 0&&e.length>n.maxLength?(this.add("INVALID_VALUE",t,`The string must contain at most ${n.maxLength} characters.`,r),!1):!0}optionalString(e,t,r,n={}){e!==void 0&&this.requireString(e,t,r,n)}requireInteger(e,t,r,n,s){if(!Number.isInteger(e))return this.add("INVALID_TYPE",t,"Expected an integer.",r),!1;const a=e;return n!==void 0&&a<n?(this.add("INVALID_VALUE",t,`Value must be at least ${n}.`,r),!1):s!==void 0&&a>s?(this.add("INVALID_VALUE",t,`Value must be at most ${s}.`,r),!1):!0}validateBlock(e,t){if(!b(e)){this.add("INVALID_TYPE",t,"A block node must be an object.");return}const r=e.type;if(typeof r!="string"){this.add("MISSING_PROPERTY",l(t,"type"),"A block node requires a type.");return}if(!pt.has(r)){this.add("UNKNOWN_NODE",l(t,"type"),`Unknown block node "${r}".`,r);return}switch(r){case"paragraph":this.validateParagraph(e,t);break;case"heading":this.validateHeading(e,t);break;case"blockquote":this.validateBlockquote(e,t);break;case"bulletList":this.validateBulletList(e,t);break;case"orderedList":this.validateOrderedList(e,t);break;case"codeBlock":this.validateCodeBlock(e,t);break;case"horizontalRule":this.checkProperties(e,t,["type"],["type"],r);break;case"image":this.validateImage(e,t);break;case"articleButton":this.validateArticleButton(e,t);break;case"table":this.validateTable(e,t);break}}validateParagraph(e,t){const r="paragraph";this.checkProperties(e,t,["type","attrs","content"],["type"],r),this.validateTextAlignAttrs(e.attrs,l(t,"attrs"),r,!1),this.validateInlineContent(e.content,l(t,"content"),r)}validateHeading(e,t){const r="heading";this.checkProperties(e,t,["type","attrs","content"],["type","attrs"],r);const n=this.requireRecord(e.attrs,l(t,"attrs"),r);n&&(this.checkProperties(n,l(t,"attrs"),["level","textAlign"],["level"],r),this.requireInteger(n.level,u(t,"attrs","level"),r,1,6),this.validateTextAlign(n.textAlign,u(t,"attrs","textAlign"),r)),this.validateInlineContent(e.content,l(t,"content"),r)}validateTextAlignAttrs(e,t,r,n){const s=n?this.requireRecord(e,t,r):this.optionalRecord(e,t,r);s&&(this.checkProperties(s,t,["textAlign"],[],r),this.validateTextAlign(s.textAlign,l(t,"textAlign"),r))}validateTextAlign(e,t,r){e!==void 0&&(typeof e!="string"?this.add("INVALID_TYPE",t,"Text alignment must be a string.",r):gt.has(e)||this.add("INVALID_VALUE",t,`Unsupported text alignment "${e}".`,r))}validateInlineContent(e,t,r){const n=this.optionalArray(e,t,r);n==null||n.forEach((s,a)=>this.validateText(s,l(t,a),!0))}validateText(e,t,r){if(!b(e)){this.add("INVALID_TYPE",t,"A text node must be an object.","text");return}const n=r?["type","text","marks"]:["type","text"];if(this.checkProperties(e,t,n,["type","text"],"text"),e.type!=="text"&&this.add("INVALID_CONTENT",l(t,"type"),"Expected a text node.","text"),this.requireString(e.text,l(t,"text"),"text"),r&&e.marks!==void 0){const s=this.requireArray(e.marks,l(t,"marks"),"text");s==null||s.forEach((a,o)=>this.validateMark(a,u(t,"marks",o)))}}validateMark(e,t){if(!b(e)){this.add("INVALID_TYPE",t,"A mark must be an object.");return}if(typeof e.type!="string"){this.add("MISSING_PROPERTY",l(t,"type"),"A mark requires a type.");return}if(mt.has(e.type)){this.checkProperties(e,t,["type"],["type"],e.type);return}if(e.type!=="link"){this.add("UNKNOWN_MARK",l(t,"type"),`Unknown mark "${e.type}".`,e.type);return}this.checkProperties(e,t,["type","attrs"],["type","attrs"],"link");const r=this.requireRecord(e.attrs,l(t,"attrs"),"link");r&&(this.checkProperties(r,l(t,"attrs"),["href","target"],["href"],"link"),this.requireString(r.href,u(t,"attrs","href"),"link"),r.target!==void 0&&r.target!=="_blank"&&r.target!=="_self"&&this.add("INVALID_VALUE",u(t,"attrs","target"),'Link target must be "_blank" or "_self".',"link"))}validateBlockquote(e,t){const r="blockquote";this.checkProperties(e,t,["type","content"],["type","content"],r);const n=this.requireNonEmptyArray(e.content,l(t,"content"),r);n==null||n.forEach((s,a)=>this.validateBlock(s,u(t,"content",a)))}validateBulletList(e,t){const r="bulletList";this.checkProperties(e,t,["type","content"],["type","content"],r);const n=this.requireNonEmptyArray(e.content,l(t,"content"),r);n==null||n.forEach((s,a)=>this.validateListItem(s,u(t,"content",a)))}validateOrderedList(e,t){const r="orderedList";this.checkProperties(e,t,["type","attrs","content"],["type","content"],r);const n=this.optionalRecord(e.attrs,l(t,"attrs"),r);n&&(this.checkProperties(n,l(t,"attrs"),["start"],[],r),n.start!==void 0&&this.requireInteger(n.start,u(t,"attrs","start"),r,1));const s=this.requireNonEmptyArray(e.content,l(t,"content"),r);s==null||s.forEach((a,o)=>this.validateListItem(a,u(t,"content",o)))}validateListItem(e,t){const r="listItem",n=this.requireRecord(e,t,r);if(!n)return;this.checkProperties(n,t,["type","content"],["type","content"],r),n.type!==r&&this.add("INVALID_CONTENT",l(t,"type"),"Expected a listItem node.",r);const s=this.requireNonEmptyArray(n.content,l(t,"content"),r);s==null||s.forEach((a,o)=>this.validateBlock(a,u(t,"content",o)))}validateCodeBlock(e,t){const r="codeBlock";this.checkProperties(e,t,["type","attrs","content"],["type"],r);const n=this.optionalRecord(e.attrs,l(t,"attrs"),r);n&&(this.checkProperties(n,l(t,"attrs"),["language"],[],r),this.optionalString(n.language,u(t,"attrs","language"),r,{maxLength:32}));const s=this.optionalArray(e.content,l(t,"content"),r);s&&(s.length>1&&this.add("INVALID_CONTENT",l(t,"content"),"A codeBlock may contain at most one text node.",r),s.forEach((a,o)=>this.validateText(a,u(t,"content",o),!1)))}validateImage(e,t){const r="image";this.checkProperties(e,t,["type","attrs"],["type","attrs"],r);const n=this.requireRecord(e.attrs,l(t,"attrs"),r);n&&(this.checkProperties(n,l(t,"attrs"),["src","alt","title","width","height","imageAlign"],["src"],r),this.requireString(n.src,u(t,"attrs","src"),r),this.optionalString(n.alt,u(t,"attrs","alt"),r,{allowEmpty:!0}),this.optionalString(n.title,u(t,"attrs","title"),r,{allowEmpty:!0}),n.width!==void 0&&this.requireInteger(n.width,u(t,"attrs","width"),r,1,1e4),n.height!==void 0&&this.requireInteger(n.height,u(t,"attrs","height"),r,1,1e4),n.imageAlign!==void 0&&(typeof n.imageAlign!="string"?this.add("INVALID_TYPE",u(t,"attrs","imageAlign"),"Image alignment must be a string.",r):yt.has(n.imageAlign)||this.add("INVALID_VALUE",u(t,"attrs","imageAlign"),`Unsupported image alignment "${n.imageAlign}".`,r)))}validateArticleButton(e,t){const r="articleButton";this.checkProperties(e,t,["type","attrs"],["type","attrs"],r);const n=this.requireRecord(e.attrs,l(t,"attrs"),r);n&&(this.checkProperties(n,l(t,"attrs"),["id","title","text","style"],["id","text","style"],r),this.requireString(n.id,u(t,"attrs","id"),r),this.optionalString(n.title,u(t,"attrs","title"),r),this.requireString(n.text,u(t,"attrs","text"),r),n.style!=="text"&&n.style!=="button"&&this.add("INVALID_VALUE",u(t,"attrs","style"),'Article button style must be "text" or "button".',r))}validateTable(e,t){const r="table";this.checkProperties(e,t,["type","content"],["type","content"],r);const n=this.requireNonEmptyArray(e.content,l(t,"content"),r);if(!n)return;let s=null;n.forEach((a,o)=>{const c=u(t,"content",o),d=this.validateTableRow(a,c);d!==null&&(s===null?s=d:d!==s&&this.add("TABLE_COLUMN_MISMATCH",l(c,"content"),`Expected ${s} table cells but received ${d}.`,"tableRow"))})}validateTableRow(e,t){var a;const r="tableRow",n=this.requireRecord(e,t,r);if(!n)return null;this.checkProperties(n,t,["type","content"],["type","content"],r),n.type!==r&&this.add("INVALID_CONTENT",l(t,"type"),"Expected a tableRow node.",r);const s=this.requireNonEmptyArray(n.content,l(t,"content"),r);return s==null||s.forEach((o,c)=>this.validateTableCell(o,u(t,"content",c))),(a=s==null?void 0:s.length)!=null?a:null}validateTableCell(e,t){const r="tableCell",n=this.requireRecord(e,t,r);if(!n)return;this.checkProperties(n,t,["type","content"],["type","content"],r),n.type!==r&&this.add("INVALID_CONTENT",l(t,"type"),"Expected a tableCell node.",r);const s=this.requireNonEmptyArray(n.content,l(t,"content"),r);s==null||s.forEach((a,o)=>this.validateBlock(a,u(t,"content",o)))}}function At(i){return new bt().validate(i)}const V=Object.freeze({version:1,validate:At,render:ft}),K=new Map([[V.version,V]]),It=Object.freeze([...K.keys()]),T=1;function j(i){return K.get(i)}function z(i,e={}){var s;const t=(s=e.protocolVersion)!=null?s:T,r=j(t);return r?r.validate(i):{valid:!1,issues:[{code:"UNSUPPORTED_PROTOCOL",path:"",message:`Article Content Protocol version ${t} is not supported.`}]}}const kt="Advertisement";function St(){return{adm:[],ads:[],loc:[]}}function Lt(){return{adm:"",ads:""}}function U(i){return`${i.code}:${i.path}:${i.message}`}function Nt(i){var o,c,d,f;const e=(c=(o=i.adm)==null?void 0:o.length)!=null?c:0,t=(f=(d=i.ads)==null?void 0:d.length)!=null?f:0,r=i.loc.length,n=e===0||e===r,s=t===0||t===r,a=e>0||t>0;return r===0&&!a||a&&n&&s?null:{code:"AD_CONFIG_LENGTH_MISMATCH",path:"/adConf",message:`Each non-empty adConf.adm or adConf.ads array must have the same length as adConf.loc, and at least one ad array must contain values when loc is non-empty. Received adm length ${e}, ads length ${t}, and loc length ${r}.`}}function Et(i,e){return e?[]:i.loc.map((t,r)=>{var n,s;return{index:r+1,location:t,adm:(n=i.adm)==null?void 0:n[r],ads:(s=i.ads)==null?void 0:s[r]}}).filter(t=>Number.isInteger(t.location)&&t.location>=1)}const Rt=N.extend({name:"ArticleContentRenderer",props:{document:{type:null,required:!0},protocolVersion:{type:Number,default:T},strict:{type:Boolean,default:!1},adConf:{type:Object,default:St},pubid:{type:Object,default:Lt},adTitle:{type:String,default:kt},imageBaseUrl:{type:String,default:I},resolveArticleButtonLink:{type:Function,default:void 0}},data(){return{reportedRuntimeIssues:new Set,reportedAdConfigIssue:null}},computed:{validation(){return z(this.document,{protocolVersion:this.protocolVersion})},adConfigIssue(){return Nt(this.adConf)},adSlots(){return Et(this.adConf,this.adConfigIssue)}},watch:{validation:{immediate:!0,deep:!0,handler(i){i.issues.forEach(e=>this.$emit("render-error",e))}},document:{deep:!0,handler(){this.reportedRuntimeIssues.clear()}},protocolVersion(){this.reportedRuntimeIssues.clear()},resolveArticleButtonLink(){this.reportedRuntimeIssues.clear()},imageBaseUrl(){this.reportedRuntimeIssues.clear()},adConfigIssue:{immediate:!0,handler(i){if(!i){this.reportedAdConfigIssue=null;return}const e=U(i);this.reportedAdConfigIssue!==e&&(this.reportedAdConfigIssue=e,console.error("[ArticleContentRenderer] Invalid adConf:",i),this.$emit("render-error",i))}}},methods:{reportRuntimeIssue(i){const e=U(i);this.reportedRuntimeIssues.has(e)||(this.reportedRuntimeIssues.add(e),this.$nextTick(()=>this.$emit("render-error",i)))}},render(i){const e=j(this.protocolVersion);if(!e||this.strict&&!this.validation.valid)return i("div",{class:"acp-render-error",attrs:{role:"alert","data-render-error":"true"}},"Invalid article content");const t=e.render(this.document,{createElement:i,adSlots:this.adSlots,admPublisherId:this.pubid.adm,adsPublisherId:this.pubid.ads,adTitle:this.adTitle,imageBaseUrl:this.imageBaseUrl,resolveArticleButtonLink:this.resolveArticleButtonLink,emitArticleButtonClick:r=>this.$emit("article-button-click",r),reportIssue:this.reportRuntimeIssue});return i("div",{class:"acp-document",attrs:{"data-node-type":"doc","data-protocol-version":this.protocolVersion}},t)}});function Pt(i,e,t,r,n,s,a,o){var c=typeof i=="function"?i.options:i;return{exports:i,options:c}}var Tt=Pt(Rt);const _=Tt.exports,_t=Object.freeze({fileFormat:"article-content-protocol",fileFormatVersion:1,mediaType:"application/vnd.article-content-protocol+json",id:"article-content-v1",version:1,name:"Article Content Protocol v1",status:"draft",rootNode:"doc",nodeTypes:Object.freeze(["doc","paragraph","heading","blockquote","bulletList","orderedList","listItem","codeBlock","horizontalRule","image","articleButton","table","tableRow","tableCell","text"]),markTypes:Object.freeze(["bold","italic","strike","underline","code","link"])}),vt={install(i){i.component("ArticleContentRenderer",_)}};exports.ARTICLE_CONTENT_PROTOCOL_V1=_t;exports.ArticleContentRenderer=_;exports.ArticleContentRendererPlugin=vt;exports.CURRENT_PROTOCOL_VERSION=T;exports.SUPPORTED_PROTOCOL_VERSIONS=It;exports.default=_;exports.validateArticleDocument=z;
|
|
1
|
+
"use strict";var M=Object.defineProperty,Y=Object.defineProperties;var F=Object.getOwnPropertyDescriptors;var B=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,G=Object.prototype.propertyIsEnumerable;var R=(i,r,t)=>r in i?M(i,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[r]=t,m=(i,r)=>{for(var t in r||(r={}))K.call(r,t)&&R(i,t,r[t]);if(B)for(var t of B(r))G.call(r,t)&&R(i,t,r[t]);return i},A=(i,r)=>Y(i,F(r));var w=(i,r,t)=>R(i,typeof r!="symbol"?r+"":r,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const W=require("vue"),H=new Set(["http:","https:","mailto:","tel:"]),X=new Set(["http:","https:","blob:"]),J="https://article-content-renderer.invalid/",N="https://www.doitme.link/";function Q(i,r){if(typeof i!="string")return i;const t=i.trim();if(!t.startsWith(N))return t;const n=(r.trim()||N).replace(/\/+$/u,""),s=t.slice(N.length).replace(/^\/+/,"");return`${n}/${s}`}function T(i,r){if(typeof i!="string")return null;const t=i.trim();if(!t||/[\u0000-\u001F\u007F]/u.test(t))return null;try{const e=new URL(t,J);return(r==="link"?H:X).has(e.protocol)?t:null}catch(e){return null}}function v(i,r){const t=new Set(typeof i=="string"?i.trim().split(/\s+/u).filter(Boolean):[]);return r==="_blank"&&(t.add("noopener"),t.add("noreferrer")),t.size>0?[...t].join(" "):void 0}const Z=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]);function p(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function _(i){return p(i)?i:{}}function f(i,r,t,e){var c;const n=p(t)?t:{},s=p(t)?e:t,o={},l={};for(const[u,h]of Object.entries(n))if(u==="class")o.class=h;else if(u==="style")o.style=h;else if(u.startsWith("on")&&typeof h=="function"){const y=u.slice(2).toLowerCase();o.on=A(m({},(c=o.on)!=null?c:{}),{[y]:h})}else h!==void 0&&h!==!1&&(l[u]=h);return Object.keys(l).length>0&&(o.attrs=l),i.createElement(r,o,s)}function k(i){return Array.isArray(i)?i:[]}function g(i,...r){return`${i}/${r.map(String).join("/")}`}function V(i){return i==="left"||i==="center"||i==="right"||i==="justify"}function tt(i){return i==="left"||i==="center"||i==="right"}function E(i){return i==="_blank"||i==="_self"}function b(i,r){i.reportIssue(r)}function et(i,r,t){if(!p(i)||i.type!=="text"||typeof i.text!="string"||!i.text)return null;let e=i.text;const n=k(i.marks);for(let s=0;s<n.length;s+=1){const o=n[s];if(!p(o)||typeof o.type!="string")continue;const l=g(r,"marks",s);switch(o.type){case"bold":e=f(t,"strong",{class:"acp-mark acp-mark--bold"},[e]);break;case"italic":e=f(t,"em",{class:"acp-mark acp-mark--italic"},[e]);break;case"strike":e=f(t,"s",{class:"acp-mark acp-mark--strike"},[e]);break;case"underline":e=f(t,"u",{class:"acp-mark acp-mark--underline"},[e]);break;case"code":e=f(t,"code",{class:"acp-mark acp-mark--code"},[e]);break;case"link":{const c=_(o.attrs),u=T(c.href,"link");if(!u){b(t,{code:"UNSAFE_URL",path:g(l,"attrs","href"),message:"The link URL is empty, malformed, or uses a disallowed protocol.",nodeType:"link"});break}const h=E(c.target)?c.target:"_blank";e=f(t,"a",{class:"acp-link",href:u,target:h,rel:v(void 0,h)},[e]);break}}}return e}function C(i,r,t){return k(i).map((e,n)=>et(e,g(r,n),t)).filter(e=>e!==null)}function q(i,r,t){return!p(i)||i.type!=="listItem"?null:f(t,"li",{class:"acp-list-item","data-node-type":"listItem"},P(i.content,g(r,"content"),t))}function rt(i,r,t){return!p(i)||i.type!=="tableCell"?null:f(t,"td",{class:"acp-table-cell","data-node-type":"tableCell"},P(i.content,g(r,"content"),t))}function it(i,r,t){if(!p(i)||i.type!=="tableRow")return null;const e=k(i.content).map((n,s)=>rt(n,g(r,"content",s),t)).filter(n=>n!==null);return f(t,"tr",{class:"acp-table-row","data-node-type":"tableRow"},e)}function U(i){var n;if(p(i)&&i.target!==void 0&&!E(i.target)||p(i)&&i.rel!==void 0&&typeof i.rel!="string")return null;const r=typeof i=="string"?{href:i}:p(i)&&typeof i.href=="string"?m(m({href:i.href},E(i.target)?{target:i.target}:{}),typeof i.rel=="string"?{rel:i.rel}:{}):null;if(!r)return null;const t=T(r.href,"link");if(!t)return null;const e=(n=r.target)!=null?n:"_self";return{href:t,target:e,rel:v(r.rel,e)}}function nt(i,r,t){var h;const e=_(i.attrs),n=e.style==="text"||e.style==="button",s=e.style==="link";if(typeof e.text!="string"||!e.text||!n&&!s||n&&(typeof e.id!="string"||!e.id)||s&&e.id!==void 0&&(typeof e.id!="string"||!e.id))return null;const o=Object.freeze(s?m(A(m(m({},typeof e.id=="string"?{id:e.id}:{}),typeof e.title=="string"?{title:e.title}:{}),{text:e.text,style:"link"}),typeof e.href=="string"?{href:e.href}:{}):A(m({id:e.id},typeof e.title=="string"?{title:e.title}:{}),{text:e.text,style:e.style})),l=Object.freeze({type:"articleButton",attrs:o});let c=null;if(o.style==="link")o.href!==void 0&&(c=U(o.href),c||b(t,{code:"UNSAFE_URL",path:`${r}/attrs/href`,message:"The articleButton link href is not a usable safe URL.",nodeType:"articleButton"}));else if(!t.resolveArticleButtonLink)b(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:"No resolveArticleButtonLink callback was provided for an articleButton node.",nodeType:"articleButton"});else try{const y=Object.freeze({type:"articleButton",attrs:o}),L=t.resolveArticleButtonLink(o,y);c=U(L),c||b(t,{code:typeof L=="string"||p(L)&&typeof L.href=="string"?"UNSAFE_URL":"LINK_RESOLUTION_FAILED",path:r,message:"The articleButton link resolver returned no usable safe URL.",nodeType:"articleButton"})}catch(y){b(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:`The articleButton link resolver threw an error: ${y instanceof Error?y.message:String(y)}`,nodeType:"articleButton"})}const u=(h=c==null?void 0:c.href)!=null?h:null;return f(t,"a",{class:["acp-article-button",`acp-article-button--${o.style}`,!u&&"acp-article-button--disabled"],href:u!=null?u:void 0,target:c==null?void 0:c.target,rel:c==null?void 0:c.rel,title:o.title,"data-node-type":"articleButton","data-article-button-id":o.id,"data-article-button-style":o.style,"aria-disabled":u?void 0:"true",onClick:y=>{u||y.preventDefault(),t.emitArticleButtonClick({attrs:o,node:l,href:u,event:y})}},o.text)}function $(i,r,t){if(!p(i)||typeof i.type!="string"||!Z.has(i.type))return null;const e=_(i.attrs);switch(i.type){case"paragraph":{const n=V(e.textAlign)?e.textAlign:void 0;return f(t,"p",{class:"acp-paragraph","data-node-type":"paragraph",style:n?{textAlign:n}:void 0},C(i.content,g(r,"content"),t))}case"heading":{const n=Number.isInteger(e.level)&&Number(e.level)>=1&&Number(e.level)<=6?Number(e.level):1,s=V(e.textAlign)?e.textAlign:void 0;return f(t,`h${n}`,{class:["acp-heading",`acp-heading--${n}`],"data-node-type":"heading",style:s?{textAlign:s}:void 0},C(i.content,g(r,"content"),t))}case"blockquote":return f(t,"blockquote",{class:"acp-blockquote","data-node-type":"blockquote"},P(i.content,g(r,"content"),t));case"bulletList":{const n=k(i.content).map((s,o)=>q(s,g(r,"content",o),t)).filter(s=>s!==null);return f(t,"ul",{class:"acp-list acp-list--bullet","data-node-type":"bulletList"},n)}case"orderedList":{const n=Number.isInteger(e.start)&&Number(e.start)>=1?Number(e.start):1,s=k(i.content).map((o,l)=>q(o,g(r,"content",l),t)).filter(o=>o!==null);return f(t,"ol",{class:"acp-list acp-list--ordered","data-node-type":"orderedList",start:n},s)}case"codeBlock":{const n=typeof e.language=="string"&&e.language?e.language:void 0,s=k(i.content).filter(o=>p(o)&&o.type==="text"&&typeof o.text=="string").map(o=>o.text).join("");return f(t,"pre",{class:"acp-code-block","data-node-type":"codeBlock","data-language":n},[f(t,"code",{class:n?`language-${n}`:void 0},s)])}case"horizontalRule":return f(t,"hr",{class:"acp-horizontal-rule","data-node-type":"horizontalRule"});case"image":{const n=T(Q(e.src,t.imageBaseUrl),"image");if(!n)return b(t,{code:"UNSAFE_URL",path:g(r,"attrs","src"),message:"The image URL is empty, malformed, or uses a disallowed protocol.",nodeType:"image"}),null;const s=tt(e.imageAlign)?e.imageAlign:"center",o=Number.isInteger(e.width)&&Number(e.width)>=1&&Number(e.width)<=1e4?Number(e.width):void 0,l=Number.isInteger(e.height)&&Number(e.height)>=1&&Number(e.height)<=1e4?Number(e.height):void 0;return f(t,"div",{class:["acp-image",`acp-image--${s}`],"data-node-type":"image","data-image-align":s},[f(t,"img",{class:"acp-image__element",src:n,alt:typeof e.alt=="string"?e.alt:"",title:typeof e.title=="string"?e.title:void 0,width:o,height:l,"data-image-align":s})])}case"articleButton":return nt(i,r,t);case"table":{const n=k(i.content).map((s,o)=>it(s,g(r,"content",o),t)).filter(s=>s!==null);return f(t,"div",{class:"acp-table-wrapper","data-node-type":"table"},[f(t,"table",{class:"acp-table"},[f(t,"tbody",n)])])}}return null}function P(i,r,t){return k(i).map((e,n)=>$(e,g(r,n),t)).filter(e=>e!==null)}function st(i,r){const t=k(i.content),e=new Map;r.customSlots.forEach(s=>{var l;if(!Number.isInteger(s.location)||s.location<1||s.location>t.length)return;const o=(l=e.get(s.location))!=null?l:[];o.push(s),e.set(s.location,o)});const n=[];return t.forEach((s,o)=>{var u;const l=o+1;(u=e.get(l))==null||u.forEach(h=>n.push(...h.content));const c=$(s,g("/content",o),r);c&&typeof c!="string"&&n.push(c)}),n}function ot(i,r){return!p(i)||i.type!=="doc"?[]:st(i,r)}const at=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]),lt=new Set(["left","center","right","justify"]),ct=new Set(["left","center","right"]),dt=new Set(["bold","italic","strike","underline","code"]);function I(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function a(i,r){return`${i}/${String(r).replaceAll("~","~0").replaceAll("/","~1")}`}function d(i,...r){let t=i;for(const e of r)t=a(t,e);return t}class ut{constructor(){w(this,"issues",[])}validate(r){if(!I(r))return this.add("INVALID_ROOT","","The document must be an object."),this.result();this.checkProperties(r,"",["type","content"],["type","content"]),r.type!=="doc"&&this.add("INVALID_ROOT","/type",'The root node type must be "doc".');const t=this.requireArray(r.content,"/content");return t==null||t.forEach((e,n)=>this.validateBlock(e,a("/content",n))),this.result()}result(){return{valid:this.issues.length===0,issues:this.issues}}add(r,t,e,n){this.issues.push(m({code:r,path:t,message:e},n?{nodeType:n}:{}))}checkProperties(r,t,e,n=[],s){const o=new Set(e);for(const l of Object.keys(r))o.has(l)||this.add("UNKNOWN_PROPERTY",a(t,l),`Property "${l}" is not allowed.`,s);for(const l of n)l in r||this.add("MISSING_PROPERTY",a(t,l),`Required property "${l}" is missing.`,s)}requireArray(r,t,e){return Array.isArray(r)?r:(this.add("INVALID_TYPE",t,"Expected an array.",e),null)}optionalArray(r,t,e){return r===void 0?[]:this.requireArray(r,t,e)}requireNonEmptyArray(r,t,e){const n=this.requireArray(r,t,e);return n&&n.length===0&&this.add("INVALID_CONTENT",t,`Node "${e}" must contain at least one child.`,e),n}requireRecord(r,t,e){return I(r)?r:(this.add("INVALID_TYPE",t,"Expected an object.",e),null)}optionalRecord(r,t,e){return r===void 0?{}:this.requireRecord(r,t,e)}requireString(r,t,e,n={}){return typeof r!="string"?(this.add("INVALID_TYPE",t,"Expected a string.",e),!1):!n.allowEmpty&&r.length===0?(this.add("INVALID_VALUE",t,"The string must not be empty.",e),!1):n.maxLength!==void 0&&r.length>n.maxLength?(this.add("INVALID_VALUE",t,`The string must contain at most ${n.maxLength} characters.`,e),!1):!0}optionalString(r,t,e,n={}){r!==void 0&&this.requireString(r,t,e,n)}requireInteger(r,t,e,n,s){if(!Number.isInteger(r))return this.add("INVALID_TYPE",t,"Expected an integer.",e),!1;const o=r;return n!==void 0&&o<n?(this.add("INVALID_VALUE",t,`Value must be at least ${n}.`,e),!1):s!==void 0&&o>s?(this.add("INVALID_VALUE",t,`Value must be at most ${s}.`,e),!1):!0}validateBlock(r,t){if(!I(r)){this.add("INVALID_TYPE",t,"A block node must be an object.");return}const e=r.type;if(typeof e!="string"){this.add("MISSING_PROPERTY",a(t,"type"),"A block node requires a type.");return}if(!at.has(e)){this.add("UNKNOWN_NODE",a(t,"type"),`Unknown block node "${e}".`,e);return}switch(e){case"paragraph":this.validateParagraph(r,t);break;case"heading":this.validateHeading(r,t);break;case"blockquote":this.validateBlockquote(r,t);break;case"bulletList":this.validateBulletList(r,t);break;case"orderedList":this.validateOrderedList(r,t);break;case"codeBlock":this.validateCodeBlock(r,t);break;case"horizontalRule":this.checkProperties(r,t,["type"],["type"],e);break;case"image":this.validateImage(r,t);break;case"articleButton":this.validateArticleButton(r,t);break;case"table":this.validateTable(r,t);break}}validateParagraph(r,t){const e="paragraph";this.checkProperties(r,t,["type","attrs","content"],["type"],e),this.validateTextAlignAttrs(r.attrs,a(t,"attrs"),e,!1),this.validateInlineContent(r.content,a(t,"content"),e)}validateHeading(r,t){const e="heading";this.checkProperties(r,t,["type","attrs","content"],["type","attrs"],e);const n=this.requireRecord(r.attrs,a(t,"attrs"),e);n&&(this.checkProperties(n,a(t,"attrs"),["level","textAlign"],["level"],e),this.requireInteger(n.level,d(t,"attrs","level"),e,1,6),this.validateTextAlign(n.textAlign,d(t,"attrs","textAlign"),e)),this.validateInlineContent(r.content,a(t,"content"),e)}validateTextAlignAttrs(r,t,e,n){const s=n?this.requireRecord(r,t,e):this.optionalRecord(r,t,e);s&&(this.checkProperties(s,t,["textAlign"],[],e),this.validateTextAlign(s.textAlign,a(t,"textAlign"),e))}validateTextAlign(r,t,e){r!==void 0&&(typeof r!="string"?this.add("INVALID_TYPE",t,"Text alignment must be a string.",e):lt.has(r)||this.add("INVALID_VALUE",t,`Unsupported text alignment "${r}".`,e))}validateInlineContent(r,t,e){const n=this.optionalArray(r,t,e);n==null||n.forEach((s,o)=>this.validateText(s,a(t,o),!0))}validateText(r,t,e){if(!I(r)){this.add("INVALID_TYPE",t,"A text node must be an object.","text");return}const n=e?["type","text","marks"]:["type","text"];if(this.checkProperties(r,t,n,["type","text"],"text"),r.type!=="text"&&this.add("INVALID_CONTENT",a(t,"type"),"Expected a text node.","text"),this.requireString(r.text,a(t,"text"),"text"),e&&r.marks!==void 0){const s=this.requireArray(r.marks,a(t,"marks"),"text");s==null||s.forEach((o,l)=>this.validateMark(o,d(t,"marks",l)))}}validateMark(r,t){if(!I(r)){this.add("INVALID_TYPE",t,"A mark must be an object.");return}if(typeof r.type!="string"){this.add("MISSING_PROPERTY",a(t,"type"),"A mark requires a type.");return}if(dt.has(r.type)){this.checkProperties(r,t,["type"],["type"],r.type);return}if(r.type!=="link"){this.add("UNKNOWN_MARK",a(t,"type"),`Unknown mark "${r.type}".`,r.type);return}this.checkProperties(r,t,["type","attrs"],["type","attrs"],"link");const e=this.requireRecord(r.attrs,a(t,"attrs"),"link");e&&(this.checkProperties(e,a(t,"attrs"),["href","target"],["href"],"link"),this.requireString(e.href,d(t,"attrs","href"),"link"),e.target!==void 0&&e.target!=="_blank"&&e.target!=="_self"&&this.add("INVALID_VALUE",d(t,"attrs","target"),'Link target must be "_blank" or "_self".',"link"))}validateBlockquote(r,t){const e="blockquote";this.checkProperties(r,t,["type","content"],["type","content"],e);const n=this.requireNonEmptyArray(r.content,a(t,"content"),e);n==null||n.forEach((s,o)=>this.validateBlock(s,d(t,"content",o)))}validateBulletList(r,t){const e="bulletList";this.checkProperties(r,t,["type","content"],["type","content"],e);const n=this.requireNonEmptyArray(r.content,a(t,"content"),e);n==null||n.forEach((s,o)=>this.validateListItem(s,d(t,"content",o)))}validateOrderedList(r,t){const e="orderedList";this.checkProperties(r,t,["type","attrs","content"],["type","content"],e);const n=this.optionalRecord(r.attrs,a(t,"attrs"),e);n&&(this.checkProperties(n,a(t,"attrs"),["start"],[],e),n.start!==void 0&&this.requireInteger(n.start,d(t,"attrs","start"),e,1));const s=this.requireNonEmptyArray(r.content,a(t,"content"),e);s==null||s.forEach((o,l)=>this.validateListItem(o,d(t,"content",l)))}validateListItem(r,t){const e="listItem",n=this.requireRecord(r,t,e);if(!n)return;this.checkProperties(n,t,["type","content"],["type","content"],e),n.type!==e&&this.add("INVALID_CONTENT",a(t,"type"),"Expected a listItem node.",e);const s=this.requireNonEmptyArray(n.content,a(t,"content"),e);s==null||s.forEach((o,l)=>this.validateBlock(o,d(t,"content",l)))}validateCodeBlock(r,t){const e="codeBlock";this.checkProperties(r,t,["type","attrs","content"],["type"],e);const n=this.optionalRecord(r.attrs,a(t,"attrs"),e);n&&(this.checkProperties(n,a(t,"attrs"),["language"],[],e),this.optionalString(n.language,d(t,"attrs","language"),e,{maxLength:32}));const s=this.optionalArray(r.content,a(t,"content"),e);s&&(s.length>1&&this.add("INVALID_CONTENT",a(t,"content"),"A codeBlock may contain at most one text node.",e),s.forEach((o,l)=>this.validateText(o,d(t,"content",l),!1)))}validateImage(r,t){const e="image";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const n=this.requireRecord(r.attrs,a(t,"attrs"),e);n&&(this.checkProperties(n,a(t,"attrs"),["src","alt","title","width","height","imageAlign"],["src"],e),this.requireString(n.src,d(t,"attrs","src"),e),this.optionalString(n.alt,d(t,"attrs","alt"),e,{allowEmpty:!0}),this.optionalString(n.title,d(t,"attrs","title"),e,{allowEmpty:!0}),n.width!==void 0&&this.requireInteger(n.width,d(t,"attrs","width"),e,1,1e4),n.height!==void 0&&this.requireInteger(n.height,d(t,"attrs","height"),e,1,1e4),n.imageAlign!==void 0&&(typeof n.imageAlign!="string"?this.add("INVALID_TYPE",d(t,"attrs","imageAlign"),"Image alignment must be a string.",e):ct.has(n.imageAlign)||this.add("INVALID_VALUE",d(t,"attrs","imageAlign"),`Unsupported image alignment "${n.imageAlign}".`,e)))}validateArticleButton(r,t){const e="articleButton";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const n=this.requireRecord(r.attrs,a(t,"attrs"),e);n&&(this.checkProperties(n,a(t,"attrs"),["id","title","text","style","href"],["text","style"],e),n.style==="text"||n.style==="button"?"id"in n?this.requireString(n.id,d(t,"attrs","id"),e):this.add("MISSING_PROPERTY",d(t,"attrs","id"),'Required property "id" is missing for an articleButton with text or button style.',e):this.optionalString(n.id,d(t,"attrs","id"),e),this.optionalString(n.title,d(t,"attrs","title"),e),this.requireString(n.text,d(t,"attrs","text"),e),this.optionalString(n.href,d(t,"attrs","href"),e),n.style!=="text"&&n.style!=="button"&&n.style!=="link"&&this.add("INVALID_VALUE",d(t,"attrs","style"),'Article button style must be "text", "button", or "link".',e),n.href!==void 0&&n.style!=="link"&&this.add("INVALID_VALUE",d(t,"attrs","href"),'Article button href may only be present when style is "link".',e))}validateTable(r,t){const e="table";this.checkProperties(r,t,["type","content"],["type","content"],e);const n=this.requireNonEmptyArray(r.content,a(t,"content"),e);if(!n)return;let s=null;n.forEach((o,l)=>{const c=d(t,"content",l),u=this.validateTableRow(o,c);u!==null&&(s===null?s=u:u!==s&&this.add("TABLE_COLUMN_MISMATCH",a(c,"content"),`Expected ${s} table cells but received ${u}.`,"tableRow"))})}validateTableRow(r,t){var o;const e="tableRow",n=this.requireRecord(r,t,e);if(!n)return null;this.checkProperties(n,t,["type","content"],["type","content"],e),n.type!==e&&this.add("INVALID_CONTENT",a(t,"type"),"Expected a tableRow node.",e);const s=this.requireNonEmptyArray(n.content,a(t,"content"),e);return s==null||s.forEach((l,c)=>this.validateTableCell(l,d(t,"content",c))),(o=s==null?void 0:s.length)!=null?o:null}validateTableCell(r,t){const e="tableCell",n=this.requireRecord(r,t,e);if(!n)return;this.checkProperties(n,t,["type","content"],["type","content"],e),n.type!==e&&this.add("INVALID_CONTENT",a(t,"type"),"Expected a tableCell node.",e);const s=this.requireNonEmptyArray(n.content,a(t,"content"),e);s==null||s.forEach((o,l)=>this.validateBlock(o,d(t,"content",l)))}}function ft(i){return new ut().validate(i)}const D=Object.freeze({version:1,validate:ft,render:ot}),x=new Map([[D.version,D]]),ht=Object.freeze([...x.keys()]),S=1;function j(i){return x.get(i)}function z(i,r={}){var s;const t=(s=r.protocolVersion)!=null?s:S,e=j(t);return e?e.validate(i):{valid:!1,issues:[{code:"UNSUPPORTED_PROTOCOL",path:"",message:`Article Content Protocol version ${t} is not supported.`}]}}function gt(){return[]}function pt(i){return`${i.code}:${i.path}:${i.message}`}const yt=W.extend({name:"ArticleContentRenderer",props:{document:{type:null,required:!0},protocolVersion:{type:Number,default:S},strict:{type:Boolean,default:!1},customSlots:{type:Array,default:gt},imageBaseUrl:{type:String,default:N},resolveArticleButtonLink:{type:Function,default:void 0}},data(){return{reportedRuntimeIssues:new Set}},computed:{validation(){return z(this.document,{protocolVersion:this.protocolVersion})}},watch:{validation:{immediate:!0,deep:!0,handler(i){i.issues.forEach(r=>this.$emit("render-error",r))}},document:{deep:!0,handler(){this.reportedRuntimeIssues.clear()}},protocolVersion(){this.reportedRuntimeIssues.clear()},resolveArticleButtonLink(){this.reportedRuntimeIssues.clear()},imageBaseUrl(){this.reportedRuntimeIssues.clear()}},methods:{resolveCustomSlots(){return this.customSlots.map(i=>{var e,n,s,o;const r={id:i.id,location:i.location},t=(o=(s=(n=(e=this.$scopedSlots)[i.id])==null?void 0:n.call(e,r))!=null?s:this.$slots[i.id])!=null?o:[];return A(m({},i),{content:t})})},reportRuntimeIssue(i){const r=pt(i);this.reportedRuntimeIssues.has(r)||(this.reportedRuntimeIssues.add(r),this.$nextTick(()=>this.$emit("render-error",i)))}},render(i){const r=j(this.protocolVersion);if(!r||this.strict&&!this.validation.valid)return i("div",{class:"acp-render-error",attrs:{role:"alert","data-render-error":"true"}},"Invalid article content");const t=r.render(this.document,{createElement:i,customSlots:this.resolveCustomSlots(),imageBaseUrl:this.imageBaseUrl,resolveArticleButtonLink:this.resolveArticleButtonLink,emitArticleButtonClick:e=>this.$emit("article-button-click",e),reportIssue:this.reportRuntimeIssue});return i("div",{class:"acp-document",attrs:{"data-node-type":"doc","data-protocol-version":this.protocolVersion}},t)}});function mt(i,r,t,e,n,s,o,l){var c=typeof i=="function"?i.options:i;return{exports:i,options:c}}var kt=mt(yt);const O=kt.exports,bt=Object.freeze({fileFormat:"article-content-protocol",fileFormatVersion:1,mediaType:"application/vnd.article-content-protocol+json",id:"article-content-v1",version:1,name:"Article Content Protocol v1",status:"draft",rootNode:"doc",nodeTypes:Object.freeze(["doc","paragraph","heading","blockquote","bulletList","orderedList","listItem","codeBlock","horizontalRule","image","articleButton","table","tableRow","tableCell","text"]),markTypes:Object.freeze(["bold","italic","strike","underline","code","link"])}),At={install(i){i.component("ArticleContentRenderer",O)}};exports.ARTICLE_CONTENT_PROTOCOL_V1=bt;exports.ArticleContentRenderer=O;exports.ArticleContentRendererPlugin=At;exports.CURRENT_PROTOCOL_VERSION=S;exports.SUPPORTED_PROTOCOL_VERSIONS=ht;exports.default=O;exports.validateArticleDocument=z;
|