coralite-plugin-aggregation 0.6.0 → 0.7.1
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 +76 -261
- package/lib/index.js +249 -326
- package/lib/templates/coralite-pagination.html +94 -73
- package/package.json +9 -18
- package/types/index.js +16 -49
- package/dist/blog/all/index.html +0 -75
- package/dist/blog/all/page/2.html +0 -75
- package/dist/blog/all/page/3.html +0 -75
- package/dist/blog/all/page/4.html +0 -75
- package/dist/blog/all/page/5.html +0 -75
- package/dist/blog/index.html +0 -75
- package/dist/blog/page/2.html +0 -75
- package/dist/blog/page/3.html +0 -75
- package/dist/blog/page/4.html +0 -75
- package/dist/blog/page/5.html +0 -75
- package/dist/blog/post-1.html +0 -71
- package/dist/blog/post-2.html +0 -71
- package/dist/blog/post-3.html +0 -71
- package/dist/blog/post-4.html +0 -71
- package/dist/blog/post-5.html +0 -71
- package/dist/index.html +0 -81
- package/dist/page/2.html +0 -81
- package/dist/page/3.html +0 -81
- package/dist/page/4.html +0 -81
- package/dist/products/product-1.html +0 -75
- package/dist/products/product-2.html +0 -72
- package/dist/products/product-3.html +0 -72
- package/dist/products/product-4.html +0 -72
package/lib/index.js
CHANGED
|
@@ -1,366 +1,289 @@
|
|
|
1
|
+
import { createPlugin } from 'coralite'
|
|
1
2
|
import path from 'node:path'
|
|
2
|
-
import { access } from 'node:fs/promises'
|
|
3
|
-
import { getHtmlFiles, createPlugin } from 'coralite'
|
|
4
|
-
import { pathToFileURL } from 'node:url'
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
5
|
+
* Aggregates content based on configuration
|
|
6
|
+
* @param {import('../types/index.js').AggregationOptions} options
|
|
7
|
+
* @param {Object} contextInstance
|
|
8
|
+
* @returns {Promise<any[]>}
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
10
|
+
async function aggregationMethod (options, contextInstance) {
|
|
11
|
+
const {
|
|
12
|
+
path: paths = [],
|
|
13
|
+
template,
|
|
14
|
+
pagination,
|
|
15
|
+
filter,
|
|
16
|
+
sort,
|
|
17
|
+
limit,
|
|
18
|
+
offset = 0,
|
|
19
|
+
recursive = false,
|
|
20
|
+
tokens
|
|
21
|
+
} = options
|
|
22
|
+
|
|
23
|
+
const contextValues = contextInstance.values
|
|
24
|
+
const pagesRoot = this.options.pages
|
|
25
|
+
|
|
26
|
+
// 1. Collect pages
|
|
27
|
+
let allPages = []
|
|
28
|
+
const uniquePaths = new Set()
|
|
29
|
+
|
|
30
|
+
for (const relativePath of paths) {
|
|
31
|
+
const targetPath = path.join(pagesRoot, relativePath)
|
|
32
|
+
|
|
33
|
+
// Check direct path match in listByPath (non-recursive)
|
|
34
|
+
if (!recursive) {
|
|
35
|
+
const pagesInDir = this.pages.getListByPath(targetPath)
|
|
36
|
+
if (pagesInDir) {
|
|
37
|
+
for (const page of pagesInDir) {
|
|
38
|
+
if (!uniquePaths.has(page.path.pathname)) {
|
|
39
|
+
uniquePaths.add(page.path.pathname)
|
|
40
|
+
allPages.push(page)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
// Recursive search
|
|
46
|
+
for (const page of this.pages.list) {
|
|
47
|
+
const dirname = page.path.dirname
|
|
48
|
+
// Check if dirname is targetPath or a subdirectory of targetPath
|
|
49
|
+
if (dirname === targetPath || dirname.startsWith(targetPath + path.sep)) {
|
|
50
|
+
if (!uniquePaths.has(page.path.pathname)) {
|
|
51
|
+
uniquePaths.add(page.path.pathname)
|
|
52
|
+
allPages.push(page)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
35
56
|
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2. Filter
|
|
60
|
+
if (typeof filter === 'function') {
|
|
61
|
+
allPages = allPages.filter(page => {
|
|
62
|
+
// Access values from result property
|
|
63
|
+
const values = page.result && page.result.values ? page.result.values : page.values
|
|
64
|
+
return filter(values)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Sort
|
|
69
|
+
if (typeof sort === 'function') {
|
|
70
|
+
allPages.sort((a, b) => {
|
|
71
|
+
const valA = a.result && a.result.values ? a.result.values : a.values
|
|
72
|
+
const valB = b.result && b.result.values ? b.result.values : b.values
|
|
73
|
+
return sort(valA, valB)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
36
76
|
|
|
37
|
-
|
|
38
|
-
|
|
77
|
+
// 4. Pagination
|
|
78
|
+
let startIndex = offset
|
|
79
|
+
let endIndex = allPages.length
|
|
39
80
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const dirname = path.join(context.path.pages, optionPath)
|
|
81
|
+
let currentPage = 1
|
|
82
|
+
let totalPages = 1
|
|
43
83
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
throw new Error('Aggregate path does not exist: "' + dirname + '"')
|
|
48
|
-
}
|
|
84
|
+
// Ensure renderContext is available
|
|
85
|
+
const currentRenderContext = contextInstance.renderContext
|
|
86
|
+
const buildId = currentRenderContext && currentRenderContext.buildId
|
|
49
87
|
|
|
50
|
-
|
|
88
|
+
if (limit) {
|
|
89
|
+
if (pagination) {
|
|
90
|
+
const segment = pagination.segment || 'page'
|
|
91
|
+
const urlPathname = contextValues.$urlPathname || ''
|
|
51
92
|
|
|
52
|
-
|
|
53
|
-
// Retrieve HTML pages from specified path
|
|
54
|
-
const collection = await getHtmlFiles({
|
|
55
|
-
type: 'page',
|
|
56
|
-
path: dirname
|
|
57
|
-
})
|
|
93
|
+
const escapedSegment = segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
58
94
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
95
|
+
// Try to match segment in URL: /.../segment/Number
|
|
96
|
+
const segmentRegex = new RegExp(`/${escapedSegment}/(\\d+)`)
|
|
97
|
+
const match = urlPathname.match(segmentRegex)
|
|
62
98
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
pages = pages.concat(cachePages)
|
|
99
|
+
if (match) {
|
|
100
|
+
currentPage = parseInt(match[1], 10)
|
|
66
101
|
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let result = []
|
|
70
|
-
let startIndex = 0
|
|
71
|
-
let endIndex = pages.length
|
|
72
|
-
let paginationOffset = context.values.paginationOffset
|
|
73
102
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
103
|
+
startIndex = offset + (currentPage - 1) * limit
|
|
104
|
+
endIndex = startIndex + limit
|
|
105
|
+
|
|
106
|
+
totalPages = Math.ceil(allPages.length / limit)
|
|
107
|
+
|
|
108
|
+
// Automatically generate subsequent pagination pages if we are on the "root" page
|
|
109
|
+
// e.g., if we are on /blog/index.html (page 1), queue up /blog/page/2, /blog/page/3...
|
|
110
|
+
if (!match && currentPage === 1 && totalPages > 1 && buildId) {
|
|
111
|
+
const currentDocument = contextInstance.document
|
|
112
|
+
const currentPathname = currentDocument.path.pathname
|
|
113
|
+
const currentFilename = currentDocument.path.filename
|
|
114
|
+
const currentDirname = currentDocument.path.dirname
|
|
115
|
+
|
|
116
|
+
// Determine the output path structure based on rules
|
|
117
|
+
let targetDir = currentDirname
|
|
118
|
+
let urlPrefixBase = ''
|
|
119
|
+
|
|
120
|
+
// Rules:
|
|
121
|
+
// /index.html -> /page/1.html (relative to currentDirname)
|
|
122
|
+
// /blog.html -> /blog/page/1.html (creates subdirectory)
|
|
123
|
+
// /blog/index.html -> /blog/page/1.html (relative to currentDirname)
|
|
124
|
+
// /blog/today.html -> /blog/today/page/1.html (creates subdirectory)
|
|
125
|
+
|
|
126
|
+
if (currentFilename === 'index.html') {
|
|
127
|
+
// Standard case: keep in same directory
|
|
128
|
+
targetDir = currentDirname
|
|
129
|
+
// Prefix for URL generation in child
|
|
130
|
+
urlPrefixBase = path.dirname(urlPathname) // e.g. /blog/
|
|
131
|
+
} else {
|
|
132
|
+
// Named file: create subdirectory with same name (minus extension)
|
|
133
|
+
const basename = path.basename(currentFilename, path.extname(currentFilename))
|
|
134
|
+
targetDir = path.join(currentDirname, basename)
|
|
83
135
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
for (let i = 0; i < pages.length; i++) {
|
|
88
|
-
const page = pages[i]
|
|
89
|
-
const metadata = page.result.values
|
|
90
|
-
let keepItem = false
|
|
91
|
-
|
|
92
|
-
// process metadata and populate token values for rendering
|
|
93
|
-
for (const key in metadata) {
|
|
94
|
-
if (Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
95
|
-
const data = metadata[key]
|
|
96
|
-
|
|
97
|
-
if (Array.isArray(data)) {
|
|
98
|
-
for (let i = 0; i < data.length; i++) {
|
|
99
|
-
|
|
100
|
-
if (!keepItem) {
|
|
101
|
-
keepItem = options.filter({ name: key, content: data[i] })
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
// handle single metadata item
|
|
106
|
-
if (!keepItem) {
|
|
107
|
-
keepItem = options.filter({
|
|
108
|
-
name: key,
|
|
109
|
-
content: data
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
136
|
+
// e.g. /blog.html -> /blog/
|
|
137
|
+
urlPrefixBase = urlPathname.replace(path.extname(currentFilename), '')
|
|
114
138
|
}
|
|
115
139
|
|
|
116
|
-
|
|
117
|
-
|
|
140
|
+
// Ensure trailing slash for URL prefix
|
|
141
|
+
if (!urlPrefixBase.endsWith('/')) urlPrefixBase += '/'
|
|
142
|
+
// path.dirname returns / for /index.html, but /blog for /blog/index.html.
|
|
143
|
+
// If /blog/index.html, urlPathname is /blog/index.html. dirname is /blog.
|
|
144
|
+
|
|
145
|
+
if (currentFilename === 'index.html') {
|
|
146
|
+
// Correct logic for index.html url prefix
|
|
147
|
+
// If /index.html, urlPathname /index.html. dirname /. prefix /.
|
|
148
|
+
// If /blog/index.html, urlPathname /blog/index.html. dirname /blog. prefix /blog/.
|
|
149
|
+
urlPrefixBase = path.dirname(urlPathname)
|
|
150
|
+
if (!urlPrefixBase.endsWith('/')) urlPrefixBase += '/'
|
|
118
151
|
}
|
|
119
|
-
}
|
|
120
152
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
153
|
+
// Retrieve the original item to get content
|
|
154
|
+
const currentItem = this.pages.getItem(currentDocument.path.pathname)
|
|
155
|
+
|
|
156
|
+
for (let i = 2; i <= totalPages; i++) {
|
|
157
|
+
const newPathname = path.join(targetDir, segment, `${i}.html`)
|
|
158
|
+
|
|
159
|
+
const virtualItem = {
|
|
160
|
+
content: currentItem ? currentItem.content : '', // Use original content
|
|
161
|
+
path: {
|
|
162
|
+
pathname: newPathname,
|
|
163
|
+
dirname: path.dirname(newPathname),
|
|
164
|
+
filename: path.basename(newPathname)
|
|
165
|
+
},
|
|
166
|
+
values: {
|
|
167
|
+
// Pass metadata to help resolve paths in children
|
|
168
|
+
meta_pagination_base_url: urlPathname,
|
|
169
|
+
// Calculate prefix once and pass it down
|
|
170
|
+
meta_pagination_url_prefix: urlPrefixBase
|
|
171
|
+
},
|
|
172
|
+
type: 'page'
|
|
173
|
+
}
|
|
133
174
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
} else {
|
|
137
|
-
startIndex = offset
|
|
175
|
+
// Add to queue
|
|
176
|
+
await this.addRenderQueue(virtualItem, buildId)
|
|
138
177
|
}
|
|
139
178
|
}
|
|
179
|
+
} else {
|
|
180
|
+
// Simple limit/offset without pagination logic
|
|
181
|
+
endIndex = Math.min(startIndex + limit, allPages.length)
|
|
140
182
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const paginatedPages = allPages.slice(startIndex, endIndex)
|
|
186
|
+
|
|
187
|
+
// 5. Render Items
|
|
188
|
+
const resultNodes = []
|
|
189
|
+
|
|
190
|
+
for (const page of paginatedPages) {
|
|
191
|
+
const pageValues = page.result && page.result.values ? page.result.values : page.values
|
|
192
|
+
let itemValues = { ...pageValues }
|
|
193
|
+
|
|
194
|
+
// Apply token transformations
|
|
195
|
+
if (tokens && typeof tokens === 'object') {
|
|
196
|
+
for (const key in tokens) {
|
|
197
|
+
if (Object.prototype.hasOwnProperty.call(tokens, key)) {
|
|
198
|
+
const transform = tokens[key]
|
|
199
|
+
if (typeof transform === 'string') {
|
|
200
|
+
itemValues[key] = pageValues[transform]
|
|
201
|
+
} else if (typeof transform === 'function') {
|
|
202
|
+
itemValues[key] = transform(pageValues)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
155
205
|
}
|
|
156
206
|
}
|
|
157
207
|
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
// Always exclude index.html from pagination
|
|
161
|
-
if (p.path.filename === 'index.html') return false
|
|
162
|
-
|
|
163
|
-
// Exclude current page if it matches
|
|
164
|
-
if (p.path.filename === context.document.path.filename) return false
|
|
165
|
-
|
|
166
|
-
return true
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
// Update endIndex after filtering
|
|
170
|
-
endIndex = Math.min(endIndex, pages.length)
|
|
171
|
-
|
|
172
|
-
// Render content
|
|
173
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
174
|
-
let page = pages[i]
|
|
175
|
-
|
|
176
|
-
// render component with current values and add to results
|
|
208
|
+
// Render the item template
|
|
209
|
+
if (template) {
|
|
177
210
|
const component = await this.createComponent({
|
|
178
|
-
id:
|
|
179
|
-
values:
|
|
180
|
-
document:
|
|
181
|
-
|
|
182
|
-
index: i
|
|
211
|
+
id: template,
|
|
212
|
+
values: itemValues,
|
|
213
|
+
document: contextInstance.document,
|
|
214
|
+
renderContext: currentRenderContext
|
|
183
215
|
})
|
|
184
216
|
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
result = result.concat(component.children)
|
|
217
|
+
if (component && component.children) {
|
|
218
|
+
resultNodes.push(...component.children)
|
|
188
219
|
}
|
|
189
220
|
}
|
|
221
|
+
}
|
|
190
222
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
// Calculate pagination length based on the filtered pages array
|
|
197
|
-
// Each page shows 'limit' items, so total pages = ceil(filteredPagesCount / limit)
|
|
198
|
-
const filteredPagesCount = pages.length
|
|
199
|
-
const paginationLength = Math.ceil(filteredPagesCount / limit)
|
|
200
|
-
|
|
201
|
-
let processed = context.values.paginationProcessed
|
|
202
|
-
|
|
203
|
-
if (!processed && paginationLength > 1) {
|
|
204
|
-
const documentPath = context.document.path
|
|
205
|
-
|
|
206
|
-
// remove file extension
|
|
207
|
-
let name = context.document.path.filename.replace(path.extname(context.document.path.filename), '')
|
|
208
|
-
|
|
209
|
-
if (name === 'index') {
|
|
210
|
-
name = ''
|
|
211
|
-
}
|
|
223
|
+
// 6. Render Pagination Controls
|
|
224
|
+
if (pagination) {
|
|
225
|
+
const segment = pagination.segment || 'page'
|
|
226
|
+
const escapedSegment = segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
212
227
|
|
|
213
|
-
|
|
214
|
-
let baseDirname = documentPath.dirname
|
|
215
|
-
if (name) {
|
|
216
|
-
baseDirname = path.join(baseDirname, name)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const paginationDirname = path.join(baseDirname, paginationSegment.toString())
|
|
220
|
-
|
|
221
|
-
// Index page path - always the base index.html
|
|
222
|
-
const indexPathname = context.values.paginationIndexPathname || documentPath.pathname
|
|
223
|
-
// For URL calculation, we need to find the index page in the same directory structure
|
|
224
|
-
// If we're on /blog/page/2.html, the index is at /blog/index.html
|
|
225
|
-
let indexURLPathname = context.values.paginationIndexURLPathname
|
|
226
|
-
let indexURLDirname = context.values.paginationIndexURLDirname
|
|
227
|
-
|
|
228
|
-
if (!indexURLDirname || !indexURLPathname) {
|
|
229
|
-
if (name) {
|
|
230
|
-
// Non-index page: index is in parent directory
|
|
231
|
-
const parentDir = path.dirname(documentPath.dirname)
|
|
232
|
-
const indexFile = path.join(parentDir, context.document.path.filename)
|
|
233
|
-
indexURLPathname = pathToFileURL(path.join('/', path.relative(this.options.path.pages, indexFile))).pathname
|
|
234
|
-
indexURLDirname = pathToFileURL(path.dirname(indexURLPathname)).pathname
|
|
235
|
-
} else {
|
|
236
|
-
// Index page
|
|
237
|
-
indexURLPathname = pathToFileURL(path.join('/', path.relative(this.options.path.pages, indexPathname))).pathname
|
|
238
|
-
indexURLDirname = pathToFileURL(path.dirname(indexURLPathname)).pathname
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const indexPage = this.pages.getItem(documentPath.pathname)
|
|
243
|
-
const maxVisiblePages = (pagination.maxVisible || paginationLength).toString()
|
|
244
|
-
|
|
245
|
-
// Generate pagination pages (page 2, 3, 4, etc.)
|
|
246
|
-
if (context.values.paginationFileDirname == null) {
|
|
247
|
-
for (let i = 1; i < paginationLength; i++) {
|
|
248
|
-
const currentPageIndex = i + 1
|
|
249
|
-
const filename = currentPageIndex + '.html'
|
|
250
|
-
const pathname = path.join(paginationDirname, filename)
|
|
251
|
-
const contextId = pathname + context.id.substring(documentPath.pathname.length)
|
|
252
|
-
|
|
253
|
-
// Calculate offset for this page
|
|
254
|
-
const pageOffset = i * limit
|
|
255
|
-
|
|
256
|
-
// URL for this pagination page
|
|
257
|
-
const urlPathname = pathToFileURL(path.join('/', path.relative(this.options.path.pages, pathname))).pathname
|
|
258
|
-
const urlDirname = pathToFileURL(path.dirname(urlPathname)).pathname
|
|
259
|
-
|
|
260
|
-
// Store context values for pagination page
|
|
261
|
-
// For pagination pages, use nested URL structure
|
|
262
|
-
const nestedURLPathname = pathToFileURL(path.join('/', path.relative(this.options.path.pages, pathname))).pathname
|
|
263
|
-
// For pagination pages, the URL dirname should be the full path without .html
|
|
264
|
-
// e.g., /blog/page/2.html -> /blog/page/2
|
|
265
|
-
const nestedURLDirname = nestedURLPathname.replace(/\.html$/, '')
|
|
266
|
-
|
|
267
|
-
this.values[contextId] = {
|
|
268
|
-
...context.values,
|
|
269
|
-
paginationIndexPathname: context.values.paginationIndexPathname,
|
|
270
|
-
paginationIndexURLPathname: context.values.paginationIndexURLPathname,
|
|
271
|
-
paginationIndexURLDirname: context.values.paginationIndexURLDirname,
|
|
272
|
-
paginationSegment: paginationSegment,
|
|
273
|
-
paginationMaxVisible: maxVisiblePages,
|
|
274
|
-
paginationProcessed: 'true',
|
|
275
|
-
paginationOffset: pageOffset.toString(),
|
|
276
|
-
paginationFilePathname: pathname,
|
|
277
|
-
paginationFileDirname: paginationDirname,
|
|
278
|
-
paginationURLPathname: nestedURLPathname,
|
|
279
|
-
paginationURLDirname: nestedURLDirname,
|
|
280
|
-
paginationLength: paginationLength.toString(),
|
|
281
|
-
paginationCurrent: currentPageIndex.toString(),
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Add pagination page to render queue
|
|
285
|
-
await this.addRenderQueue({
|
|
286
|
-
values: {
|
|
287
|
-
paginationIndexPathname: indexPathname,
|
|
288
|
-
paginationIndexURLPathname: indexURLPathname,
|
|
289
|
-
paginationIndexURLDirname: indexURLDirname,
|
|
290
|
-
paginationFileDirname: documentPath.dirname,
|
|
291
|
-
},
|
|
292
|
-
path: {
|
|
293
|
-
dirname: paginationDirname,
|
|
294
|
-
pathname,
|
|
295
|
-
filename
|
|
296
|
-
},
|
|
297
|
-
content: indexPage.content
|
|
298
|
-
})
|
|
299
|
-
}
|
|
300
|
-
}
|
|
228
|
+
const paginationTemplateId = pagination.template || 'coralite-pagination'
|
|
301
229
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (name) {
|
|
308
|
-
// Non-index page: use nested structure
|
|
309
|
-
// e.g., /blog/page/2 for page 2
|
|
310
|
-
currentPaginationURLPathname = indexURLPathname
|
|
311
|
-
// Calculate the full nested path
|
|
312
|
-
// For page 2: /blog/page/2
|
|
313
|
-
const relativePath = path.relative(this.options.path.pages, documentPath.dirname)
|
|
314
|
-
currentPaginationURLDirname = pathToFileURL(path.join('/', relativePath, name)).pathname
|
|
315
|
-
} else {
|
|
316
|
-
// Index page: use flat structure
|
|
317
|
-
currentPaginationURLPathname = indexURLPathname
|
|
318
|
-
currentPaginationURLDirname = indexURLDirname
|
|
319
|
-
}
|
|
320
|
-
context.values = {
|
|
321
|
-
...context.values,
|
|
322
|
-
paginationIndexPathname: indexPathname,
|
|
323
|
-
paginationIndexURLPathname: indexURLPathname,
|
|
324
|
-
paginationIndexURLDirname: indexURLDirname,
|
|
325
|
-
paginationSegment: paginationSegment,
|
|
326
|
-
paginationMaxVisible: maxVisiblePages,
|
|
327
|
-
paginationProcessed: 'true',
|
|
328
|
-
paginationOffset: limit.toString(),
|
|
329
|
-
paginationFilePathname: indexPathname,
|
|
330
|
-
paginationFileDirname: baseDirname,
|
|
331
|
-
paginationURLPathname: currentPaginationURLPathname,
|
|
332
|
-
paginationURLDirname: currentPaginationURLDirname,
|
|
333
|
-
paginationLength: paginationLength.toString(),
|
|
334
|
-
paginationCurrent: '1'
|
|
335
|
-
}
|
|
336
|
-
}
|
|
230
|
+
// Construct baseUrl and urlPrefix for template
|
|
231
|
+
const urlPathname = contextValues.$urlPathname
|
|
232
|
+
let baseUrl = urlPathname
|
|
233
|
+
let urlPrefix = ''
|
|
337
234
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
235
|
+
if (contextValues.meta_pagination_base_url) {
|
|
236
|
+
baseUrl = contextValues.meta_pagination_base_url
|
|
237
|
+
}
|
|
341
238
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
values,
|
|
353
|
-
document: context.document,
|
|
354
|
-
contextId: contextId + paginationTemplateId
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
if (typeof component === 'object') {
|
|
358
|
-
result = result.concat(component.children)
|
|
359
|
-
}
|
|
239
|
+
if (contextValues.meta_pagination_url_prefix) {
|
|
240
|
+
urlPrefix = contextValues.meta_pagination_url_prefix
|
|
241
|
+
} else {
|
|
242
|
+
// Page 1 logic calculation if not passed
|
|
243
|
+
if (baseUrl.endsWith('/index.html') || baseUrl.endsWith('/')) {
|
|
244
|
+
urlPrefix = path.dirname(baseUrl)
|
|
245
|
+
} else {
|
|
246
|
+
// Named file
|
|
247
|
+
const basename = path.basename(baseUrl, '.html')
|
|
248
|
+
urlPrefix = path.join(path.dirname(baseUrl), basename)
|
|
360
249
|
}
|
|
361
250
|
}
|
|
362
251
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
252
|
+
// Normalize urlPrefix to ensure trailing slash
|
|
253
|
+
if (!urlPrefix.endsWith('/')) urlPrefix += '/'
|
|
254
|
+
|
|
255
|
+
const paginationValues = {
|
|
256
|
+
'current-page': String(currentPage),
|
|
257
|
+
'total-pages': String(totalPages),
|
|
258
|
+
'base-url': baseUrl,
|
|
259
|
+
'url-prefix': urlPrefix,
|
|
260
|
+
segment: pagination.segment || 'page',
|
|
261
|
+
'max-visible': String(pagination.maxVisible || 5),
|
|
262
|
+
'aria-label': pagination.ariaLabel || 'Pagination',
|
|
263
|
+
ellipsis: pagination.ellipsis || '...'
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const component = await this.createComponent({
|
|
267
|
+
id: paginationTemplateId,
|
|
268
|
+
values: paginationValues,
|
|
269
|
+
document: contextInstance.document,
|
|
270
|
+
renderContext: currentRenderContext
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
if (component && component.children) {
|
|
274
|
+
resultNodes.push(...component.children)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return resultNodes
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const aggregation = createPlugin({
|
|
282
|
+
name: 'aggregation',
|
|
283
|
+
method: aggregationMethod,
|
|
284
|
+
templates: [
|
|
285
|
+
path.join(import.meta.dirname, 'templates/coralite-pagination.html')
|
|
286
|
+
]
|
|
366
287
|
})
|
|
288
|
+
|
|
289
|
+
export default aggregation
|