feat: support {{block.super}}, see #38

This commit is contained in:
harttle
2021-01-24 02:57:48 +08:00
parent 0e0dc2adf0
commit a3af44dc10
5 changed files with 81 additions and 21 deletions
+28 -14
View File
@@ -1,8 +1,9 @@
import BlockMode from '../../context/block-mode'
import { ParseStream, TagToken, TopLevelToken, Template, Context, TagImplOptions, Emitter } from '../../types'
import { BlockDrop } from '../../drop/block-drop'
import { ParseStream, TagToken, TopLevelToken, Template, Context, TagImpl, Emitter } from '../../types'
export default {
parse: function (token: TagToken, remainTokens: TopLevelToken[]) {
parse (this: TagImpl, token: TagToken, remainTokens: TopLevelToken[]) {
const match = /\w+/.exec(token.args)
this.block = match ? match[0] : ''
this.tpls = [] as Template[]
@@ -14,18 +15,31 @@ export default {
})
stream.start()
},
render: function * (ctx: Context, emitter: Emitter) {
const blocks = ctx.getRegister('blocks')
const childDefined = blocks[this.block]
const r = this.liquid.renderer
const html = childDefined !== undefined
? childDefined
: yield r.renderTemplates(this.tpls, ctx)
if (ctx.getRegister('blockMode', BlockMode.OUTPUT) === BlockMode.STORE) {
blocks[this.block] = html
return
* render (this: TagImpl, ctx: Context, emitter: Emitter) {
const blockRender = this.getBlockRender(ctx)
yield this.emitHTML(ctx, emitter, blockRender)
},
getBlockRender (this: TagImpl, ctx: Context) {
const { liquid, tpls } = this
const extendedBlockRender = ctx.getRegister('blocks')[this.block]
const defaultBlockRender = function * (superBlock: BlockDrop) {
ctx.push({ block: superBlock })
const result = yield liquid.renderer.renderTemplates(tpls, ctx)
ctx.pop()
return result
}
return extendedBlockRender
? (superBlock: BlockDrop) => extendedBlockRender(new BlockDrop(() => defaultBlockRender(superBlock)))
: defaultBlockRender
},
* emitHTML (this: TagImpl, ctx: Context, emitter: Emitter, blockRender: (block: BlockDrop) => string) {
if (ctx.getRegister('blockMode', BlockMode.OUTPUT) === BlockMode.STORE) {
ctx.getRegister('blocks')[this.block] = blockRender
} else {
emitter.write(yield blockRender(new BlockDrop()))
}
emitter.write(html)
}
} as TagImplOptions
}
+9 -7
View File
@@ -20,15 +20,17 @@ export default {
: evalToken(this.file, ctx))
: file.getText()
assert(filepath, () => `illegal filename "${file.getText()}":"${filepath}"`)
// render the remaining tokens immediately
ctx.setRegister('blockMode', BlockMode.STORE)
const blocks = ctx.getRegister('blocks')
const html = yield renderer.renderTemplates(this.tpls, ctx)
if (blocks[''] === undefined) blocks[''] = html
const templates = yield liquid._parseFile(filepath, ctx.opts, ctx.sync)
ctx.push(yield hash.render(ctx))
// render remaining contents and store rendered results
ctx.setRegister('blockMode', BlockMode.STORE)
const html = yield renderer.renderTemplates(this.tpls, ctx)
const blocks = ctx.getRegister('blocks')
if (blocks[''] === undefined) blocks[''] = () => html
ctx.setRegister('blockMode', BlockMode.OUTPUT)
// render the layout file use stored blocks
ctx.push(yield hash.render(ctx))
const partial = yield renderer.renderTemplates(templates, ctx)
ctx.pop()
emitter.write(partial)
+13
View File
@@ -0,0 +1,13 @@
import { Drop } from './drop'
export class BlockDrop extends Drop {
constructor (
// the block render from layout template
private superBlockRender: () => Iterable<string> = () => ''
) {
super()
}
public super () {
return this.superBlockRender()
}
}
+1
View File
@@ -11,6 +11,7 @@ export { Context } from './context/context'
export { Template } from './template/template'
export { FilterImplOptions } from './template/filter/filter-impl-options'
export { TagImplOptions } from './template/tag/tag-impl-options'
export { TagImpl } from './template/tag/tag-impl'
export { ParseStream } from './parser/parse-stream'
export { Token } from './tokens/token'
export { TopLevelToken } from './tokens/toplevel-token'