├── .husky └── pre-commit ├── .prettierrc ├── src ├── .vitepress │ ├── components │ │ ├── playground │ │ │ ├── lib │ │ │ │ ├── codemirror-languages │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── readme.md │ │ │ │ │ ├── js-object.js │ │ │ │ │ ├── handlebars.js │ │ │ │ │ └── js-object.grammar │ │ │ │ ├── prettify.js │ │ │ │ ├── utils.js │ │ │ │ ├── in-browser-example-executor │ │ │ │ │ ├── worker.js │ │ │ │ │ ├── execute-one-after-another.js │ │ │ │ │ ├── limit-waiting-time.js │ │ │ │ │ ├── lazy-get-handlebars.js │ │ │ │ │ ├── client.js │ │ │ │ │ ├── worker-with-termination-timeout.js │ │ │ │ │ ├── execute-one-after-another.test.js │ │ │ │ │ └── limit-waiting-time.test.js │ │ │ │ ├── share-utils.js │ │ │ │ ├── execute-example.js │ │ │ │ ├── execute-example.test.js │ │ │ │ └── example-parser.js │ │ │ ├── WorkspaceError.vue │ │ │ ├── HandlebarsVersionChooser.vue │ │ │ ├── ExportYamlModal.vue │ │ │ ├── WorkspaceElement.vue │ │ │ ├── HighlightedCode.vue │ │ │ ├── CodeEditor.vue │ │ │ ├── WorkspaceElementDecorator.vue │ │ │ ├── Modal.vue │ │ │ └── ShareUrlModal.vue │ │ ├── Flex.vue │ │ ├── PlaygroundLayout.vue │ │ ├── TryoutIcon.vue │ │ └── DownloadHandlebars.vue │ ├── lib │ │ ├── handlebars-versions.js │ │ └── handlebars-cli-help.js │ └── theme │ │ └── index.js ├── snippets │ ├── precompilation │ │ ├── example.handlebars │ │ ├── build.sh │ │ ├── precompile-in-nodejs.js │ │ ├── index.html │ │ ├── precompile-in-nodejs.output.js │ │ └── example.precompiled.js │ └── compiler-and-runtime │ │ ├── simple-console-out.html │ │ └── index.html ├── public │ ├── favicon.png │ ├── handlebars-logo.png │ └── manifest.json ├── examples.data.js ├── examples │ ├── partials │ │ ├── failover.md │ │ ├── basic.md │ │ ├── partial-block.md │ │ ├── variable.md │ │ ├── parameters.md │ │ ├── other-context.md │ │ ├── dynamic.md │ │ ├── inline.md │ │ ├── partial-block-parameters.md │ │ ├── register.md │ │ ├── inline-blocks.md │ │ ├── parent-context.md │ │ └── partials.md │ ├── hook-helper-missing-default-no-param.md │ ├── simple-expressions.md │ ├── hook-helper-missing-default-param.md │ ├── html-escaping.md │ ├── builtin-helper-log.md │ ├── path-expressions-dot.md │ ├── path-expressions-slash.md │ ├── builtin-helper-eachelse-block.md │ ├── builtin-helper-with-block.md │ ├── hook-block-helper-missing-default.md │ ├── comments.md │ ├── builtin-helper-unless-block.md │ ├── builtin-helper-log-multiple-params.md │ ├── raw-blocks.md │ ├── builtin-helper-if-block.md │ ├── path-expressions-dot-dot.md │ ├── builtin-helper-with-else.md │ ├── builtin-helper-lookup.md │ ├── builtin-helper-each-block.md │ ├── helper-simple.md │ ├── helper-data-name-conflict.md │ ├── builtin-helper-ifelse-block.md │ ├── path-expressions-dot-dot-if.md │ ├── builtin-helper-if-subexpression.md │ ├── helper-safestring.md │ ├── each-with.md │ ├── hook-block-helper-missing.md │ ├── helper-this-context.md │ ├── helper-multiple-parameters.md │ ├── literal-segments.md │ ├── builtin-helper-with-block-param.md │ ├── helper-lookup-property.md │ ├── hook-helper-missing.md │ ├── helper-literals.md │ ├── helper-block.md │ ├── helper-dynamic-parameters.md │ ├── builtin-helper-lookup-dynamic-property.md │ ├── builtin-helper-log-loglevel.md │ ├── all-features.md │ ├── helper-hash-arguments.md │ └── _example-base-data.yaml ├── ko │ ├── examples │ │ ├── partials │ │ │ ├── failover.md │ │ │ ├── basic.md │ │ │ ├── partial-block.md │ │ │ ├── variable.md │ │ │ ├── parameters.md │ │ │ ├── other-context.md │ │ │ ├── dynamic.md │ │ │ ├── inline.md │ │ │ ├── partial-block-parameters.md │ │ │ ├── inline-blocks.md │ │ │ ├── parent-context.md │ │ │ ├── register.md │ │ │ └── partials.md │ │ ├── hook-helper-missing-default-no-param.md │ │ ├── simple-expressions.md │ │ ├── hook-helper-missing-default-param.md │ │ ├── html-escaping.md │ │ ├── builtin-helper-log.md │ │ ├── path-expressions-dot.md │ │ ├── path-expressions-slash.md │ │ ├── builtin-helper-eachelse-block.md │ │ ├── builtin-helper-with-block.md │ │ ├── hook-block-helper-missing-default.md │ │ ├── comments.md │ │ ├── builtin-helper-unless-block.md │ │ ├── builtin-helper-log-multiple-params.md │ │ ├── raw-blocks.md │ │ ├── builtin-helper-if-block.md │ │ ├── path-expressions-dot-dot.md │ │ ├── builtin-helper-with-else.md │ │ ├── builtin-helper-lookup.md │ │ ├── builtin-helper-each-block.md │ │ ├── helper-simple.md │ │ ├── helper-data-name-conflict.md │ │ ├── builtin-helper-ifelse-block.md │ │ ├── path-expressions-dot-dot-if.md │ │ ├── builtin-helper-if-subexpression.md │ │ ├── helper-safestring.md │ │ ├── each-with.md │ │ ├── helper-this-context.md │ │ ├── literal-segments.md │ │ ├── hook-block-helper-missing.md │ │ ├── helper-multiple-parameters.md │ │ ├── builtin-helper-with-block-param.md │ │ ├── helper-lookup-property.md │ │ ├── hook-helper-missing.md │ │ ├── helper-literals.md │ │ ├── helper-block.md │ │ ├── helper-dynamic-parameters.md │ │ ├── builtin-helper-lookup-dynamic-property.md │ │ ├── builtin-helper-log-loglevel.md │ │ ├── all-features.md │ │ ├── helper-hash-arguments.md │ │ └── _example-base-data.yaml │ ├── api-reference │ │ ├── index.md │ │ ├── helpers.md │ │ ├── data-variables.md │ │ ├── compilation.md │ │ ├── utilities.md │ │ └── runtime.md │ ├── playground.md │ ├── index.md │ ├── guide │ │ ├── installation │ │ │ ├── when-to-use-handlebars.md │ │ │ ├── integrations.md │ │ │ └── precompilation.md │ │ ├── hooks.md │ │ └── partials.md │ └── contributing │ │ ├── index.md │ │ └── interactive-examples.md ├── zh │ ├── examples │ │ ├── partials │ │ │ ├── failover.md │ │ │ ├── basic.md │ │ │ ├── partial-block.md │ │ │ ├── variable.md │ │ │ ├── parameters.md │ │ │ ├── other-context.md │ │ │ ├── dynamic.md │ │ │ ├── inline.md │ │ │ ├── partial-block-parameters.md │ │ │ ├── inline-blocks.md │ │ │ ├── parent-context.md │ │ │ ├── register.md │ │ │ └── partials.md │ │ ├── hook-helper-missing-default-no-param.md │ │ ├── simple-expressions.md │ │ ├── hook-helper-missing-default-param.md │ │ ├── html-escaping.md │ │ ├── builtin-helper-log.md │ │ ├── path-expressions-dot.md │ │ ├── path-expressions-slash.md │ │ ├── builtin-helper-eachelse-block.md │ │ ├── builtin-helper-with-block.md │ │ ├── hook-block-helper-missing-default.md │ │ ├── comments.md │ │ ├── builtin-helper-unless-block.md │ │ ├── builtin-helper-log-multiple-params.md │ │ ├── raw-blocks.md │ │ ├── builtin-helper-if-block.md │ │ ├── path-expressions-dot-dot.md │ │ ├── builtin-helper-with-else.md │ │ ├── builtin-helper-lookup.md │ │ ├── builtin-helper-each-block.md │ │ ├── helper-simple.md │ │ ├── helper-data-name-conflict.md │ │ ├── builtin-helper-ifelse-block.md │ │ ├── path-expressions-dot-dot-if.md │ │ ├── builtin-helper-if-subexpression.md │ │ ├── helper-safestring.md │ │ ├── each-with.md │ │ ├── helper-this-context.md │ │ ├── literal-segments.md │ │ ├── hook-block-helper-missing.md │ │ ├── helper-multiple-parameters.md │ │ ├── builtin-helper-with-block-param.md │ │ ├── helper-lookup-property.md │ │ ├── hook-helper-missing.md │ │ ├── helper-literals.md │ │ ├── helper-block.md │ │ ├── helper-dynamic-parameters.md │ │ ├── builtin-helper-lookup-dynamic-property.md │ │ ├── builtin-helper-log-loglevel.md │ │ ├── all-features.md │ │ ├── helper-hash-arguments.md │ │ └── _example-base-data.yaml │ ├── api-reference │ │ ├── index.md │ │ ├── helpers.md │ │ ├── data-variables.md │ │ ├── compilation.md │ │ ├── utilities.md │ │ ├── runtime.md │ │ └── runtime-options.md │ ├── playground.md │ ├── index.md │ ├── guide │ │ ├── installation │ │ │ ├── when-to-use-handlebars.md │ │ │ ├── integrations.md │ │ │ └── precompilation.md │ │ ├── hooks.md │ │ └── partials.md │ └── contributing │ │ ├── index.md │ │ └── interactive-examples.md ├── handlebars.data.js ├── playground.md ├── api-reference │ ├── helpers.md │ ├── index.md │ ├── data-variables.md │ ├── compilation.md │ └── utilities.md ├── index.md └── guide │ ├── installation │ ├── when-to-use-handlebars.md │ └── integrations.md │ └── hooks.md ├── .gitignore ├── .prettierignore ├── .github └── workflows │ ├── ci.yml │ └── build-and-deploy.yml ├── README.md ├── LICENSE └── package.json /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint-staged 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "proseWrap": "always" 4 | } 5 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/codemirror-languages/.gitignore: -------------------------------------------------------------------------------- 1 | *.terms.js -------------------------------------------------------------------------------- /src/snippets/precompilation/example.handlebars: -------------------------------------------------------------------------------- 1 | Handlebars {{doesWhat}} precompiled! -------------------------------------------------------------------------------- /src/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handlebars-lang/docs/HEAD/src/public/favicon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/.vitepress/.temp 2 | /src/.vitepress/cache 3 | /src/.vitepress/dist 4 | /node_modules 5 | /target -------------------------------------------------------------------------------- /src/public/handlebars-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handlebars-lang/docs/HEAD/src/public/handlebars-logo.png -------------------------------------------------------------------------------- /src/examples.data.js: -------------------------------------------------------------------------------- 1 | import { createContentLoader } from "vitepress"; 2 | 3 | export default createContentLoader("**/examples/**/*.md"); 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | !.vitepress 2 | /src/snippets/precompilation/example.precompiled.js 3 | /src/snippets/precompilation/precompile-in-nodejs.output.js 4 | -------------------------------------------------------------------------------- /src/snippets/precompilation/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$( dirname "$(readlink -f "$0" )" )" || exit 1 4 | 5 | npx handlebars example.handlebars -f example.precompiled.js -------------------------------------------------------------------------------- /src/examples/partials/failover.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#> myPartial }} 6 | Failover content 7 | {{/myPartial}} 8 | --- 9 | -------------------------------------------------------------------------------- /src/ko/examples/partials/failover.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#> myPartial }} 6 | Failover content 7 | {{/myPartial}} 8 | --- 9 | -------------------------------------------------------------------------------- /src/zh/examples/partials/failover.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#> myPartial }} 6 | Failover content 7 | {{/myPartial}} 8 | --- 9 | -------------------------------------------------------------------------------- /src/examples/hook-helper-missing-default-no-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | some_{{foo}}mustache 6 | some_{{#foo}}abc{{/foo}}block 7 | input: {} 8 | --- 9 | -------------------------------------------------------------------------------- /src/examples/simple-expressions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 |

{{firstname}} {{lastname}}

6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/hook-helper-missing-default-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{foo bar}} 6 | {{#foo bar}}abc{{/foo}} 7 | input: {} 8 | errorExpected: true 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/hook-helper-missing-default-no-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | some_{{foo}}mustache 6 | some_{{#foo}}abc{{/foo}}block 7 | input: {} 8 | --- 9 | -------------------------------------------------------------------------------- /src/zh/examples/hook-helper-missing-default-no-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | some_{{foo}}mustache 6 | some_{{#foo}}abc{{/foo}}block 7 | input: {} 8 | --- 9 | -------------------------------------------------------------------------------- /src/examples/html-escaping.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | raw: {{{specialChars}}} 6 | html-escaped: {{specialChars}} 7 | input: 8 | specialChars: '& < > " '' ` =' 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/simple-expressions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 |

{{firstname}} {{lastname}}

6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/simple-expressions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 |

{{firstname}} {{lastname}}

6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-log.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |+ 5 | {{log 'this is a simple log output'}} 6 | input: 7 | --- 8 | 9 | Press F12 and open the dev-console to see the log output. 10 | -------------------------------------------------------------------------------- /src/snippets/precompilation/precompile-in-nodejs.js: -------------------------------------------------------------------------------- 1 | let template = "Handlebars {{doesWhat}} precompiled!"; 2 | let Handlebars = require("handlebars"); 3 | let compiled = Handlebars.precompile(template); 4 | console.log(compiled); 5 | -------------------------------------------------------------------------------- /src/ko/examples/hook-helper-missing-default-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{foo bar}} 6 | {{#foo bar}}abc{{/foo}} 7 | input: {} 8 | errorExpected: true 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/hook-helper-missing-default-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{foo bar}} 6 | {{#foo bar}}abc{{/foo}} 7 | input: {} 8 | errorExpected: true 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/partials/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: "{{> myPartial }}" 5 | preparationScript: | 6 | Handlebars.registerPartial('myPartial', '{{prefix}}'); 7 | input: 8 | prefix: Hello 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/partials/partial-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#> layout }} 6 | My Content 7 | {{/layout}} 8 | partials: 9 | layout: Site Content {{> @partial-block }} 10 | --- 11 | -------------------------------------------------------------------------------- /src/examples/partials/variable.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{> (lookup . 'myVariable') }} 6 | partials: 7 | lookupMyPartial: Found! 8 | input: 9 | myVariable: lookupMyPartial 10 | --- 11 | -------------------------------------------------------------------------------- /src/ko/examples/html-escaping.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | raw: {{{specialChars}}} 6 | html-escaped: {{specialChars}} 7 | input: 8 | specialChars: '& < > " '' ` =' 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/html-escaping.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | raw: {{{specialChars}}} 6 | html-escaped: {{specialChars}} 7 | input: 8 | specialChars: '& < > " '' ` =' 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/partials/parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: "{{> myPartial parameter=favoriteNumber }}" 5 | partials: 6 | myPartial: "The result is {{parameter}}" 7 | input: 8 | favoriteNumber: 123 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-log.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{log 'this is a simple log output'}} 6 | input: 7 | --- 8 | 9 | Press F12 and open the dev-console to see the log output. 10 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-log.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{log 'this is a simple log output'}} 6 | input: 7 | --- 8 | 9 | Press F12 and open the dev-console to see the log output. 10 | -------------------------------------------------------------------------------- /src/examples/path-expressions-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{person.firstname}} {{person.lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/examples/path-expressions-slash.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{person/firstname}} {{person/lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-eachelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#each paragraphs}} 6 |

{{this}}

7 | {{else}} 8 |

No content

9 | {{/each}} 10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/ko/examples/partials/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial }}" 5 | preparationScript: | 6 | Handlebars.registerPartial('myPartial', '{{prefix}}'); 7 | input: 8 | prefix: Hello 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/partials/partial-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#> layout }} 6 | My Content 7 | {{/layout}} 8 | partials: 9 | layout: Site Content {{> @partial-block }} 10 | --- 11 | -------------------------------------------------------------------------------- /src/ko/examples/partials/variable.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{> (lookup . 'myVariable') }} 6 | partials: 7 | lookupMyPartial: Found! 8 | input: 9 | myVariable: lookupMyPartial 10 | --- 11 | -------------------------------------------------------------------------------- /src/zh/examples/partials/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial }}" 5 | preparationScript: | 6 | Handlebars.registerPartial('myPartial', '{{prefix}}'); 7 | input: 8 | prefix: Hello 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/partials/partial-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#> layout }} 6 | My Content 7 | {{/layout}} 8 | partials: 9 | layout: Site Content {{> @partial-block }} 10 | --- 11 | -------------------------------------------------------------------------------- /src/zh/examples/partials/variable.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{> (lookup . 'myVariable') }} 6 | partials: 7 | lookupMyPartial: Found! 8 | input: 9 | myVariable: lookupMyPartial 10 | --- 11 | -------------------------------------------------------------------------------- /src/examples/partials/other-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: "{{> myPartial myOtherContext }}" 5 | partials: 6 | myPartial: "{{information}}" 7 | input: 8 | myOtherContext: 9 | information: Interesting! 10 | --- 11 | -------------------------------------------------------------------------------- /src/ko/api-reference/index.md: -------------------------------------------------------------------------------- 1 | # 인덱스 2 | 3 | - [(사전) 컴파일](compilation.md) 4 | - [런타임](runtime.md) 5 | - [유틸리티](utilities.md) 6 | - [헬퍼 유틸리티](utilities.md#helper-utilities) 7 | - [일반 유틸리티](utilities.md#general-utilities) 8 | - [내장 헬퍼에서 사용하는 `@data` 변수](data-variables.md) 9 | -------------------------------------------------------------------------------- /src/ko/examples/partials/parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial parameter=favoriteNumber }}" 5 | partials: 6 | myPartial: "The result is {{parameter}}" 7 | input: 8 | favoriteNumber: 123 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/partials/parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial parameter=favoriteNumber }}" 5 | partials: 6 | myPartial: "The result is {{parameter}}" 7 | input: 8 | favoriteNumber: 123 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-with-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |+ 5 | {{#with person}} 6 | {{firstname}} {{lastname}} 7 | {{/with}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/ko/examples/path-expressions-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{person.firstname}} {{person.lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/ko/examples/path-expressions-slash.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{person/firstname}} {{person/lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/zh/api-reference/index.md: -------------------------------------------------------------------------------- 1 | # 索引 2 | 3 | - [编译和预编译](compilation.md) 4 | - [运行时](runtime.md) 5 | - [Utilities](utilities.md) 6 | - [Helper utilities](utilities.md#助手代码实用方法) 7 | - [General utilities](utilities.md#general-utilities) 8 | - [内置助手代码使用的 `@data` 变量](data-variables.md) 9 | -------------------------------------------------------------------------------- /src/zh/examples/path-expressions-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{person.firstname}} {{person.lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/zh/examples/path-expressions-slash.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{person/firstname}} {{person/lastname}} 6 | partials: 7 | input: 8 | person: 9 | firstname: Yehuda 10 | lastname: Katz 11 | --- 12 | -------------------------------------------------------------------------------- /src/examples/hook-block-helper-missing-default.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-eachelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#each paragraphs}} 6 |

{{this}}

7 | {{else}} 8 |

No content

9 | {{/each}} 10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-eachelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#each paragraphs}} 6 |

{{this}}

7 | {{else}} 8 |

No content

9 | {{/each}} 10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/ko/examples/partials/other-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial myOtherContext }}" 5 | partials: 6 | myPartial: "{{information}}" 7 | input: 8 | myOtherContext: 9 | information: Interesting! 10 | --- 11 | -------------------------------------------------------------------------------- /src/zh/examples/partials/other-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> myPartial myOtherContext }}" 5 | partials: 6 | myPartial: "{{information}}" 7 | input: 8 | myOtherContext: 9 | information: Interesting! 10 | --- 11 | -------------------------------------------------------------------------------- /src/examples/comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{! This comment will not show up in the output}} 6 | 7 | {{!-- This comment may contain mustaches like }} --}} 8 | input: {} 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-with-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#with person}} 6 | {{firstname}} {{lastname}} 7 | {{/with}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-with-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#with person}} 6 | {{firstname}} {{lastname}} 7 | {{/with}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-unless-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 |
6 | {{#unless license}} 7 |

WARNING: This entry does not have a license!

8 | {{/unless}} 9 |
10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/ko/examples/hook-block-helper-missing-default.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/zh/examples/hook-block-helper-missing-default.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | input: 9 | person: 10 | firstname: Yehuda 11 | lastname: Katz 12 | --- 13 | -------------------------------------------------------------------------------- /src/examples/partials/dynamic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: "{{> (whichPartial) }}" 5 | preparationScript: | 6 | Handlebars.registerHelper('whichPartial', function(context, options) { return 'dynamicPartial' }); 7 | partials: 8 | dynamicPartial: Dynamo! 9 | --- 10 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-log-multiple-params.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |+ 5 | {{log 'firstname' firstname 'lastname' lastname}} 6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | 11 | Press F12 and open the dev-console to see the log output. 12 | -------------------------------------------------------------------------------- /src/ko/examples/comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{! This comment will not show up in the output}} 6 | 7 | {{!-- This comment may contain mustaches like }} --}} 8 | input: {} 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{! This comment will not show up in the output}} 6 | 7 | {{!-- This comment may contain mustaches like }} --}} 8 | input: {} 9 | --- 10 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/codemirror-languages/readme.md: -------------------------------------------------------------------------------- 1 | # CodeMirror Languages 2 | 3 | This folder contains custom CodeMirror languages and its parsers. 4 | 5 | If you change the grammar, you have to rebuild the parser: 6 | 7 | - `npm run codemirror:lang-handlebars` 8 | - `npm run codemirror:lang-js-object` 9 | -------------------------------------------------------------------------------- /src/examples/raw-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{{{raw-loud}}}} 6 | {{bar}} 7 | {{{{/raw-loud}}}} 8 | preparationScript: | 9 | Handlebars.registerHelper('raw-loud', function(options) { 10 | return options.fn().toUpperCase() 11 | }); 12 | --- 13 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-unless-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#unless license}} 7 |

WARNING: This entry does not have a license!

8 | {{/unless}} 9 |
10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-unless-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#unless license}} 7 |

WARNING: This entry does not have a license!

8 | {{/unless}} 9 |
10 | input: {} 11 | --- 12 | -------------------------------------------------------------------------------- /src/.vitepress/components/Flex.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-if-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{/if}} 9 |
10 | input: 11 | author: true 12 | firstName: Yehuda 13 | lastName: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/examples/path-expressions-dot-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{../prefix}} {{firstname}} 7 | {{/each}} 8 | partials: 9 | input: 10 | people: 11 | - firstname: Nils 12 | - firstname: Yehuda 13 | prefix: "Hello" 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/partials/dynamic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> (whichPartial) }}" 5 | preparationScript: | 6 | Handlebars.registerHelper('whichPartial', function(context, options) { return 'dynamicPartial' }); 7 | partials: 8 | dynamicPartial: Dynamo! 9 | --- 10 | -------------------------------------------------------------------------------- /src/zh/examples/partials/dynamic.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: "{{> (whichPartial) }}" 5 | preparationScript: | 6 | Handlebars.registerHelper('whichPartial', function(context, options) { return 'dynamicPartial' }); 7 | partials: 8 | dynamicPartial: Dynamo! 9 | --- 10 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-log-multiple-params.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{log 'firstname' firstname 'lastname' lastname}} 6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | 11 | Press F12 and open the dev-console to see the log output. 12 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-log-multiple-params.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{log 'firstname' firstname 'lastname' lastname}} 6 | input: 7 | firstname: Yehuda 8 | lastname: Katz 9 | --- 10 | 11 | Press F12 and open the dev-console to see the log output. 12 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-with-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |+ 5 | {{#with city}} 6 | {{city.name}} (not shown because there is no city) 7 | {{else}} 8 | No city found 9 | {{/with}} 10 | input: 11 | person: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/examples/partials/inline.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#*inline "myPartial"}} 6 | My Content 7 | {{/inline}} 8 | {{#each people}} 9 | {{> myPartial}} 10 | {{/each}} 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | --- 16 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-lookup.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |+ 5 | {{#each people}} 6 | {{.}} lives in {{lookup ../cities @index}} 7 | {{/each}} 8 | input: 9 | people: 10 | - Nils 11 | - Yehuda 12 | cities: 13 | - Darmstadt 14 | - San Francisco 15 | --- 16 | -------------------------------------------------------------------------------- /src/ko/examples/raw-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{{{raw-loud}}}} 6 | {{bar}} 7 | {{{{/raw-loud}}}} 8 | preparationScript: | 9 | Handlebars.registerHelper('raw-loud', function(options) { 10 | return options.fn().toUpperCase() 11 | }); 12 | --- 13 | -------------------------------------------------------------------------------- /src/zh/examples/raw-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{{{raw-loud}}}} 6 | {{bar}} 7 | {{{{/raw-loud}}}} 8 | preparationScript: | 9 | Handlebars.registerHelper('raw-loud', function(options) { 10 | return options.fn().toUpperCase() 11 | }); 12 | --- 13 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-each-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | 10 | input: 11 | people: 12 | - Yehuda Katz 13 | - Alan Johnson 14 | - Charles Jolley 15 | --- 16 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-if-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{/if}} 9 |
10 | input: 11 | author: true 12 | firstName: Yehuda 13 | lastName: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/path-expressions-dot-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{../prefix}} {{firstname}} 7 | {{/each}} 8 | partials: 9 | input: 10 | people: 11 | - firstname: Nils 12 | - firstname: Yehuda 13 | prefix: "Hello" 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-if-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{/if}} 9 |
10 | input: 11 | author: true 12 | firstName: Yehuda 13 | lastName: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/path-expressions-dot-dot.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{../prefix}} {{firstname}} 7 | {{/each}} 8 | partials: 9 | input: 10 | people: 11 | - firstname: Nils 12 | - firstname: Yehuda 13 | prefix: "Hello" 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/playground.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: 张 13 | lastname: 三 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/playground.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: Hyunwoo 13 | lastname: Im 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-with-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#with city}} 6 | {{city.name}} (not shown because there is no city) 7 | {{else}} 8 | No city found 9 | {{/with}} 10 | input: 11 | person: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/partials/inline.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#*inline "myPartial"}} 6 | My Content 7 | {{/inline}} 8 | {{#each people}} 9 | {{> myPartial}} 10 | {{/each}} 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | --- 16 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-with-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#with city}} 6 | {{city.name}} (not shown because there is no city) 7 | {{else}} 8 | No city found 9 | {{/with}} 10 | input: 11 | person: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/partials/inline.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#*inline "myPartial"}} 6 | My Content 7 | {{/inline}} 8 | {{#each people}} 9 | {{> myPartial}} 10 | {{/each}} 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | --- 16 | -------------------------------------------------------------------------------- /src/examples/helper-simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-lookup.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#each people}} 6 | {{.}} lives in {{lookup ../cities @index}} 7 | {{/each}} 8 | input: 9 | people: 10 | - Nils 11 | - Yehuda 12 | cities: 13 | - Darmstadt 14 | - San Francisco 15 | --- 16 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-lookup.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |+ 5 | {{#each people}} 6 | {{.}} lives in {{lookup ../cities @index}} 7 | {{/each}} 8 | input: 9 | people: 10 | - Nils 11 | - Yehuda 12 | cities: 13 | - Darmstadt 14 | - San Francisco 15 | --- 16 | -------------------------------------------------------------------------------- /src/examples/helper-data-name-conflict.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | helper: {{name}} 6 | data: {{./name}} or {{this/name}} or {{this.name}} 7 | partials: 8 | preparationScript: | 9 | Handlebars.registerHelper('name', function () { 10 | return "Nils" 11 | }) 12 | input: 13 | name: Yehuda 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-each-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | 10 | input: 11 | people: 12 | - Yehuda Katz 13 | - Alan Johnson 14 | - Charles Jolley 15 | --- 16 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-each-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | 10 | input: 11 | people: 12 | - Yehuda Katz 13 | - Alan Johnson 14 | - Charles Jolley 15 | --- 16 | -------------------------------------------------------------------------------- /src/snippets/precompilation/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /src/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Handlebars.js", 3 | "short_name": "Handlebars", 4 | "start_url": "/", 5 | "display": "standalone", 6 | "background_color": "#f0772b", 7 | "theme_color": "#000000", 8 | "icons": [ 9 | { 10 | "src": "/handlebars-icon.svg", 11 | "sizes": "512x512", 12 | "type": "image/svg" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-ifelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{else}} 9 |

Unknown Author

10 | {{/if}} 11 |
12 | input: 13 | author: false 14 | firstName: Yehuda 15 | lastName: Katz 16 | --- 17 | -------------------------------------------------------------------------------- /src/examples/partials/partial-block-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#each people as |person|}} 6 | {{#> childEntry}} 7 | {{person.firstname}} 8 | {{/childEntry}} 9 | {{/each}} 10 | input: 11 | people: 12 | - firstname: Nils 13 | - firstname: Yehuda 14 | - firstname: Carl 15 | --- 16 | -------------------------------------------------------------------------------- /src/ko/examples/helper-simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/helper-simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/helper-data-name-conflict.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | helper: {{name}} 6 | data: {{./name}} or {{this/name}} or {{this.name}} 7 | partials: 8 | preparationScript: | 9 | Handlebars.registerHelper('name', function () { 10 | return "Nils" 11 | }) 12 | input: 13 | name: Yehuda 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/helper-data-name-conflict.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | helper: {{name}} 6 | data: {{./name}} or {{this/name}} or {{this.name}} 7 | partials: 8 | preparationScript: | 9 | Handlebars.registerHelper('name', function () { 10 | return "Nils" 11 | }) 12 | input: 13 | name: Yehuda 14 | --- 15 | -------------------------------------------------------------------------------- /src/handlebars.data.js: -------------------------------------------------------------------------------- 1 | import { retrieveHandlebarsVersions } from "./.vitepress/lib/handlebars-versions.js"; 2 | import { getHandlebarsCliHelp } from "./.vitepress/lib/handlebars-cli-help.js"; 3 | 4 | export default { 5 | async load() { 6 | return { 7 | versions: await retrieveHandlebarsVersions(), 8 | cliHelp: await getHandlebarsCliHelp(), 9 | }; 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /src/examples/path-expressions-dot-dot-if.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{#if creator}} 7 | {{../prefix}} {{firstname}} 8 | {{/if}} 9 | {{/each}} 10 | partials: 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | creator: true 16 | prefix: "Hello" 17 | --- 18 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-ifelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{else}} 9 |

Unknown Author

10 | {{/if}} 11 |
12 | input: 13 | author: false 14 | firstName: Yehuda 15 | lastName: Katz 16 | --- 17 | -------------------------------------------------------------------------------- /src/ko/examples/partials/partial-block-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#each people as |person|}} 6 | {{#> childEntry}} 7 | {{person.firstname}} 8 | {{/childEntry}} 9 | {{/each}} 10 | input: 11 | people: 12 | - firstname: Nils 13 | - firstname: Yehuda 14 | - firstname: Carl 15 | --- 16 | -------------------------------------------------------------------------------- /src/zh/api-reference/helpers.md: -------------------------------------------------------------------------------- 1 | # 助手代码 2 | 3 | ## `options` 参数 4 | 5 | 除了在助手代码调用中运行的参数,`options` 也被作为一个额外的参数传递给助手代码。 6 | 7 | - `lookupProperty(object, propertyName)`: 可以返回对象自身属性的函数。本函数对 `allowedProtoProperties` 与 8 | `allowedProtoMethods` 内的白名单进行参考。例如: 9 | 10 | 11 | 12 | - TODO:对所有传递给助手代码的选项进行解释。 13 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-ifelse-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 |
6 | {{#if author}} 7 |

{{firstName}} {{lastName}}

8 | {{else}} 9 |

Unknown Author

10 | {{/if}} 11 |
12 | input: 13 | author: false 14 | firstName: Yehuda 15 | lastName: Katz 16 | --- 17 | -------------------------------------------------------------------------------- /src/zh/examples/partials/partial-block-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#each people as |person|}} 6 | {{#> childEntry}} 7 | {{person.firstname}} 8 | {{/childEntry}} 9 | {{/each}} 10 | input: 11 | people: 12 | - firstname: Nils 13 | - firstname: Yehuda 14 | - firstname: Carl 15 | --- 16 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-if-subexpression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#if (isdefined value1)}}true{{else}}false{{/if}} 6 | {{#if (isdefined value2)}}true{{else}}false{{/if}} 7 | preparationScript: | 8 | Handlebars.registerHelper('isdefined', function (value) { 9 | return value !== undefined; 10 | }); 11 | input: 12 | value1: {} 13 | --- 14 | -------------------------------------------------------------------------------- /src/examples/helper-safestring.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{bold text}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper("bold", function(text) { 9 | var result = "" + Handlebars.escapeExpression(text) + ""; 10 | return new Handlebars.SafeString(result); 11 | }); 12 | input: 13 | text: Isn't this great? 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/examples/path-expressions-dot-dot-if.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{#if creator}} 7 | {{../prefix}} {{firstname}} 8 | {{/if}} 9 | {{/each}} 10 | partials: 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | creator: true 16 | prefix: "Hello" 17 | --- 18 | -------------------------------------------------------------------------------- /src/zh/examples/path-expressions-dot-dot-if.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{#if creator}} 7 | {{../prefix}} {{firstname}} 8 | {{/if}} 9 | {{/each}} 10 | partials: 11 | input: 12 | people: 13 | - firstname: Nils 14 | - firstname: Yehuda 15 | creator: true 16 | prefix: "Hello" 17 | --- 18 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-if-subexpression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#if (isdefined value1)}}true{{else}}false{{/if}} 6 | {{#if (isdefined value2)}}true{{else}}false{{/if}} 7 | preparationScript: | 8 | Handlebars.registerHelper('isdefined', function (value) { 9 | return value !== undefined; 10 | }); 11 | input: 12 | value1: {} 13 | --- 14 | -------------------------------------------------------------------------------- /src/ko/examples/helper-safestring.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{bold text}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper("bold", function(text) { 9 | var result = "" + Handlebars.escapeExpression(text) + ""; 10 | return new Handlebars.SafeString(result); 11 | }); 12 | input: 13 | text: Isn't this great? 14 | --- 15 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-if-subexpression.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#if (isdefined value1)}}true{{else}}false{{/if}} 6 | {{#if (isdefined value2)}}true{{else}}false{{/if}} 7 | preparationScript: | 8 | Handlebars.registerHelper('isdefined', function (value) { 9 | return value !== undefined; 10 | }); 11 | input: 12 | value1: {} 13 | --- 14 | -------------------------------------------------------------------------------- /src/zh/examples/helper-safestring.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{bold text}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper("bold", function(text) { 9 | var result = "" + Handlebars.escapeExpression(text) + ""; 10 | return new Handlebars.SafeString(result); 11 | }); 12 | input: 13 | text: Isn't this great? 14 | --- 15 | -------------------------------------------------------------------------------- /src/ko/api-reference/helpers.md: -------------------------------------------------------------------------------- 1 | # 헬퍼(Helpers) 2 | 3 | ## `options` 파라미터 4 | 5 | 헬퍼 호출에 사용되는 파라미터 외에도, options 객체가 추가 파라미터로 헬퍼에 전달됩니다. 6 | 7 | - `lookupProperty(object, propertyName)`: 객체의 "자체 속성"을 반환하는 함수입니다. 이 함수는 `allowedProtoProperties`와 8 | `allowedProtoMethods`에 지정된 화이트리스트를 따릅니다. 예시: 9 | 10 | 11 | 12 | - TODO:헬퍼에 전달되는 모든 옵션을 설명하세요. 13 | -------------------------------------------------------------------------------- /src/snippets/compiler-and-runtime/simple-console-out.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/prettify.js: -------------------------------------------------------------------------------- 1 | import * as prettier from "prettier"; 2 | import prettierPluginBabel from "prettier/plugins/babel"; 3 | import prettierPluginESTree from "prettier/plugins/estree"; 4 | 5 | export async function prettify(object) { 6 | return prettier.format(JSON.stringify(object || null), { 7 | parser: "json5", 8 | plugins: [prettierPluginBabel, prettierPluginESTree], 9 | printWidth: 40, 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /src/examples/partials/register.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each persons}} 6 | {{>person person=.}} 7 | {{/each}} 8 | preparationScript: > 9 | Handlebars.registerPartial("person", "{{person.name}} is {{person.age}} years old.\n") 10 | input: 11 | persons: 12 | - name: Nils 13 | age: 20 14 | - name: Teddy 15 | age: 10 16 | - name: Nelson 17 | age: 40 18 | --- 19 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/utils.js: -------------------------------------------------------------------------------- 1 | import { ExampleParser } from "./example-parser.js"; 2 | 3 | export function deindent(string, ...values) { 4 | const result = String.raw(string, ...values); 5 | return result.replace(/^\s*/gm, ""); 6 | } 7 | 8 | export async function parseExample(example) { 9 | if (example == null) { 10 | return; 11 | } 12 | 13 | const exampleParser = new ExampleParser(example); 14 | return exampleParser.parse(); 15 | } 16 | -------------------------------------------------------------------------------- /src/examples/partials/inline-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#> layout}} 6 | {{#*inline "nav"}} 7 | My Nav 8 | {{/inline}} 9 | {{#*inline "content"}} 10 | My Content 11 | {{/inline}} 12 | {{/layout}} 13 | partials: 14 | layout: |- 15 | 18 |
19 | {{> content}} 20 |
21 | --- 22 | -------------------------------------------------------------------------------- /src/examples/partials/parent-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{> myPartial prefix=../prefix firstname=firstname lastname=lastname}}. 7 | {{/each}} 8 | partials: 9 | myPartial: "{{prefix}}, {{firstname}} {{lastname}}" 10 | input: 11 | people: 12 | - firstname: Nils 13 | lastname: Knappmeier 14 | - firstname: Yehuda 15 | lastname: Katz 16 | prefix: Hello 17 | --- 18 | -------------------------------------------------------------------------------- /src/examples/each-with.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | Geo-Coordinates : 6 | {{#each cities}} 7 | {{name}} {{#with location}} {{north}}, {{east}} {{/with}} 8 | {{/each}} 9 | partials: 10 | input: 11 | cities: 12 | - name: Darmstadt 13 | location: 14 | north: 49.87 15 | east: 8.64 16 | - name: San Francisco 17 | location: 18 | north: 37.73 19 | east: -122.44 20 | --- 21 | -------------------------------------------------------------------------------- /src/examples/hook-block-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | preparationScript: | 9 | Handlebars.registerHelper('blockHelperMissing', function(context, options) { 10 | return "Helper '"+options.name+"' not found. Printing block: " + options.fn(context); 11 | }); 12 | input: 13 | person: 14 | firstname: Yehuda 15 | lastname: Katz 16 | --- 17 | -------------------------------------------------------------------------------- /src/examples/helper-this-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{print_person}} 7 | {{/each}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('print_person', function () { 11 | return this.firstname + ' ' + this.lastname 12 | }) 13 | input: 14 | people: 15 | - firstname: Nils 16 | lastname: Knappmeier 17 | - firstname: Yehuda 18 | lastname: Katz 19 | --- 20 | -------------------------------------------------------------------------------- /src/ko/examples/partials/inline-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#> layout}} 6 | {{#*inline "nav"}} 7 | My Nav 8 | {{/inline}} 9 | {{#*inline "content"}} 10 | My Content 11 | {{/inline}} 12 | {{/layout}} 13 | partials: 14 | layout: |- 15 | 18 |
19 | {{> content}} 20 |
21 | --- 22 | -------------------------------------------------------------------------------- /src/ko/examples/partials/parent-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{> myPartial prefix=../prefix firstname=firstname lastname=lastname}}. 7 | {{/each}} 8 | partials: 9 | myPartial: "{{prefix}}, {{firstname}} {{lastname}}" 10 | input: 11 | people: 12 | - firstname: Nils 13 | lastname: Knappmeier 14 | - firstname: Yehuda 15 | lastname: Katz 16 | prefix: Hello 17 | --- 18 | -------------------------------------------------------------------------------- /src/zh/examples/partials/inline-blocks.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#> layout}} 6 | {{#*inline "nav"}} 7 | My Nav 8 | {{/inline}} 9 | {{#*inline "content"}} 10 | My Content 11 | {{/inline}} 12 | {{/layout}} 13 | partials: 14 | layout: |- 15 | 18 |
19 | {{> content}} 20 |
21 | --- 22 | -------------------------------------------------------------------------------- /src/zh/examples/partials/parent-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{> myPartial prefix=../prefix firstname=firstname lastname=lastname}}. 7 | {{/each}} 8 | partials: 9 | myPartial: "{{prefix}}, {{firstname}} {{lastname}}" 10 | input: 11 | people: 12 | - firstname: Nils 13 | lastname: Knappmeier 14 | - firstname: Yehuda 15 | lastname: Katz 16 | prefix: Hello 17 | --- 18 | -------------------------------------------------------------------------------- /src/examples/helper-multiple-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{link "See Website" url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | url: "https://yehudakatz.com/" 15 | --- 16 | -------------------------------------------------------------------------------- /src/examples/literal-segments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{!-- wrong: {{array.0.item}} --}} 6 | correct: array.[0].item: {{array.[0].item}} 7 | 8 | {{!-- wrong: {{array.[0].item-class}} --}} 9 | correct: array.[0].[item-class]: {{array.[0].[item-class]}} 10 | 11 | {{!-- wrong: {{./true}}--}} 12 | correct: ./[true]: {{./[true]}} 13 | input: 14 | array: 15 | - item: item1 16 | item-class: class1 17 | true: "yes" 18 | --- 19 | -------------------------------------------------------------------------------- /src/ko/examples/each-with.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | Geo-Coordinates : 6 | {{#each cities}} 7 | {{name}} {{#with location}} {{north}}, {{east}} {{/with}} 8 | {{/each}} 9 | partials: 10 | input: 11 | cities: 12 | - name: Darmstadt 13 | location: 14 | north: 49.87 15 | east: 8.64 16 | - name: San Francisco 17 | location: 18 | north: 37.73 19 | east: -122.44 20 | --- 21 | -------------------------------------------------------------------------------- /src/zh/examples/each-with.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | Geo-Coordinates : 6 | {{#each cities}} 7 | {{name}} {{#with location}} {{north}}, {{east}} {{/with}} 8 | {{/each}} 9 | partials: 10 | input: 11 | cities: 12 | - name: Darmstadt 13 | location: 14 | north: 49.87 15 | east: 8.64 16 | - name: San Francisco 17 | location: 18 | north: 37.73 19 | east: -122.44 20 | --- 21 | -------------------------------------------------------------------------------- /src/ko/examples/helper-this-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{print_person}} 7 | {{/each}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('print_person', function () { 11 | return this.firstname + ' ' + this.lastname 12 | }) 13 | input: 14 | people: 15 | - firstname: Nils 16 | lastname: Knappmeier 17 | - firstname: Yehuda 18 | lastname: Katz 19 | --- 20 | -------------------------------------------------------------------------------- /src/zh/examples/helper-this-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each people}} 6 | {{print_person}} 7 | {{/each}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('print_person', function () { 11 | return this.firstname + ' ' + this.lastname 12 | }) 13 | input: 14 | people: 15 | - firstname: Nils 16 | lastname: Knappmeier 17 | - firstname: Yehuda 18 | lastname: Katz 19 | --- 20 | -------------------------------------------------------------------------------- /src/.vitepress/lib/handlebars-versions.js: -------------------------------------------------------------------------------- 1 | import semver from "semver"; 2 | 3 | export async function retrieveHandlebarsVersions() { 4 | const response = await fetch("https://registry.npmjs.org/handlebars/"); 5 | const npmMetaData = await response.json(); 6 | 7 | const allVersions = Object.keys(npmMetaData.versions).filter((version) => semver.gte(version, "3.0.0")); 8 | allVersions.sort(semver.rcompare); 9 | 10 | return { 11 | latest: npmMetaData["dist-tags"].latest, 12 | allVersions, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/ko/examples/partials/register.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each persons}} 6 | {{>person person=.}} 7 | {{/each}} 8 | preparationScript: > 9 | Handlebars.registerPartial( 10 | "person", 11 | "{{person.name}} is {{person.age}} years old.\n" 12 | ) 13 | input: 14 | persons: 15 | - name: Nils 16 | age: 20 17 | - name: Teddy 18 | age: 10 19 | - name: Nelson 20 | age: 40 21 | --- 22 | -------------------------------------------------------------------------------- /src/zh/examples/partials/register.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each persons}} 6 | {{>person person=.}} 7 | {{/each}} 8 | preparationScript: > 9 | Handlebars.registerPartial( 10 | "person", 11 | "{{person.name}} is {{person.age}} years old.\n" 12 | ) 13 | input: 14 | persons: 15 | - name: Nils 16 | age: 20 17 | - name: Teddy 18 | age: 10 19 | - name: Nelson 20 | age: 40 21 | --- 22 | -------------------------------------------------------------------------------- /src/ko/examples/literal-segments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{!-- wrong: {{array.0.item}} --}} 6 | correct: array.[0].item: {{array.[0].item}} 7 | 8 | {{!-- wrong: {{array.[0].item-class}} --}} 9 | correct: array.[0].[item-class]: {{array.[0].[item-class]}} 10 | 11 | {{!-- wrong: {{./true}}--}} 12 | correct: ./[true]: {{./[true]}} 13 | input: 14 | array: 15 | - item: item1 16 | item-class: class1 17 | true: "yes" 18 | --- 19 | -------------------------------------------------------------------------------- /src/zh/examples/literal-segments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{!-- wrong: {{array.0.item}} --}} 6 | correct: array.[0].item: {{array.[0].item}} 7 | 8 | {{!-- wrong: {{array.[0].item-class}} --}} 9 | correct: array.[0].[item-class]: {{array.[0].[item-class]}} 10 | 11 | {{!-- wrong: {{./true}}--}} 12 | correct: ./[true]: {{./[true]}} 13 | input: 14 | array: 15 | - item: item1 16 | item-class: class1 17 | true: "yes" 18 | --- 19 | -------------------------------------------------------------------------------- /src/ko/examples/hook-block-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | preparationScript: | 9 | Handlebars.registerHelper('blockHelperMissing', function(context, options) { 10 | return "Helper '"+options.name+"' not found. " 11 | + "Printing block: " + options.fn(context); 12 | }); 13 | input: 14 | person: 15 | firstname: Yehuda 16 | lastname: Katz 17 | --- 18 | -------------------------------------------------------------------------------- /src/zh/examples/hook-block-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#person}} 6 | {{firstname}} {{lastname}} 7 | {{/person}} 8 | preparationScript: | 9 | Handlebars.registerHelper('blockHelperMissing', function(context, options) { 10 | return "Helper '"+options.name+"' not found. " 11 | + "Printing block: " + options.fn(context); 12 | }); 13 | input: 14 | person: 15 | firstname: Yehuda 16 | lastname: Katz 17 | --- 18 | -------------------------------------------------------------------------------- /src/playground.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{firstname}} {{loud lastname}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('loud', function (aString) { 9 | return aString.toUpperCase() 10 | }) 11 | input: 12 | firstname: Yehuda 13 | lastname: Katz 14 | --- 15 | 16 | 20 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-with-block-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{#with city as | city |}} 6 | {{#with city.location as | loc |}} 7 | {{city.name}}: {{loc.north}} {{loc.east}} 8 | {{/with}} 9 | {{/with}} 10 | input: 11 | city: 12 | name: San Francisco 13 | summary: San Francisco is the cultural center of Northern California 14 | location: 15 | north: "37.73," 16 | east: -122.44 17 | population: 883305 18 | --- 19 | -------------------------------------------------------------------------------- /src/examples/helper-lookup-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{lookupOrDefault this 'firstname' 'Name not found'}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('lookupOrDefault', function (object, propertyName, defaultValue, options) { 9 | var result = options.lookupProperty(object, propertyName) 10 | if (result != null) { 11 | return result 12 | } 13 | return defaultValue 14 | }) 15 | input: 16 | firstname: Yehuda 17 | --- 18 | -------------------------------------------------------------------------------- /src/ko/examples/helper-multiple-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link "See Website" url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | url: "https://yehudakatz.com/" 15 | --- 16 | -------------------------------------------------------------------------------- /src/zh/examples/helper-multiple-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link "See Website" url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | url: "https://yehudakatz.com/" 15 | --- 16 | -------------------------------------------------------------------------------- /src/.vitepress/lib/handlebars-cli-help.js: -------------------------------------------------------------------------------- 1 | import cp from "child_process"; 2 | 3 | export async function getHandlebarsCliHelp() { 4 | const handlebarsCliUrl = await import.meta.resolve("handlebars/bin/handlebars"); 5 | const handlebarsCliPath = new URL(handlebarsCliUrl).pathname; 6 | const nodeExecutable = process.argv[0]; 7 | 8 | const { stdout } = cp.spawnSync(nodeExecutable, [handlebarsCliPath, "--help"], { 9 | argv0: "handlebars", 10 | stdio: ["pipe", "pipe", "pipe"], 11 | encoding: "utf-8", 12 | }); 13 | 14 | return stdout; 15 | } 16 | -------------------------------------------------------------------------------- /src/examples/hook-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: |- 5 | {{foo}} 6 | {{foo true}} 7 | {{foo 2 true}} 8 | {{#foo true}}{{/foo}} 9 | {{#foo}}{{/foo}} 10 | preparationScript: > 11 | Handlebars.registerHelper('helperMissing', function( /* dynamic arguments */) { 12 | var options = arguments[arguments.length-1]; 13 | var args = Array.prototype.slice.call(arguments, 0,arguments.length-1) 14 | return new Handlebars.SafeString("Missing: "+options.name+"("+args+")") 15 | }) 16 | --- 17 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-with-block-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#with city as | city |}} 6 | {{#with city.location as | loc |}} 7 | {{city.name}}: {{loc.north}} {{loc.east}} 8 | {{/with}} 9 | {{/with}} 10 | input: 11 | city: 12 | name: San Francisco 13 | summary: San Francisco is the cultural center of Northern California 14 | location: 15 | north: "37.73," 16 | east: -122.44 17 | population: 883305 18 | --- 19 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-with-block-param.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{#with city as | city |}} 6 | {{#with city.location as | loc |}} 7 | {{city.name}}: {{loc.north}} {{loc.east}} 8 | {{/with}} 9 | {{/with}} 10 | input: 11 | city: 12 | name: San Francisco 13 | summary: San Francisco is the cultural center of Northern California 14 | location: 15 | north: "37.73," 16 | east: -122.44 17 | population: 883305 18 | --- 19 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/worker.js: -------------------------------------------------------------------------------- 1 | import { executeExample } from "../execute-example"; 2 | import { lazyGetHandlebars } from "./lazy-get-handlebars"; 3 | 4 | onmessage = async function (parsedExampleWithVersion) { 5 | try { 6 | const handlebars = await lazyGetHandlebars(parsedExampleWithVersion.data.handlebarsVersion); 7 | const result = executeExample(handlebars, parsedExampleWithVersion.data); 8 | 9 | postMessage(result); 10 | } catch (e) { 11 | postMessage({ error: e.message }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/examples/helper-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{progress "Search" 10 false}} 6 | {{progress "Upload" 90 true}} 7 | {{progress "Finish" 100 false}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('progress', function (name, percent, stalled) { 11 | var barWidth = percent / 5 12 | var bar = "********************".slice(0,barWidth) 13 | return bar + " " + percent + "% " + name + " " + (stalled ? "stalled" : "") 14 | }) 15 | input: {} 16 | --- 17 | -------------------------------------------------------------------------------- /src/ko/examples/helper-lookup-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{lookupOrDefault this 'firstname' 'Name not found'}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('lookupOrDefault', function (object, propertyName, defaultValue, options) { 9 | var result = options.lookupProperty(object, propertyName) 10 | if (result != null) { 11 | return result 12 | } 13 | return defaultValue 14 | }) 15 | input: 16 | firstname: Yehuda 17 | --- 18 | -------------------------------------------------------------------------------- /src/zh/examples/helper-lookup-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{lookupOrDefault this 'firstname' 'Name not found'}} 6 | partials: 7 | preparationScript: | 8 | Handlebars.registerHelper('lookupOrDefault', function (object, propertyName, defaultValue, options) { 9 | var result = options.lookupProperty(object, propertyName) 10 | if (result != null) { 11 | return result 12 | } 13 | return defaultValue 14 | }) 15 | input: 16 | firstname: Yehuda 17 | --- 18 | -------------------------------------------------------------------------------- /src/examples/partials/partials.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{>header}} 6 |
7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{person.name}} is {{person.age}} years old. 15 | input: 16 | persons: 17 | - name: Nils 18 | age: 20 19 | - name: Teddy 20 | age: 10 21 | - name: Nelson 22 | age: 40 23 | --- 24 | 25 | ```handlebars 26 | test 27 | ``` 28 | -------------------------------------------------------------------------------- /src/ko/examples/hook-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{foo}} 6 | {{foo true}} 7 | {{foo 2 true}} 8 | {{#foo true}}{{/foo}} 9 | {{#foo}}{{/foo}} 10 | preparationScript: > 11 | Handlebars.registerHelper('helperMissing', function( /* dynamic arguments */) { 12 | var options = arguments[arguments.length-1]; 13 | var args = Array.prototype.slice.call(arguments, 0,arguments.length-1) 14 | return new Handlebars.SafeString("Missing: "+options.name+"("+args+")") 15 | }) 16 | --- 17 | -------------------------------------------------------------------------------- /src/zh/examples/hook-helper-missing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: |- 5 | {{foo}} 6 | {{foo true}} 7 | {{foo 2 true}} 8 | {{#foo true}}{{/foo}} 9 | {{#foo}}{{/foo}} 10 | preparationScript: > 11 | Handlebars.registerHelper('helperMissing', function( /* dynamic arguments */) { 12 | var options = arguments[arguments.length-1]; 13 | var args = Array.prototype.slice.call(arguments, 0,arguments.length-1) 14 | return new Handlebars.SafeString("Missing: "+options.name+"("+args+")") 15 | }) 16 | --- 17 | -------------------------------------------------------------------------------- /src/ko/examples/helper-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{progress "Search" 10 false}} 6 | {{progress "Upload" 90 true}} 7 | {{progress "Finish" 100 false}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('progress', function (name, percent, stalled) { 11 | var barWidth = percent / 5 12 | var bar = "********************".slice(0,barWidth) 13 | return bar + " " + percent + "% " + name + " " + (stalled ? "stalled" : "") 14 | }) 15 | input: {} 16 | --- 17 | -------------------------------------------------------------------------------- /src/zh/examples/helper-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{progress "Search" 10 false}} 6 | {{progress "Upload" 90 true}} 7 | {{progress "Finish" 100 false}} 8 | partials: 9 | preparationScript: | 10 | Handlebars.registerHelper('progress', function (name, percent, stalled) { 11 | var barWidth = percent / 5 12 | var bar = "********************".slice(0,barWidth) 13 | return bar + " " + percent + "% " + name + " " + (stalled ? "stalled" : "") 14 | }) 15 | input: {} 16 | --- 17 | -------------------------------------------------------------------------------- /src/snippets/precompilation/precompile-in-nodejs.output.js: -------------------------------------------------------------------------------- 1 | {"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 2 | var helper, alias1=container.propertyIsEnumerable; 3 | 4 | return "Handlebars " 5 | + container.escapeExpression(((helper = (helper = helpers.doesWhat || (depth0 != null ? depth0.doesWhat : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"doesWhat","hash":{},"data":data}) : helper))) 6 | + " precompiled!"; 7 | },"useData":true} -------------------------------------------------------------------------------- /src/api-reference/helpers.md: -------------------------------------------------------------------------------- 1 | # Helpers 2 | 3 | ## The `options`-parameter 4 | 5 | In addition to the parameters used in the helper-call, an `options`-object is passed to the helper as additional 6 | parameter. 7 | 8 | - `lookupProperty(object, propertyName)`: a function that returns an "own property" of an object. Whitelists specified 9 | in `allowedProtoProperties` and `allowedProtoMethods` are respected by this function. Example: 10 | 11 | 12 | 13 | - TODO: Describe all options that are passed to helpers 14 | -------------------------------------------------------------------------------- /src/ko/examples/partials/partials.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{>header}} 6 |
7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{person.name}} is {{person.age}} years old. 15 | input: 16 | persons: 17 | - name: Nils 18 | age: 20 19 | - name: Teddy 20 | age: 10 21 | - name: Nelson 22 | age: 40 23 | --- 24 | 25 | ```handlebars 26 | test 27 | ``` 28 | -------------------------------------------------------------------------------- /src/zh/examples/partials/partials.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{>header}} 6 |
7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{person.name}} is {{person.age}} years old. 15 | input: 16 | persons: 17 | - name: Nils 18 | age: 20 19 | - name: Teddy 20 | age: 10 21 | - name: Nelson 22 | age: 40 23 | --- 24 | 25 | ```handlebars 26 | test 27 | ``` 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: {} 8 | 9 | jobs: 10 | test: 11 | name: Test & Lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | 17 | - name: Setup Node.js 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: '22' 21 | 22 | - name: Install dependencies 23 | run: npm ci 24 | 25 | - name: Lint 26 | run: npm run lint 27 | 28 | - name: Test 29 | run: npm run test 30 | -------------------------------------------------------------------------------- /src/api-reference/index.md: -------------------------------------------------------------------------------- 1 | # Index 2 | 3 | 8 | 9 | - [(Pre-)Compilation](compilation.md) 10 | - [Runtime](runtime.md) 11 | - [Utilities](utilities.md) 12 | - [Helper utilities](utilities.md#helper-utilities) 13 | - [General utilities](utilities.md#general-utilities) 14 | - [`@data`-variables used by built-in helpers](data-variables.md) 15 | -------------------------------------------------------------------------------- /src/examples/helper-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#list people}}{{firstname}} {{lastname}}{{/list}} 6 | preparationScript: | 7 | Handlebars.registerHelper("list", function(items, options) { 8 | const itemsAsHtml = items.map(item => "
  • " + options.fn(item) + "
  • "); 9 | return "
      \n" + itemsAsHtml.join("\n") + "\n
    "; 10 | }); 11 | input: 12 | people: 13 | - firstname: Yehuda 14 | lastname: Katz 15 | - firstname: Carl 16 | lastname: Lerche 17 | - firstname: Alan 18 | lastname: Johnson 19 | --- 20 | -------------------------------------------------------------------------------- /src/examples/helper-dynamic-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{link people.text people.url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | people: 15 | firstname: Yehuda 16 | lastname: Katz 17 | url: "https://yehudakatz.com/" 18 | text: "See Website" 19 | --- 20 | -------------------------------------------------------------------------------- /src/ko/examples/helper-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#list people}}{{firstname}} {{lastname}}{{/list}} 6 | preparationScript: | 7 | Handlebars.registerHelper("list", function(items, options) { 8 | const itemsAsHtml = items.map(item => "
  • " + options.fn(item) + "
  • "); 9 | return "
      \n" + itemsAsHtml.join("\n") + "\n
    "; 10 | }); 11 | input: 12 | people: 13 | - firstname: Yehuda 14 | lastname: Katz 15 | - firstname: Carl 16 | lastname: Lerche 17 | - firstname: Alan 18 | lastname: Johnson 19 | --- 20 | -------------------------------------------------------------------------------- /src/zh/examples/helper-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#list people}}{{firstname}} {{lastname}}{{/list}} 6 | preparationScript: | 7 | Handlebars.registerHelper("list", function(items, options) { 8 | const itemsAsHtml = items.map(item => "
  • " + options.fn(item) + "
  • "); 9 | return "
      \n" + itemsAsHtml.join("\n") + "\n
    "; 10 | }); 11 | input: 12 | people: 13 | - firstname: Yehuda 14 | lastname: Katz 15 | - firstname: Carl 16 | lastname: Lerche 17 | - firstname: Alan 18 | lastname: Johnson 19 | --- 20 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-lookup-dynamic-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{#each persons as | person |}} 6 | {{name}} lives in {{#with (lookup ../cities [resident-in])~}} 7 | {{name}} ({{country}}) 8 | {{/with}} 9 | {{/each}} 10 | input: 11 | persons: 12 | - name: Nils 13 | resident-in: darmstadt 14 | - name: Yehuda 15 | resident-in: san-francisco 16 | cities: 17 | darmstadt: 18 | name: Darmstadt 19 | country: Germany 20 | san-francisco: 21 | name: San Francisco 22 | country: USA 23 | --- 24 | -------------------------------------------------------------------------------- /src/ko/examples/helper-dynamic-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link people.text people.url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | people: 15 | firstname: Yehuda 16 | lastname: Katz 17 | url: "https://yehudakatz.com/" 18 | text: "See Website" 19 | --- 20 | -------------------------------------------------------------------------------- /src/zh/examples/helper-dynamic-parameters.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link people.text people.url}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, url) { 8 | var url = Handlebars.escapeExpression(url), 9 | text = Handlebars.escapeExpression(text) 10 | 11 | return new Handlebars.SafeString("" + text +""); 12 | }); 13 | input: 14 | people: 15 | firstname: Yehuda 16 | lastname: Katz 17 | url: "https://yehudakatz.com/" 18 | text: "See Website" 19 | --- 20 | -------------------------------------------------------------------------------- /src/examples/builtin-helper-log-loglevel.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{log "debug logging" level="debug"}} 6 | {{log "info logging" level="info"}} 7 | {{log "info logging is the default"}} 8 | {{log "logging a warning" level="warn"}} 9 | {{log "logging an error" level="error"}} 10 | preparationScript: |- 11 | Handlebars.logger.level = 'error' 12 | console.log('Current log level: ', Handlebars.logger.level, '\n---') 13 | input: 14 | --- 15 | 16 | Press F12 and open the dev-console to see the log output. In order to see debug output, you may need to configure your 17 | dev-tools properly. 18 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-lookup-dynamic-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each persons as | person |}} 6 | {{name}} lives in {{#with (lookup ../cities [resident-in])~}} 7 | {{name}} ({{country}}) 8 | {{/with}} 9 | {{/each}} 10 | input: 11 | persons: 12 | - name: Nils 13 | resident-in: darmstadt 14 | - name: Yehuda 15 | resident-in: san-francisco 16 | cities: 17 | darmstadt: 18 | name: Darmstadt 19 | country: Germany 20 | san-francisco: 21 | name: San Francisco 22 | country: USA 23 | --- 24 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-lookup-dynamic-property.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{#each persons as | person |}} 6 | {{name}} lives in {{#with (lookup ../cities [resident-in])~}} 7 | {{name}} ({{country}}) 8 | {{/with}} 9 | {{/each}} 10 | input: 11 | persons: 12 | - name: Nils 13 | resident-in: darmstadt 14 | - name: Yehuda 15 | resident-in: san-francisco 16 | cities: 17 | darmstadt: 18 | name: Darmstadt 19 | country: Germany 20 | san-francisco: 21 | name: San Francisco 22 | country: USA 23 | --- 24 | -------------------------------------------------------------------------------- /src/ko/examples/builtin-helper-log-loglevel.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{log "debug logging" level="debug"}} 6 | {{log "info logging" level="info"}} 7 | {{log "info logging is the default"}} 8 | {{log "logging a warning" level="warn"}} 9 | {{log "logging an error" level="error"}} 10 | preparationScript: |- 11 | Handlebars.logger.level = 'error' 12 | console.log('Current log level: ', Handlebars.logger.level, '\n---') 13 | input: 14 | --- 15 | 16 | Press F12 and open the dev-console to see the log output. In order to see debug output, you may need to configure your 17 | dev-tools properly. 18 | -------------------------------------------------------------------------------- /src/zh/examples/builtin-helper-log-loglevel.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{log "debug logging" level="debug"}} 6 | {{log "info logging" level="info"}} 7 | {{log "info logging is the default"}} 8 | {{log "logging a warning" level="warn"}} 9 | {{log "logging an error" level="error"}} 10 | preparationScript: |- 11 | Handlebars.logger.level = 'error' 12 | console.log('Current log level: ', Handlebars.logger.level, '\n---') 13 | input: 14 | --- 15 | 16 | Press F12 and open the dev-console to see the log output. In order to see debug output, you may need to configure your 17 | dev-tools properly. 18 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/execute-one-after-another.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {}asyncFunction 4 | * @returns {function(): Promise<*>} 5 | */ 6 | export function executeOneAfterAnother(asyncFunction) { 7 | let lastExecutionDone = Promise.resolve(); 8 | 9 | return function (/* same args as asyncFunction */) { 10 | lastExecutionDone = runWhenCompleted(lastExecutionDone, () => asyncFunction.apply(this, [...arguments])); 11 | return lastExecutionDone; 12 | }; 13 | } 14 | 15 | async function runWhenCompleted(promiseToBeCompleted, functionToRun) { 16 | return promiseToBeCompleted.then(functionToRun, functionToRun); 17 | } 18 | -------------------------------------------------------------------------------- /src/examples/all-features.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{>header}} 6 |
    7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{loud person.name}} is {{person.age}} years old. 15 | preparationScript: | 16 | Handlebars.registerHelper('loud', function (aString) { 17 | return aString.toUpperCase() 18 | }) 19 | input: 20 | persons: 21 | - name: Nils 22 | age: 20 23 | - name: Teddy 24 | age: 10 25 | - name: Nelson 26 | age: 40 27 | --- 28 | -------------------------------------------------------------------------------- /src/ko/examples/all-features.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{>header}} 6 |
    7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{loud person.name}} is {{person.age}} years old. 15 | preparationScript: | 16 | Handlebars.registerHelper('loud', function (aString) { 17 | return aString.toUpperCase() 18 | }) 19 | input: 20 | persons: 21 | - name: Nils 22 | age: 20 23 | - name: Teddy 24 | age: 10 25 | - name: Nelson 26 | age: 40 27 | --- 28 | -------------------------------------------------------------------------------- /src/zh/examples/all-features.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{>header}} 6 |
    7 | {{#each persons}} 8 | {{>person person=.}} 9 | {{/each}} 10 | partials: 11 | header: | 12 | {{persons.length}} persons found 13 | person: | 14 | The person {{loud person.name}} is {{person.age}} years old. 15 | preparationScript: | 16 | Handlebars.registerHelper('loud', function (aString) { 17 | return aString.toUpperCase() 18 | }) 19 | input: 20 | persons: 21 | - name: Nils 22 | age: 20 23 | - name: Teddy 24 | age: 10 25 | - name: Nelson 26 | age: 40 27 | --- 28 | -------------------------------------------------------------------------------- /.github/workflows/build-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: build-and-deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build-and-deploy: 10 | runs-on: ubuntu-latest 11 | env: 12 | TARGET_URL: handlebarsjs.com 13 | steps: 14 | - uses: actions/checkout@v1 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: '22' 18 | - run: npm ci 19 | - run: npm run docs:build 20 | 21 | - name: Deploy to ${{ env.TARGET_URL }} 22 | uses: peaceiris/actions-gh-pages@v3 23 | with: 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | publish_dir: ./src/.vitepress/dist 26 | cname: ${{ env.TARGET_URL }} 27 | -------------------------------------------------------------------------------- /src/snippets/compiler-and-runtime/index.html: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 7 | 8 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /src/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Handlebars" 7 | tagline: 轻量的语义化模板 8 | image: 9 | src: /handlebars-icon.svg 10 | alt: Handlebars icon 11 | actions: 12 | - theme: brand 13 | text: 快速上手 → 14 | link: /zh/guide/ 15 | - theme: alt 16 | text: 在线演示 → 17 | link: /zh/playground.html 18 | 19 | features: 20 | - title: 语义化模板 21 | details: Handlebars 提供了必要的功能,使你可以高效地构建语义化模板。 22 | - title: 兼容 Mustache 23 | details: Handlebars 与 Mustache 模板基本兼容。大多数情况下,您可以在使用 Handlebars 的同时继续使用您当前的模板。 24 | - title: 高速执行 25 | details: Handlebars 会将模板编译为 JavaScript 函数。这使得 Handlebars 的执行速度比其他大多数模板引擎都要快。 26 | --- 27 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/WorkspaceError.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/HandlebarsVersionChooser.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | 30 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/limit-waiting-time.js: -------------------------------------------------------------------------------- 1 | export async function limitWaitingTime(promiseToWaitFor, maxWaitMillis, timeoutCallback) { 2 | try { 3 | return await Promise.race([ 4 | promiseToWaitFor, 5 | rejectAfter(maxWaitMillis, () => new TimeoutError(`Timed out after ${maxWaitMillis}ms`)), 6 | ]); 7 | } catch (error) { 8 | if (error instanceof TimeoutError) { 9 | timeoutCallback(); 10 | } 11 | throw error; 12 | } 13 | } 14 | 15 | async function rejectAfter(milliseconds, errorProvider) { 16 | return new Promise((resolve, reject) => setTimeout(() => reject(errorProvider()), milliseconds)); 17 | } 18 | 19 | export class TimeoutError extends Error { 20 | constructor(message) { 21 | super(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | // https://vitepress.dev/guide/custom-theme 2 | import { h } from "vue"; 3 | import Theme from "vitepress/theme"; 4 | import Flex from "../components/Flex.vue"; 5 | import Example from "../components/Example.vue"; 6 | import PlaygroundLayout from "../components/PlaygroundLayout.vue"; 7 | import "./style.css"; 8 | 9 | export default { 10 | extends: Theme, 11 | Layout: () => { 12 | return h(Theme.Layout, null, { 13 | // https://vitepress.dev/guide/extending-default-theme#layout-slots 14 | }); 15 | }, 16 | async enhanceApp({ app, router, siteData }) { 17 | // https://vitepress.dev/guide/custom-theme#theme-interface 18 | app.component("playground", PlaygroundLayout); 19 | app.component("Flex", Flex); 20 | app.component("Example", Example); 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/ExportYamlModal.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | 31 | -------------------------------------------------------------------------------- /src/ko/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Handlebars" 7 | tagline: 강력한 경량형 템플릿 8 | image: 9 | src: /handlebars-icon.svg 10 | alt: Handlebars icon 11 | actions: 12 | - theme: brand 13 | text: 시작하기 → 14 | link: /ko/guide/ 15 | - theme: alt 16 | text: Playground → 17 | link: /ko/playground.html 18 | 19 | features: 20 | - title: Semantic 템플릿 21 | details: Handlebars는 큰 어려움 없이 semantic 템플릿을 효과적으로 구축할 수 있는 필요한 기능을 제공합니다. 22 | - title: Mustache 호환성 23 | details: 24 | Handlebars는 대부분의 경우 Mustache 템플릿과 호환 가능합니다. 대부분의 경우 Mustache를 Handlebars로 대체하고 25 | 현재의 템플릿을 계속 사용할 수 있습니다. 26 | - title: 빠른 실행 27 | details: 28 | Handlebars는 템플릿을 JavaScript 함수로 컴파일하기 때문에 템플릿 실행이 대부분의 다른 템플릿 엔진보다 빠릅니다. 29 | --- 30 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/lazy-get-handlebars.js: -------------------------------------------------------------------------------- 1 | // Cache version -> Promise 2 | const handlebarsCache = {}; 3 | 4 | export async function lazyGetHandlebars(version) { 5 | if (handlebarsCache[version] == null) { 6 | handlebarsCache[version] = loadHandlebarsNow(version); 7 | } 8 | return handlebarsCache[version]; 9 | } 10 | 11 | async function loadHandlebarsNow(version) { 12 | const response = await fetch(resolveHandlebarsUrl(version)); 13 | if (response.ok) { 14 | const exports = {}; 15 | const handlebarsUmdCode = await response.text(); 16 | Function("", handlebarsUmdCode).call(exports); 17 | return exports["Handlebars"]; 18 | } 19 | } 20 | 21 | function resolveHandlebarsUrl(version) { 22 | return `https://unpkg.com/handlebars@${version}/dist/handlebars.min.js`; 23 | } 24 | -------------------------------------------------------------------------------- /src/examples/helper-hash-arguments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: playground 3 | example: 4 | template: | 5 | {{link "See Website" href=person.url class="person"}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, options) { 8 | var attributes = []; 9 | 10 | Object.keys(options.hash).forEach(key => { 11 | var escapedKey = Handlebars.escapeExpression(key); 12 | var escapedValue = Handlebars.escapeExpression(options.hash[key]); 13 | attributes.push(escapedKey + '="' + escapedValue + '"'); 14 | }) 15 | var escapedText = Handlebars.escapeExpression(text); 16 | 17 | var escapedOutput ="" + escapedText + ""; 18 | return new Handlebars.SafeString(escapedOutput); 19 | }); 20 | input: 21 | person: 22 | firstname: Yehuda 23 | lastname: Katz 24 | url: "https://yehudakatz.com/" 25 | --- 26 | -------------------------------------------------------------------------------- /src/zh/guide/installation/when-to-use-handlebars.md: -------------------------------------------------------------------------------- 1 | # 什么时候使用/不使用 Handlebars? 2 | 3 | 本节概述了 Handlebars 的优缺点。它能够让你了解 Handlebars 是否适合你的实际情况,并使你就是否选择 Handlebars 做出明智的决定。 4 | 5 | ::: info 关于在浏览器中使用 Handlebars 的注意事项 6 | 7 | Handlebars 是一个纯渲染引擎。如果你要允许人们自己编写用于渲染 HTML 页面,电子邮件或者 Markdown 文件的模板,那么使用 Handlebars 效果将会很好。 8 | 9 | Handlebars **没有事件处理**,访问 **后端服务** 或增量 **DOM 更新** 的内置支持。 10 | 11 | 如果你想构建一个 **单页应用程序(SPA)** 并且想要处理用户输入,则可能应该寻找一个前端框架: 12 | 13 | - [Angular](https://angular.io/) 14 | - [Aurelia](https://aurelia.io/) 15 | - [Ember](https://emberjs.com/) 16 | - [Inferno](https://infernojs.org/) 17 | - [Mithril](https://mithril.js.org/) 18 | - [Svelte](https://svelte.dev/) 19 | - [Ractive](https://ractive.js.org/) 20 | - [React](https://reactjs.org/) 21 | - [Vue](https://vuejs.org/) 22 | 23 | ::: 24 | 25 | # 高级 26 | 27 | - Handlebars 非常适合在 CLI 应用渲染,非 HTML 文本内容,在服务器端呈现纯内容。 28 | - Handlebars 已移植到许多编程语言上(Java、Rust 等)。 29 | - Handlebars 不利于 DOM 的快速(增量)更新,事件处理和前后端通信。 30 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/client.js: -------------------------------------------------------------------------------- 1 | import ExecuteHandlebarsWorker from "./worker?worker"; 2 | import pDebounce from "p-debounce"; 3 | import { WorkerWithTerminationTimeout } from "./worker-with-termination-timeout"; 4 | import { executeOneAfterAnother } from "./execute-one-after-another"; 5 | 6 | const HANDLEBARS_EXECUTION_TIME_LIMIT_MILLIS = 2000; 7 | const DEBOUNCE_DELAY = 200; 8 | 9 | const workerWithTimeout = new WorkerWithTerminationTimeout( 10 | () => new ExecuteHandlebarsWorker(), 11 | HANDLEBARS_EXECUTION_TIME_LIMIT_MILLIS, 12 | ); 13 | 14 | async function executeExampleNow(parsedExample) { 15 | return workerWithTimeout.postMessage(parsedExample); 16 | } 17 | 18 | const debouncedSequentialExecuteExample = pDebounce(executeOneAfterAnother(executeExampleNow), DEBOUNCE_DELAY); 19 | 20 | export async function executeExample(parsedExample) { 21 | return debouncedSequentialExecuteExample(parsedExample); 22 | } 23 | -------------------------------------------------------------------------------- /src/ko/examples/helper-hash-arguments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link "See Website" href=person.url class="person"}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, options) { 8 | var attributes = []; 9 | 10 | Object.keys(options.hash).forEach(key => { 11 | var escapedKey = Handlebars.escapeExpression(key); 12 | var escapedValue = Handlebars.escapeExpression(options.hash[key]); 13 | attributes.push(escapedKey + '="' + escapedValue + '"'); 14 | }) 15 | var escapedText = Handlebars.escapeExpression(text); 16 | 17 | var escapedOutput ="" + escapedText + ""; 18 | return new Handlebars.SafeString(escapedOutput); 19 | }); 20 | input: 21 | person: 22 | firstname: Yehuda 23 | lastname: Katz 24 | url: "https://yehudakatz.com/" 25 | --- 26 | -------------------------------------------------------------------------------- /src/zh/examples/helper-hash-arguments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: InteractivePlaygroundLayout 3 | example: 4 | template: | 5 | {{link "See Website" href=person.url class="person"}} 6 | preparationScript: | 7 | Handlebars.registerHelper("link", function(text, options) { 8 | var attributes = []; 9 | 10 | Object.keys(options.hash).forEach(key => { 11 | var escapedKey = Handlebars.escapeExpression(key); 12 | var escapedValue = Handlebars.escapeExpression(options.hash[key]); 13 | attributes.push(escapedKey + '="' + escapedValue + '"'); 14 | }) 15 | var escapedText = Handlebars.escapeExpression(text); 16 | 17 | var escapedOutput ="" + escapedText + ""; 18 | return new Handlebars.SafeString(escapedOutput); 19 | }); 20 | input: 21 | person: 22 | firstname: Yehuda 23 | lastname: Katz 24 | url: "https://yehudakatz.com/" 25 | --- 26 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/worker-with-termination-timeout.js: -------------------------------------------------------------------------------- 1 | import { limitWaitingTime } from "./limit-waiting-time"; 2 | 3 | export class WorkerWithTerminationTimeout { 4 | constructor(workerFactory, timeoutMillis) { 5 | this.workerFactory = workerFactory; 6 | this.timeoutMillis = timeoutMillis; 7 | this._recreateWorker(); 8 | } 9 | 10 | async postMessage(message) { 11 | return new Promise((resolve, reject) => { 12 | this.worker.addEventListener("message", (e) => { 13 | if (e.data.error) { 14 | reject(new Error(e.data.error)); 15 | } else { 16 | resolve(e.data); 17 | } 18 | }); 19 | limitWaitingTime(this.worker.postMessage(message), this.timeoutMillis, () => this._recreateWorker()); 20 | }); 21 | } 22 | 23 | _recreateWorker() { 24 | if (this.worker != null) { 25 | this.worker.terminate(); 26 | } 27 | this.worker = this.workerFactory(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/codemirror-languages/js-object.js: -------------------------------------------------------------------------------- 1 | import { parser } from "./js-object.parser.js"; 2 | import { LRLanguage, LanguageSupport } from "@codemirror/language"; 3 | import { styleTags, tags as t } from "@lezer/highlight"; 4 | 5 | let parserWithMetadata = parser.configure({ 6 | props: [ 7 | styleTags({ 8 | PropertyDefinition: t.propertyName, 9 | BooleanLiteral: t.bool, 10 | Number: t.number, 11 | Escape: t.escape, 12 | String: t.string, 13 | LineComment: t.lineComment, 14 | BlockComment: t.blockComment, 15 | "[ ]": t.squareBracket, 16 | "{ }": t.brace, 17 | }), 18 | ], 19 | }); 20 | 21 | const language = LRLanguage.define({ 22 | name: "js-object", 23 | parser: parserWithMetadata, 24 | languageData: { 25 | closeBrackets: { brackets: ["(", "[", "{", "'", '"'] }, 26 | commentTokens: { line: "//", block: { open: "/*", close: "*/" } }, 27 | }, 28 | }); 29 | 30 | export function jsObject() { 31 | return new LanguageSupport(language, []); 32 | } 33 | -------------------------------------------------------------------------------- /src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Handlebars" 7 | tagline: Minimal templating on steroids 8 | image: 9 | src: /handlebars-icon.svg 10 | alt: Handlebars icon 11 | actions: 12 | - theme: brand 13 | text: Get started → 14 | link: /guide/ 15 | - theme: alt 16 | text: Live Demo → 17 | link: /playground.html 18 | 19 | features: 20 | - title: Semantic templates 21 | details: 22 | Handlebars provides the power necessary to let you build semantic templates effectively with no frustration. 23 | - title: Mustache-compatible 24 | details: 25 | Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with 26 | Handlebars and continue using your current templates. 27 | - title: Fast execution 28 | details: 29 | Handlebars compiles templates into JavaScript functions. This makes the template execution faster than most other 30 | template engines. 31 | --- 32 | -------------------------------------------------------------------------------- /src/snippets/precompilation/example.precompiled.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var template = Handlebars.template, 3 | templates = (Handlebars.templates = Handlebars.templates || {}); 4 | templates["example"] = template({ 5 | compiler: [8, ">= 4.3.0"], 6 | main: function (container, depth0, helpers, partials, data) { 7 | var helper, 8 | alias1 = container.propertyIsEnumerable; 9 | 10 | return ( 11 | "Handlebars " + 12 | container.escapeExpression( 13 | ((helper = 14 | (helper = helpers.doesWhat || (depth0 != null ? depth0.doesWhat : depth0)) != null 15 | ? helper 16 | : container.hooks.helperMissing), 17 | typeof helper === "function" 18 | ? helper.call(depth0 != null ? depth0 : container.nullContext || {}, { 19 | name: "doesWhat", 20 | hash: {}, 21 | data: data, 22 | }) 23 | : helper), 24 | ) + 25 | " precompiled!" 26 | ); 27 | }, 28 | useData: true, 29 | }); 30 | })(); 31 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/share-utils.js: -------------------------------------------------------------------------------- 1 | const CURRENT_SHARING_FORMAT = 1; 2 | 3 | export function createSharedUrl(currentExample) { 4 | let currentExampleAsJson = JSON.stringify(currentExample); 5 | const { protocol, host } = document.location; 6 | const hash = "#format=" + CURRENT_SHARING_FORMAT + "¤tExample=" + encodeURIComponent(currentExampleAsJson); 7 | return `${protocol}//${host}/playground.html${hash}`; 8 | } 9 | 10 | export function loadFromSharedUrl() { 11 | const hashMatch = document.location.hash.match(/#format=(\d+)¤tExample=(.*)/); 12 | if (hashMatch) { 13 | const format = Number(hashMatch[1]); 14 | const encodedExampleData = hashMatch[2]; 15 | switch (format) { 16 | case 1: 17 | return loadFromFormatVersion1(encodedExampleData); 18 | default: 19 | throw new Error("Unknown example sharing format " + format); 20 | } 21 | } 22 | } 23 | 24 | function loadFromFormatVersion1(encodedExampleData) { 25 | const decodedExampleData = decodeURIComponent(encodedExampleData); 26 | return JSON.parse(decodedExampleData); 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/handlebars-lang/docs/actions/workflows/ci.yml/badge.svg)](https://github.com/handlebars-lang/docs/actions/workflows/ci.yml) 2 | 3 | This is the repository for the Handlebars documentation site. 4 | 5 | * Target-URL: https://handlebarsjs.com 6 | 7 | # Why VitePress? 8 | 9 | There are a lot of static page generators out there nowadays. 10 | I have chosen [VitePress](https://vitepress.dev/) over other systems for several reasons: 11 | 12 | * I like [vuejs](https://vuejs.org). 13 | * VitePress builds fast loading static sites with modern PWA technologies. 14 | * VitePress is centered around markdown, but leaves the opportunity to inject interactive parts if needed. 15 | * VitePress has a simple predefined way of adapting stylesheets, which makes it easy to adapt colors from the 16 | original site without rewriting the whole css 17 | * The vuejs documentation site is build with VitePress, so it will hopefully be around for a while. 18 | 19 | You can challenge me and propose other solutions, but you might be asked to help out if you do. 20 | 21 | -- Nils 22 | 23 | :rocket: :rocket: 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011-2017 by Yehuda Katz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/ko/guide/installation/when-to-use-handlebars.md: -------------------------------------------------------------------------------- 1 | # Handlebars를 사용할 때와 사용하지 말아야 할 때? 2 | 3 | 이 섹션은 Handlebars의 강점과 약점에 대한 개요를 제공 합니다. Handlebars가 사용 사례에 적합한지 여부를 파악하고, 4 | Handlebars를 선택할지 여부에 대한 통찰력있는 결정을 내릴 수 있도록 돕습니다. 5 | 6 | ::: info 브라우저에서 Handlebars를 사용하는 데 관한 참고사항입니다. 7 | 8 | Handlebars는 순수한 렌더링 엔진입니다. HTML 페이지, 이메일 또는 마크다운 파일을 렌더링하는 경우에 잘 작동합니다. 9 | 10 | Handlebars에는 **이벤트 처리**, **백엔드 서비스** 접근 또는 **증분 DOM 업데이트**를 위한 내장 지원이 없습니다. 11 | 12 | 사용자 입력을 처리하고 **싱글 페이지 애플리케이션**을 구축하려는 경우, 아마도 Vue.js나 React와 같은 프레임워크를 찾아보 13 | 는 것이 좋습니다.: 14 | 15 | - [Angular](https://angular.io/) 16 | - [Aurelia](https://aurelia.io/) 17 | - [Ember](https://emberjs.com/) 18 | - [Inferno](https://infernojs.org/) 19 | - [Mithril](https://mithril.js.org/) 20 | - [Svelte](https://svelte.dev/) 21 | - [Ractive](https://ractive.js.org/) 22 | - [React](https://reactjs.org/) 23 | - [Vue](https://vuejs.org/) 24 | 25 | ::: 26 | 27 | # Handlebars의 장점 28 | 29 | - Handlebars는 CLI 애플리케이션, HTML이 아닌 텍스트 콘텐츠, 순수 콘텐츠의 서버 측 렌더링에 좋습니다. 30 | - Handlebars는 많은 프로그래밍 언어로 이식되었습니다(Java, Rust 등). 31 | 32 | # Handlebars의 단점 33 | 34 | - Handlebars는 DOM의 빠른(증분적) 업데이트, 이벤트 처리, 프론트엔드-백엔드 통신에 적합하지 않습니다. 35 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/execute-example.js: -------------------------------------------------------------------------------- 1 | import json5 from "json5"; 2 | 3 | export function executeExample(Handlebars, parsedExample) { 4 | const handlebars = prepareHandlebarsInstance(Handlebars, parsedExample); 5 | return compileAndRun(handlebars, parsedExample); 6 | } 7 | 8 | function prepareHandlebarsInstance(Handlebars, parsedExample) { 9 | const handlebars = Handlebars.create(); 10 | registerPartials(handlebars, parsedExample.partials); 11 | runPreparationScript(handlebars, parsedExample.preparationScript); 12 | return handlebars; 13 | } 14 | 15 | function registerPartials(handlebars, partials) { 16 | partials.forEach((partial) => { 17 | handlebars.registerPartial(partial.name, partial.content); 18 | }); 19 | } 20 | 21 | function runPreparationScript(handlebars, preparationScript) { 22 | const compiledPreparationScript = Function("Handlebars", preparationScript); 23 | compiledPreparationScript.call(undefined, handlebars); 24 | } 25 | 26 | function compileAndRun(handlebars, parsedExample) { 27 | const template = handlebars.compile(parsedExample.template); 28 | let inputObject = json5.parse(parsedExample.input); 29 | return template(inputObject); 30 | } 31 | -------------------------------------------------------------------------------- /src/zh/api-reference/data-variables.md: -------------------------------------------------------------------------------- 1 | # `@data` 变量 2 | 3 | 下面的`@data`变量是由 Handlebars 及其内建助手代码实现的。 4 | 5 | ## `@root` 6 | 7 | 初始化模版被执行时的上下文。 8 | 9 | ```handlebars 10 | {{#each array}} {{@root.foo}} {{/each}} 11 | ``` 12 | 13 | 除非特意改变,对于页面渲染时的每一部分,本项的值恒定。因此,当深度参数不能够引用它们的父模版时,本项可以在代码片段内使用。 14 | 15 | ## `@first` 16 | 17 | 本项会被 `each` 助手代码在迭代的第一步被设置为 true。 18 | 19 | ```handlebars 20 | {{#each array}} {{#if @first}} First! {{/if}} {{/each}} 21 | ``` 22 | 23 | ## `@index` 24 | 25 | 从零开始的编号,表示当前的迭代次数。由 `each` 助手代码设置。 26 | 27 | ```handlebars 28 | {{#each array}} {{@index}} {{/each}} 29 | ``` 30 | 31 | ## `@key` 32 | 33 | 当前迭代次数的键。在遍历对象时被 `each` 助手代码设置。 34 | 35 | ```handlebars 36 | {{#each array}} {{@key}} {{/each}} 37 | ``` 38 | 39 | ## `@last` 40 | 41 | 在迭代的最后一步被 `each` 助手代码设置为 true。 42 | 43 | ```handlebars 44 | {{#each array}} {{#if @last}} Last :( {{/if}} {{/each}} 45 | ``` 46 | 47 | ## `@level` 48 | 49 | 设定 log 的输出级别。 50 | 51 | ```js 52 | template({}, { data: { level: Handlebars.logger.WARN } }); 53 | ``` 54 | 55 | 可以为以下值:`Handlebars.logger.DEBUG`,`Handlebars.logger.INFO`,`Handlebars.logger.WARN` 或者 56 | `Handlebars.logger.ERROR` 57 | 58 | 当设定时,程序会按照设定的级别选择输出的信息。默认值为 `Handlebars.logger.ERROR`。 59 | -------------------------------------------------------------------------------- /src/examples/_example-base-data.yaml: -------------------------------------------------------------------------------- 1 | # In order to make the examples in this site recognizable, we generally use this data as their basis. 2 | # If you want to create new example, you can use parts of this data along with your templates, partials and helpers. 3 | # You don't have to use the same JSON structure, but using the same entities (i.e. people, Darmstadt, San Francisco) 4 | # would be nice. If you have to use new data, please add it to this file. 5 | cities: 6 | - name: Darmstadt 7 | summary: Darmstadt is a city in Hesse, Germany 8 | country: Germany 9 | location: 10 | north: 49.87 11 | east: 8.64 12 | population: 158254 13 | - name: San Francisco 14 | summary: San Francisco is the cultural center of Northern California 15 | country: USA 16 | location: 17 | north: 37.73, 18 | east: -122.44 19 | population: 883305 20 | people: 21 | - firstname: Nils 22 | lastname: Knappmeier 23 | url: https://knappi.org 24 | resident-in: Darmstadt 25 | - firstname: Yehuda 26 | lastname: Katz 27 | url: https://yehudakatz.com/ 28 | resident-in: San Francisco 29 | - firstname: Carl 30 | lastname: Lerche 31 | - firstname: Alan 32 | lastname: Johnson 33 | -------------------------------------------------------------------------------- /src/ko/examples/_example-base-data.yaml: -------------------------------------------------------------------------------- 1 | # In order to make the examples in this site recognizable, we generally use this data as their basis. 2 | # If you want to create new example, you can use parts of this data along with your templates, partials and helpers. 3 | # You don't have to use the same JSON structure, but using the same entities (i.e. people, Darmstadt, San Francisco) 4 | # would be nice. If you have to use new data, please add it to this file. 5 | cities: 6 | - name: Darmstadt 7 | summary: Darmstadt is a city in Hesse, Germany 8 | country: Germany 9 | location: 10 | north: 49.87 11 | east: 8.64 12 | population: 158254 13 | - name: San Francisco 14 | summary: San Francisco is the cultural center of Northern California 15 | country: USA 16 | location: 17 | north: 37.73, 18 | east: -122.44 19 | population: 883305 20 | people: 21 | - firstname: Nils 22 | lastname: Knappmeier 23 | url: https://knappi.org 24 | resident-in: Darmstadt 25 | - firstname: Yehuda 26 | lastname: Katz 27 | url: https://yehudakatz.com/ 28 | resident-in: San Francisco 29 | - firstname: Carl 30 | lastname: Lerche 31 | - firstname: Alan 32 | lastname: Johnson 33 | -------------------------------------------------------------------------------- /src/zh/examples/_example-base-data.yaml: -------------------------------------------------------------------------------- 1 | # In order to make the examples in this site recognizable, we generally use this data as their basis. 2 | # If you want to create new example, you can use parts of this data along with your templates, partials and helpers. 3 | # You don't have to use the same JSON structure, but using the same entities (i.e. people, Darmstadt, San Francisco) 4 | # would be nice. If you have to use new data, please add it to this file. 5 | cities: 6 | - name: Darmstadt 7 | summary: Darmstadt is a city in Hesse, Germany 8 | country: Germany 9 | location: 10 | north: 49.87 11 | east: 8.64 12 | population: 158254 13 | - name: San Francisco 14 | summary: San Francisco is the cultural center of Northern California 15 | country: USA 16 | location: 17 | north: 37.73, 18 | east: -122.44 19 | population: 883305 20 | people: 21 | - firstname: Nils 22 | lastname: Knappmeier 23 | url: https://knappi.org 24 | resident-in: Darmstadt 25 | - firstname: Yehuda 26 | lastname: Katz 27 | url: https://yehudakatz.com/ 28 | resident-in: San Francisco 29 | - firstname: Carl 30 | lastname: Lerche 31 | - firstname: Alan 32 | lastname: Johnson 33 | -------------------------------------------------------------------------------- /src/.vitepress/components/PlaygroundLayout.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 43 | -------------------------------------------------------------------------------- /src/ko/api-reference/data-variables.md: -------------------------------------------------------------------------------- 1 | # `@data` 변수 2 | 3 | 다음 `@data` 변수들은 Handlebars와 내장 헬퍼에 의해 구현됩니다. 4 | 5 | ## `@root` 6 | 7 | 템플릿이 실행된 초기 컨텍스트입니다. 8 | 9 | ```handlebars 10 | {{#each array}} {{@root.foo}} {{/each}} 11 | ``` 12 | 13 | 명시적으로 수정되지 않는 한, 이 값은 페이지 렌더링의 모든 부분에서 일관되게 유지되므로, 깊은 매개변수가 상위 템플릿을 참 14 | 조할 수 없는 부분 템플릿 내에서도 사용할 수 있습니다. 15 | 16 | ## `@first` 17 | 18 | 반복의 첫 번째 단계에서 `each` 헬퍼에 의해 true로 설정됩니다. 19 | 20 | ```handlebars 21 | {{#each array}} {{#if @first}} First! {{/if}} {{/each}} 22 | ``` 23 | 24 | ## `@index` 25 | 26 | 현재 반복 단계의 0부터 시작하는 인덱스입니다. `each` 헬퍼에 의해 설정됩니다. 27 | 28 | ```handlebars 29 | {{#each array}} {{@index}} {{/each}} 30 | ``` 31 | 32 | ## `@key` 33 | 34 | 현재 반복 단계의 키 이름입니다. 객체를 반복할 때 `each` 헬퍼에 의해 설정됩니다. 35 | 36 | ```handlebars 37 | {{#each array}} {{@key}} {{/each}} 38 | ``` 39 | 40 | ## `@last` 41 | 42 | 반복의 마지막 단계에서 `each` 헬퍼에 의해 true로 설정됩니다. 43 | 44 | ```handlebars 45 | {{#each array}} {{#if @last}} Last :( {{/if}} {{/each}} 46 | ``` 47 | 48 | ## `@level` 49 | 50 | 로그 레벨을 할당합니다. 51 | 52 | ```js 53 | template({}, { data: { level: Handlebars.logger.WARN } }); 54 | ``` 55 | 56 | `Handlebars.logger.DEBUG`,`Handlebars.logger.INFO`,`Handlebars.logger.WARN` 또는 `Handlebars.logger.ERROR` 중 하나로설 57 | 정할 수 있습니다. 58 | 59 | 설정하게 되면, 로거는 출력에 `Handlebars.logger.level` 이상의 로그 레벨을 가진 메시지만 포함합니다. 기본 값은 60 | `Handlebars.logger.ERROR`입니다. 61 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/WorkspaceElement.vue: -------------------------------------------------------------------------------- 1 | 11 | 45 | -------------------------------------------------------------------------------- /src/guide/installation/when-to-use-handlebars.md: -------------------------------------------------------------------------------- 1 | # When (not) to use Handlebars? 2 | 3 | This section should give you an overview over the strengths and weaknesses of Handlebars. Ideally, it enables you to see 4 | if handlebars fits your use case and make an informed decision about choosing handlebars or not. 5 | 6 | ::: info A note on using Handlebars in the browser 7 | 8 | Handlebars is a pure rendering engine. It works well if you want to allow people to write templates for rendering 9 | HTML-pages, e-mails or markdown files. 10 | 11 | It has **no** built-in support for **event-handling**, accessing **backend-services** or incremental **DOM updates**. 12 | 13 | If you want to build a **single-page application** and you want to handle user-input, you should probably look for a 14 | framework like 15 | 16 | - [Angular](https://angular.io/) 17 | - [Aurelia](https://aurelia.io/) 18 | - [Ember](https://emberjs.com/) 19 | - [Inferno](https://infernojs.org/) 20 | - [Mithril](https://mithril.js.org/) 21 | - [Svelte](https://svelte.dev/) 22 | - [Ractive](https://ractive.js.org/) 23 | - [React](https://reactjs.org/) 24 | - [Vue](https://vuejs.org/) 25 | 26 | ::: 27 | 28 | ## Pro Handlebars 29 | 30 | - Handlebars is good for rendering in CLI-apps, non-HTML text content, server-side rendering of pure contents. 31 | - Handlebars has been ported to many programming languages (Java, Rust etc). 32 | 33 | ## Contra Handlebars 34 | 35 | - Handlebars is not good for fast (incremental) updates of the DOM, event-handling, frontend-backend communication. 36 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/execute-example.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { executeExample } from "./execute-example"; 3 | import Handlebars from "handlebars"; 4 | 5 | describe("the handlebars runner", () => { 6 | it("should run a simple example", () => { 7 | expect(runWithAppliedDefaultValues({ template: "{{name}}", input: '{ name: "Erwin"}' })).toEqual("Erwin"); 8 | }); 9 | 10 | it("should register partials", () => { 11 | expect( 12 | runWithAppliedDefaultValues({ 13 | template: "template {{>partial}}", 14 | partials: [{ name: "partial", content: "partial {{name}}" }], 15 | input: '{ name: "Erwin"}', 16 | }), 17 | ).toEqual("template partial Erwin"); 18 | }); 19 | 20 | it("should execute the preparation-script", () => { 21 | expect( 22 | runWithAppliedDefaultValues({ 23 | template: "{{loud name}}", 24 | // language=JavaScript 25 | preparationScript: 'Handlebars.registerHelper("loud", function (arg) { return arg.toUpperCase() })', 26 | input: '{ name: "Erwin"}', 27 | }), 28 | ).toEqual("ERWIN"); 29 | }); 30 | 31 | it("should throw parse errors", () => { 32 | expect(() => runWithAppliedDefaultValues({ template: "{{loud" })).toThrow(); 33 | }); 34 | }); 35 | 36 | function runWithAppliedDefaultValues(incompleteExample) { 37 | const exampleDefaults = { template: "", partials: [], preparationScript: "", input: "{}" }; 38 | return executeExample(Handlebars, { ...exampleDefaults, ...incompleteExample }); 39 | } 40 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/HighlightedCode.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 43 | 44 | 53 | 54 | 63 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/execute-one-after-another.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, vi } from "vitest"; 2 | import { executeOneAfterAnother } from "./execute-one-after-another"; 3 | 4 | describe("oneAfterAnother", () => { 5 | it("without: ensure call order with non-wrapped function", async () => { 6 | const mockFunction = vi.fn(); 7 | const promise1 = delay(100).then(() => mockFunction("a")); 8 | const promise2 = delay(50).then(() => mockFunction("b")); 9 | const promise3 = delay(0).then(() => mockFunction("c")); 10 | 11 | await Promise.all([promise1, promise2, promise3]); 12 | expect(mockFunction).toHaveBeenNthCalledWith(1, "c"); 13 | expect(mockFunction).toHaveBeenNthCalledWith(2, "b"); 14 | expect(mockFunction).toHaveBeenNthCalledWith(3, "a"); 15 | }); 16 | 17 | it("should resolve promises in sequence", async () => { 18 | const wrappedFunction = executeOneAfterAnother(delay); 19 | const mockFunction = vi.fn(); 20 | const promise1 = wrappedFunction(100).then(() => mockFunction("a")); 21 | const promise2 = wrappedFunction(50).then(() => mockFunction("b")); 22 | const promise3 = wrappedFunction(0).then(() => mockFunction("c")); 23 | 24 | await Promise.all([promise1, promise2, promise3]); 25 | expect(mockFunction).toHaveBeenNthCalledWith(1, "a"); 26 | expect(mockFunction).toHaveBeenNthCalledWith(2, "b"); 27 | expect(mockFunction).toHaveBeenNthCalledWith(3, "c"); 28 | }); 29 | }); 30 | 31 | async function delay(milliseconds) { 32 | return new Promise((resolve) => setTimeout(resolve, milliseconds)); 33 | } 34 | -------------------------------------------------------------------------------- /src/zh/api-reference/compilation.md: -------------------------------------------------------------------------------- 1 | # 编译和预编译 2 | 3 | ## `Handlebars.compile(template, options)` 4 | 5 | 编译一个模版以立即运行。 6 | 7 | ```js 8 | const template = Handlebars.compile("{{foo}}"); 9 | template({}); 10 | ``` 11 | 12 | 支持多种选项以更改模版的执行方式。 13 | 14 | ::: v-pre 15 | 16 | - `data`: 设置为 `false` 以终止 `@data` 跟踪。 17 | - `compat`: 设置为 `true` 以允许递归领域查找。 18 | - `knownHelpers`: 将已知在模版运行时会真实存在的助手代码列表 Hash 化。输入本参数会使编译器在一些情况下优化。内置助手代码已经在本列表里包含,但若设置本项为 19 | `false`,内置的助手代码可能会被忽视。 20 | - `knownHelpersOnly`: 设置为 `true` 以允许基于已知助手代码列表的进一步优化。 21 | - `noEscape`: 设置为 `true` 以避免 HTML 的内容转义。 22 | - `strict`: 在严格模式下运行。在这个模式下,模版将会对缺失参数抛出异常,而非静默忽略。同时,这种模式将会禁止逆操作,比如 23 | `{{^foo}}{{/foo}}`,除非领域被特意包含在源对象中。 24 | - `assumeObjects`: 在遍历路径时,不再检查对象是否存在。这是严格模式的子集,本子集在已知输入安全的情况下会生成最优模版。 25 | - `preventIndent`: 默认情况下,缩进的代码片段调用将会导致代码片段整体全部被缩进。在代码片段写入 `pre` 26 | 标签时,这会造成未预料到的结果。将本项设置成 `true` 可以避免这种自动缩进的功能。 27 | - `ignoreStandalone`: 当设置为 `true` 28 | 时,将不会去除单独的标签。在这种情况下,不在同一行的代码块和代码片段将不会去除本行里的空格。 29 | - `explicitPartialContext`: 对代码片段的上下文进行精确设置。当开启时,没有设置上下文的代码片段将会依托空对象执行。 30 | 31 | ::: 32 | 33 | ## `Handlebars.precompile(template, options)` 34 | 35 | 对一个模版进行预编译,这样可以直接将模版送到客户端并执行而不需要再编译。 36 | 37 | ```js 38 | var templateSpec = Handlebars.precompile("{{foo}}"); 39 | ``` 40 | 41 | 与 `Handlebars.compile` 方法的参数相同,并且额外的参数有: 42 | 43 | - `srcName`: 生成输入文件的源键值表。当运行时,返回的结构为 `{code, map}`。 `code` 包含模版的定义,`map` 包含源键值表。 44 | - `destName`: 可选,本参数可以与 `srcName` 一起使用以在生成源键值表的时候同时提供目标文件的名称。 45 | 46 | ## `Handlebars.template(templateSpec)` 47 | 48 | 设置一个已经被 `Handlebars.precompile` 预编译的模版。 49 | 50 | ```js 51 | var template = Handlebars.template(templateSpec); 52 | template({}); 53 | ``` 54 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/in-browser-example-executor/limit-waiting-time.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, vi } from "vitest"; 2 | import { limitWaitingTime, TimeoutError } from "./limit-waiting-time"; 3 | 4 | describe("limitWaitingTime", () => { 5 | it("should resolve if the given promise resolves", async () => { 6 | const timeoutCallback = vi.fn(); 7 | const testPromise = delay(100).then(() => "a"); 8 | 9 | const resultPromise = limitWaitingTime(testPromise, 200, timeoutCallback); 10 | 11 | await expect(resultPromise).resolves.toEqual("a"); 12 | expect(timeoutCallback).not.toHaveBeenCalled(); 13 | }); 14 | 15 | it("should reject the promise after a timeout", async () => { 16 | const timeoutCallback = vi.fn(); 17 | const testPromise = delay(200).then(() => "a"); 18 | 19 | const resultPromise = limitWaitingTime(testPromise, 100, timeoutCallback); 20 | 21 | await expect(resultPromise).rejects.toEqual(new TimeoutError("Timed out after 100ms")); 22 | expect(timeoutCallback).toHaveBeenCalledTimes(1); 23 | }); 24 | 25 | it("should reject if the given promise reject before the timeout, without calling the timeoutCallback ", async () => { 26 | const timeoutCallback = vi.fn(); 27 | const testPromise = delay(100).then(() => { 28 | throw new Error("b"); 29 | }); 30 | 31 | const resultPromise = limitWaitingTime(testPromise, 200, timeoutCallback); 32 | 33 | await expect(resultPromise).rejects.toEqual(new Error("b")); 34 | expect(timeoutCallback).not.toHaveBeenCalled(); 35 | }); 36 | }); 37 | 38 | async function delay(milliseconds) { 39 | return new Promise((resolve) => setTimeout(resolve, milliseconds)); 40 | } 41 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/codemirror-languages/handlebars.js: -------------------------------------------------------------------------------- 1 | import { parser } from "./handlebars.parser.js"; 2 | import { LRLanguage, LanguageSupport } from "@codemirror/language"; 3 | import { html, htmlLanguage } from "@codemirror/lang-html"; 4 | import { styleTags, tags as t } from "@lezer/highlight"; 5 | import { parseMixed } from "@lezer/common"; 6 | 7 | let parserWithMetadata = parser.configure({ 8 | strict: false, 9 | props: [ 10 | styleTags({ 11 | Name: t.name, 12 | Prop: t.name, 13 | Array: t.name, 14 | Context: t.name, 15 | BlockParam: t.name, 16 | Bool: t.bool, 17 | Number: t.number, 18 | This: t.className, 19 | "BlockHelper As DataVariable PartialBlock Else BlockHelperClose": t.className, 20 | Partial: t.className, 21 | InlinePartial: t.className, 22 | String: t.string, 23 | Comment1: t.blockComment, 24 | Comment2: t.blockComment, 25 | "# > | @": t.annotation, 26 | '"/"': t.annotation, 27 | "=": t.operator, 28 | "MustacheOpen MustacheClose {{{ }}} {{{{ }}}}": [t.brace, t.bool], 29 | "( ) [ ]": t.bracket, 30 | }), 31 | ], 32 | wrap: parseMixed((node) => { 33 | return node.type.isTop 34 | ? { 35 | parser: htmlLanguage.parser, 36 | overlay: (node) => node.name === "Text", 37 | } 38 | : null; 39 | }), 40 | }); 41 | 42 | const language = LRLanguage.define({ 43 | name: "handlebars", 44 | parser: parserWithMetadata, 45 | languageData: { 46 | commentTokens: { block: { open: "{{!", close: "}}" } }, 47 | }, 48 | }); 49 | 50 | export function handlebars() { 51 | return new LanguageSupport(language, [html().support]); 52 | } 53 | -------------------------------------------------------------------------------- /src/api-reference/data-variables.md: -------------------------------------------------------------------------------- 1 | # `@data` variables 2 | 3 | The following `@data` variables are implemented by Handlebars and its builtin helpers. 4 | 5 | ## `@root` 6 | 7 | Initial context with which the template was executed. 8 | 9 | ```handlebars 10 | {{#each array}} {{@root.foo}} {{/each}} 11 | ``` 12 | 13 | Unless explicitly modified, this value is consistent across all portions of the page rendering, meaning it can be used 14 | within partials where depthed parameters are unable to reference their parent templates. 15 | 16 | ## `@first` 17 | 18 | Set to true by the `each` helper for the first step of iteration. 19 | 20 | ```handlebars 21 | {{#each array}} {{#if @first}} First! {{/if}} {{/each}} 22 | ``` 23 | 24 | ## `@index` 25 | 26 | Zero-based index for the current iteration step. Set by the `each` helper. 27 | 28 | ```handlebars 29 | {{#each array}} {{@index}} {{/each}} 30 | ``` 31 | 32 | ## `@key` 33 | 34 | Key name for the current iteration step. Set by the `each` helper when iterating over objects. 35 | 36 | ```handlebars 37 | {{#each array}} {{@key}} {{/each}} 38 | ``` 39 | 40 | ## `@last` 41 | 42 | Set to true by the `each` helper for the last step of iteration. 43 | 44 | ```handlebars 45 | {{#each array}} {{#if @last}} Last :( {{/if}} {{/each}} 46 | ``` 47 | 48 | ## `@level` 49 | 50 | Assigned log level. 51 | 52 | ```js 53 | template({}, { data: { level: Handlebars.logger.WARN } }); 54 | ``` 55 | 56 | May be set to one of `Handlebars.logger.DEBUG` , `Handlebars.logger.INFO` , `Handlebars.logger.WARN` , or 57 | `Handlebars.logger.ERROR` 58 | 59 | When set, the logger will include in its output only messages with a log level of `Handlebars.logger.level` or higher. 60 | The default value is `Handlebars.logger.ERROR`. 61 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/CodeEditor.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 57 | 58 | 66 | -------------------------------------------------------------------------------- /src/zh/guide/hooks.md: -------------------------------------------------------------------------------- 1 | # 钩子 2 | 3 | 你可以在几个地方使用钩子挂接到 Handlebars 的函数调用。 4 | 5 | ## helperMissing 6 | 7 | 当 Mustache 或表达式是如下情况时钩子会被调用: 8 | 9 | - Mustache 表达式不是一个已经注册的助手代码,**并且** 10 | - 不是当前上下文的计算属性。 11 | 12 | 你可以通过注册 `helperMissing` 助手代码为这些情况添加自定义处理: 13 | 14 | 15 | 16 | 17 | 18 | 与任何自定义助手代码或块助手代码一样,该助手代码接收相同的参数和选项(`hash`,`name`等)。 `option.name` 19 | 是被调用的助手代码的名称。 20 | 21 | ### 默认行为 22 | 23 | 如果没有参数传递给 Mustache,则默认行为是不执行任何操作并忽略整个表达式或代码块: 24 | 25 | 26 | 27 | 28 | 29 | 30 | 如果有参数传递给 Mustache,则 Handlebars 将引发异常: 31 | 32 | 33 | 34 | 35 | 36 | 37 | ## blockHelperMissing 38 | 39 | 遇到如下情况时,钩子将会被调用: 40 | 41 | - 代码块表达式尝试调用未注册的助手代码, 42 | - 但是这个助手代码的名称与当前计算上下文中的某个属性相同。 43 | 44 | 你可以通过注册一个名为 `blockHelperMissing` 的助手代码来处理这种情况。 45 | 46 | 47 | 48 | 49 | 50 | ### 默认行为 51 | 52 | 钩子将在当前上下文中使用已解析的属性值作为参数进行调用,并且将 `options.name` 字段设置为属性的名称。 53 | 54 | 如果钩子没有被覆盖,则默认实现将模仿 Mustache 的行为:只调用代码块。 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/.vitepress/components/TryoutIcon.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 45 | -------------------------------------------------------------------------------- /src/ko/api-reference/compilation.md: -------------------------------------------------------------------------------- 1 | # (사전) 컴파일 2 | 3 | ## `Handlebars.compile(template, options)` 4 | 5 | 템플릿을 컴파일하여 즉시 실행할 수 있게 합니다. 6 | 7 | ```js 8 | const template = Handlebars.compile("{{foo}}"); 9 | template({}); 10 | ``` 11 | 12 | 템플릿 실행 방식을 변경하는 다양한 옵션을 지원합니다. 13 | 14 | ::: v-pre 15 | 16 | - `data`: `@data` 추적을 비활성화하려면 false로 설정합니다. 17 | - `compat`: 재귀 필드 조회를 활성화하려면 true로 설정합니다. 18 | - `knownHelpers`: 템플릿 실행 시 존재하는 것으로 알려진 헬퍼 목록을 포함하는 해시입니다. 이를 전달하면 컴파일러가 여러 19 | 경우를 최적화할 수 있습니다. 내장 헬퍼는 이 목록에 자동으로 포함되며 값을 `false`로 설정하여 생략할 수 있습니다. 20 | - `knownHelpersOnly`: 알려진 헬퍼 목록을 기반으로 추가 최적화를 허용하려면 true로 설정합니다. 21 | - `noEscape`: HTML 이스케이프를 하지 않으려면 true로 설정합니다. 22 | - `strict`: 엄격 모드에서 실행합니다. 이 모드에서는 누락된 필드를 묵인하지 않고 예외를 발생시킵니다. 이로 인해 23 | `{{^foo}}{{/foo}}`와 같은 역 연산이 데이터 소스 객체에 명시적으로 포함되지 않으면 비활성화됩니다. 24 | - `assumeObjects`: 경로를 탐색할 때 객체 존재 여부 확인을 제거합니다. 이는 데이터 입력이 안전하다고 알려진 경우 최적화된 25 | 템플릿을 생성하는 엄격 모드의 하위 집합입니다. 26 | - `preventIndent`: 기본적으로 들여쓰기된 부분 템플릿 호출은 전체 부분 템플릿 출력이 동일한 양으로 들여쓰기되게 합니다. 27 | 이는 부분 템플릿이 `pre` 태그를 작성할 때 예기치 않은 동작을 초래할 수 있습니다. 이 옵션을 `true`로 설정하면 자동 들여 28 | 쓰기 기능이 비활성화됩니다. 29 | - `ignoreStandalone`: 설정 시 독립 태그 제거를 비활성화합니다. 설정하면 블록과 부분 템플릿이 각자 줄에 있을 때 해당 줄의 30 | 공백을 제거하지 않습니다. 31 | - `explicitPartialContext`: 부분 템플릿의 암시적 컨텍스트를 비활성화합니다. 활성화되면 컨텍스트 값을 전달받지 않은 부분 32 | 템플릿은 빈 객체를 대상으로 실행됩니다. 33 | 34 | ::: 35 | 36 | ## `Handlebars.precompile(template, options)` 37 | 38 | 주어진 템플릿을 사전 컴파일하여 클라이언트로 전송한 후 컴파일 없이 실행할 수 있게 합니다. 39 | 40 | ```js 41 | var templateSpec = Handlebars.precompile("{{foo}}"); 42 | ``` 43 | 44 | `Handlebars.compile` 메서드와 동일한 옵션 매개변수를 지원합니다. 추가적으로 다음을 전달할 수 있습니다: 45 | 46 | - `srcName`: 입력 파일의 소스 맵을 생성하기 위해 전달됩니다. 이렇게 실행되면 반환 구조는 `{code, map}`이며, `code`에는 47 | 템플릿 정의가 포함되고 `map`에는 소스 맵이 포함됩니다. 48 | - `destName`: 소스 맵을 생성할 때 `srcName`과 함께 사용되는 선택적 매개변수로, 대상 파일 이름을 제공합니다. 49 | 50 | ## `Handlebars.template(templateSpec)` 51 | 52 | `Handlebars.precompile`로 사전 컴파일된 템플릿을 설정합니다. 53 | 54 | ```js 55 | var template = Handlebars.template(templateSpec); 56 | template({}); 57 | ``` 58 | -------------------------------------------------------------------------------- /src/zh/guide/installation/integrations.md: -------------------------------------------------------------------------------- 1 | # 集成 2 | 3 | 以下软件包在不同的环境中集成了 Handlebars。这些软件包 **并非** 由 Handlebars 团队负责。 4 | 5 | 有多个 Webpack 插件,可让你在 Webpack 环境中使用 Handlebars。 6 | 7 | ## Webpack: handlebars-loader 8 | 9 | [handlebars-loader](https://github.com/pcardune/handlebars-loader) 允许你导入 [预编译](./precompilation.html) 10 | 模板。只需将你的 handlebars-template 写入 `template.handlebars` 文件中,然后使用 11 | 12 | ```js 13 | const compiledTemplate = require("./template.handlebars"); 14 | ``` 15 | 16 | 或是 17 | 18 | ```js 19 | import compiledTemplate from "./template.handlebars"; 20 | ``` 21 | 22 | ## Webpack: handlebars-webpack-plugin 23 | 24 | [handlebars-webpack-plugin](https://github.com/sagold/handlebars-webpack-plugin) 使用 Handlebars 构建你的静态 HTML 页面 25 | 26 | ## Webpack: html-bundler-webpack-plugin 27 | 28 | [html-bundler-webpack-plugin](https://github.com/webdiscus/html-bundler-webpack-plugin) 支持使用包括 29 | [Handlebars](https://github.com/webdiscus/html-bundler-webpack-plugin#using-the-handlebars) 30 | 在内的几种模板引擎来渲染模板,并将样式和脚本打包到生成的 HTML 文件中。 31 | 32 | ## Babel: handlebars-inline-precompile 33 | 34 | [babel-plugin-handlebars-inline-precompile](https://github.com/jamiebuilds/babel-plugin-handlebars-inline-precompile) 35 | 提供了预编译的 Handlebars 模板,这些模板在 JavaScript 源代码中作为模板文本提供: 36 | 37 | ```js 38 | import hbs from "handlebars-inline-precompile"; 39 | const compiledTemplate = hbs`{{name}}`; 40 | ``` 41 | 42 | 请参阅包文档以获取设置说明。 43 | 44 | ## Browserify: hbsfy 45 | 46 | [hbsfy](https://www.npmjs.com/package/hbsfy) 包可让你在浏览器中导入预编译的模板环境: 47 | 48 | ```js 49 | const compiledTemplate = require("./template.handlebars"); 50 | ``` 51 | 52 | ## 包:parcel-plugin-handlebars 53 | 54 | 这里有一个较老的插件包: https://www.npmjs.com/package/parcel-plugin-handlebars 55 | 56 | 但是你应该使用这些 forks 里面的其中一个,因为它们较新: https://www.npmjs.com/search?q=parcel-plugin-handlebars 57 | 58 | 最新的一个包是: https://www.npmjs.com/package/@inventory/parcel-plugin-handlebars 59 | 60 | ## 包:parcel-plugin-handlebars-precompile 61 | 62 | TODO: 在此填写 63 | 64 | https://www.npmjs.com/package/parcel-plugin-handlebars-precompile 65 | -------------------------------------------------------------------------------- /src/ko/guide/hooks.md: -------------------------------------------------------------------------------- 1 | # 훅(Hooks) 2 | 3 | Handlebars 함수 호출에 훅을 걸 수 있는 여러 지점이 있습니다. 4 | 5 | ## helperMissing 6 | 7 | 이 훅은 머스태시 또는 블록 문이 아래와 같은 경우 호출됩니다. 8 | 9 | - 단순 머스태시 표현식이 등록된 도우미가 **아닐 때** 10 | - 현재 평가 컨텍스트의 속성이 아닐 때 11 | 12 | 이러한 상황에 대한 사용자 정의 처리를 추가하려면 `helperMissing` 도우미를 등록할 수 있습니다. 13 | 14 | 15 | 16 | 17 | 18 | 이 도우미는 모든 사용자 정의 도우미 또는 블록 도우미와 동일한 인수 및 옵션(`hash`, `name` 등)을 받습니다. 19 | `options.name`은 호출된 도우미의 이름입니다. 20 | 21 | ### 기본 동작 22 | 23 | 머스태시에 매개 변수가 전달되지 않으면 기본 동작은 아무것도 하지 않고 전체 머스태시 표현식 또는 전체 블록을 무시하는 것 24 | 입니다: 25 | 26 | 27 | 28 | 29 | 30 | 31 | 머스태시에 매개 변수가 전달되면 Handlebars는 예외를 발생시킵니다: 32 | 33 | 34 | 35 | 36 | 37 | 38 | ## blockHelperMissing 39 | 40 | 이 훅은 다음과 같은 경우 호출됩니다: 41 | 42 | - 블록 표현식이 등록되지 않은 도우미를 호출하지만 43 | - 그 이름이 현재 평가 컨텍스트의 속성과 일치하는 경우 44 | 45 | 이 상황을 처리하려면 blockHelperMissing이라는 헬퍼를 등록할 수 있습니다. 46 | 47 | 48 | 49 | 50 | 51 | ### 기본 동작 52 | 53 | 훅은 현재 컨텍스트에서 해결된 속성 값과 `options.name` 필드가 속성 이름으로 설정된 상태로 호출됩니다. 54 | 55 | 훅이 재정의되지 않으면 기본 구현은 Mustache의 동작을 모방하여 블록을 호출합니다. 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/zh/api-reference/utilities.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: [1, 3] 3 | --- 4 | 5 | # 实用方法 6 | 7 | ## 助手代码实用方法 8 | 9 | 这些方法会帮你更轻松地实现自定义助手代码。 10 | 11 | ### `Handlebars.SafeString(string)` 12 | 13 | 防止 `string` 在模版渲染时转义。 14 | 15 | ```js 16 | new Handlebars.SafeString("
    HTML Content!
    "); 17 | ``` 18 | 19 | 当构建将会被标记为安全的字符串时,为安全起见,任何外部内容都应该使用 `Handlebars.escapeExpression` 方法转义。 20 | 21 | ### `Handlebars.escapeExpression(string)` 22 | 23 | ::: v-pre 24 | 25 | HTML 转义输入的字符串,使得字符串可以安全地在 HTML 内容中渲染为文字。 26 | 27 | ```js 28 | Handlebars.Utils.escapeExpression(string); 29 | ``` 30 | 31 | 将字符串值里的`&`, `<`, `>`, `"`, `'`, `` ` ``, `=` 用 HTML 实体的等效值替换。`SafeString` 的值保持不变。 32 | 33 | 除了 `{{{` 表达式之外的表达式都将被本方法处理。为了防止可能的代码注入,帮助函数也应该在返回 HTML 内容时通过一个 34 | `SafeString` 的实例来使用本函数。 35 | 36 | 本函数是 `Handlebars.Utils.escapeExpression` 的别名。 37 | 38 | ::: 39 | 40 | ### `Handlebars.createFrame(data)` 41 | 42 | 由块助手代码使用以创建子数据对象。 43 | 44 | ```js 45 | if (options.data) { 46 | var data = Handlebars.createFrame(options.data); 47 | data.foo = "bar"; 48 | options.data = data; 49 | } 50 | ``` 51 | 52 | 更改数据状态的助手代码应会同时创建一个新的框架以将它们自己隔离并且避免和任何父程序的状态冲突。通常来说,在执行时,对每个助手代码来说只有一个框架需要被创建。比如,`each` 53 | 迭代器创建一个会被所有子执行程序应用的框架。 54 | 55 | ## General Utilities 56 | 57 | Handlebars 提供了一大批由 `Handlebars.Utils` 对象暴露的应用函数。 58 | 59 | ### `Handlebars.Utils.isEmpty(value)` 60 | 61 | 判断给定的值是否为空。 62 | 63 | Handlebars.Utils.isEmpty(value) 64 | 65 | 以上函数被内建的 `if` 与 `with` 助手代码应用以控制执行流。Handlebars 对于「空」的定义如下: 66 | 67 | - 长度为 0 的数组 68 | - 除了 0 以外的虚值 69 | 70 | 以上是为了和 [Mustache behavior](http://mustache.github.io/mustache.5.html#Sections) 匹配。 71 | 72 | ### `Handlebars.Utils.extend(obj, value)` 73 | 74 | 简单的应用函数,用于使用 `value` 里定义的所有键来增强 `obj` 。 75 | 76 | Handlebars.Utils.extend(foo, {bar: true}) 77 | 78 | 将会将 `foo` 对象内的键 `bar` 对应的值设定为 `true`。 79 | 80 | ### `Handlebars.Utils.toString(obj)` 81 | 82 | 通用的 `toString` 方法。 83 | 84 | ### `Handlebars.Utils.isArray(obj)` 85 | 86 | 判断对象是否为数组。 87 | 88 | ### `Handlebars.Utils.isFunction(obj)` 89 | 90 | 判断对象是否为函数。 91 | 92 | ### `Handlebars.log(level, message)` 93 | 94 | 被 `log` 助手代码使用的输出程序。 95 | 96 | 可能会在需要时被重载。 97 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/example-parser.js: -------------------------------------------------------------------------------- 1 | import { prettify } from "./prettify"; 2 | import { executeExample } from "./execute-example"; 3 | import Handlebars from "handlebars"; 4 | 5 | export class ExampleParser { 6 | constructor({ template, input, partials, preparationScript }) { 7 | this.normalizedExample = { 8 | template: useDefaultValueIfMissing(template, ""), 9 | input: useDefaultValueIfMissing(input, null), 10 | partials: useDefaultValueIfMissing(partials, {}), 11 | preparationScript: useDefaultValueIfMissing(preparationScript, ""), 12 | }; 13 | } 14 | 15 | /** 16 | * Entrypoint for parsing 17 | */ 18 | async parse() { 19 | const parsedExample = { 20 | template: this.normalizedExample.template, 21 | partials: this._partialsAsNameContentArray(), 22 | preparationScript: this.normalizedExample.preparationScript, 23 | input: (await prettify(this.normalizedExample.input)) || null, 24 | }; 25 | 26 | return this._executeAndBuildExample(parsedExample); 27 | } 28 | 29 | _partialsAsNameContentArray() { 30 | return Object.keys(this.normalizedExample.partials).map((partialName) => { 31 | return { 32 | name: partialName, 33 | content: this.normalizedExample.partials[partialName], 34 | }; 35 | }); 36 | } 37 | 38 | _executeAndBuildExample(parsedExample) { 39 | try { 40 | const output = executeExample(Handlebars, parsedExample); 41 | return { ...parsedExample, output, error: null }; 42 | } catch (error) { 43 | const errorWithEnumerableProperties = this._handlebarsExecutionErrorWithEnumerableProperties(error); 44 | return { ...parsedExample, output: null, error: errorWithEnumerableProperties }; 45 | } 46 | } 47 | 48 | _handlebarsExecutionErrorWithEnumerableProperties(error) { 49 | if (error == null) { 50 | return null; 51 | } 52 | return { 53 | message: error.message, 54 | stack: error.stack, 55 | }; 56 | } 57 | } 58 | 59 | function useDefaultValueIfMissing(value, defaultValue) { 60 | return value == null ? defaultValue : value; 61 | } 62 | -------------------------------------------------------------------------------- /src/zh/guide/installation/precompilation.md: -------------------------------------------------------------------------------- 1 | # 预编译模板 2 | 3 | 6 | 7 | 使用 Handlebars 预编译器,你可以预编译 Handlebars 模板以节省客户端时间并减少 Handlebars 库所需的运行时大小。 8 | 9 | ## 入门 10 | 11 | 首先,你需要 _Node.js 和 npm_ 。转到 [https://nodejs.org/en/download/](https://nodejs.org/en/download/) 12 | 了解如何在你的操作系统上执行此操作。 13 | 14 | 接下来,安装 Handlebars npm 软件包,其中包含了预编译器。 15 | 16 | ```bash 17 | npm install -g handlebars 18 | ``` 19 | 20 | 创建一个文件 `example.handlebars` 来包含模板: 21 | 22 | <<< @/snippets/precompilation/example.handlebars 23 | 24 | 运行预编译器。 25 | 26 | ```bash 27 | handlebars example.handlebars -f example.precompiled.js 28 | ``` 29 | 30 | 引用 Handlebars 运行时和预编译的 JavaScript。 31 | 32 | <<< @/snippets/precompilation/index.html 33 | 34 | 也可以在 [安装页面](index.md#downloading-handlebars) 上下载运行时。 35 | 36 | ## 优化 37 | 38 | 因为你在预编译模板,所以你还可以对编译器进行多种优化。首先你可以指定一个已知 helper 的列表: 39 | 40 | ```bash 41 | handlebars -f -k each -k if -k unless 42 | ``` 43 | 44 | Handlebars 编译器将优化对这些 helper 的访问以提高性能。当所有 helper 都在编译时时候,`--knownOnly` 45 | 选项提供了最小的生成代码,也提供了最快的执行速度。 46 | 47 | ## 用法 48 | 49 | ```txt-vue 50 | {{ handlebars.cliHelp }} 51 | ``` 52 | 53 | 如果使用预编译器的 normal 模式,则预编译结果将存储到 `Handlebars.templates` 54 | 对象下对应的模板名称(不带扩展名)的对象中。这些预编译模板可以以和普通模板相同的方式执行。如果使用 simple 模式,预编译器将生成一个 JavaScript 方法。要执行此方法,必须将其传递给 55 | `Handlebars.template()` 方法,生成的对象也可以以相同的方式使用。 56 | 57 | ## 在 Node.js 中预编译模板 58 | 59 | 如果你希望从 Node.js 内部预编译模板而无需从命令行调用 Handlebars,则可以使用 Handlebars.precompile 完成。将此函数的字符串结果传递给你的前端,前端即可使用 Handlebars.template 来解析。 60 | 61 | <<< @/snippets/precompilation/precompile-in-nodejs.js 62 | 63 | 输出如下: 64 | 65 | <<< @/snippets/precompilation/precompile-in-nodejs.output.js 66 | 67 | 在客户端,你将通过以下方式使用 JavaScript。 68 | 69 | ```js 70 | Handlebars.partials["test1"] = Handlebars.template({ 71 | /** 在此处插入编译的输出 **/ 72 | }); 73 | ``` 74 | 75 | 最后,你可以在 JavaScript 中动态引用这些模板。 76 | 77 | ```js 78 | var result = Handlebars.partials["test1"]({ name: "yourname" }); 79 | // 使用得到的 result 80 | ``` 81 | 82 | ## 集成 83 | 84 | 一些 npm 包可用于将 Handlebars 预编译器集成到你的构建系统中(如 Webpack, Browserify ...)。参阅 集成 页面: 85 | 86 | [了解更多:集成](integrations.md) 87 | -------------------------------------------------------------------------------- /src/zh/api-reference/runtime.md: -------------------------------------------------------------------------------- 1 | # Handlebars 运行时 2 | 3 | ## `Handlebars.registerPartial(name, partial)` 4 | 5 | 注册可以被当前环境内任意模版访问的代码片段。 6 | 7 | ```js 8 | Handlebars.registerPartial("foo", partial); 9 | ``` 10 | 11 | 同时支持一次性注册多个代码片段。 12 | 13 | ```js 14 | Handlebars.registerPartial({ foo: partial, bar: partial }); 15 | ``` 16 | 17 | 如果导入整个库,代码片段的值可能是按需编译的字符串。如果只是在运行时导入,代码片段必须为通过 `Handlebars.template` 18 | 预编译过的模版。 19 | 20 | ## `Handlebars.unregisterPartial(name)` 21 | 22 | 注销之前注册过的代码片段。 23 | 24 | ```js 25 | Handlebars.unregisterPartial("foo"); 26 | ``` 27 | 28 | ## `Handlebars.registerHelper(name, helper)` 29 | 30 | 注册可以被当前环境中任意模版访问的助手代码。 31 | 32 | ```js 33 | Handlebars.registerHelper("foo", function () {}); 34 | ``` 35 | 36 | 支持同时注册多个助手代码。 37 | 38 | ```js 39 | Handlebars.registerHelper({ foo: function () {}, bar: function () {} }); 40 | ``` 41 | 42 | ## `Handlebars.unregisterHelper(name)` 43 | 44 | 注销之前的注册的助手代码。 45 | 46 | ```js 47 | Handlebars.unregisterHelper("foo"); 48 | ``` 49 | 50 | ## `Handlebars.registerDecorator(name, helper)` (deprecated) 51 | 52 | ::: warning 弃用警告 53 | 54 | 自定义装饰器已经被废弃,并且可能会在 Handlebars 的下个主要版本消失。自定义装饰器关联了非常多的内部 API,而这会对导入其他语言造成不便,并且代码也变得难以维护。 55 | 56 | ::: 57 | 58 | 注册一个可以被环境内任意模版访问的装饰器。 59 | 60 | ```js 61 | Handlebars.registerDecorator("foo", function () {}); 62 | ``` 63 | 64 | 支持同时注册多个装饰器。 65 | 66 | ```js 67 | Handlebars.registerDecorator({ foo: function () {}, bar: function () {} }); 68 | ``` 69 | 70 | ## `Handlebars.unregisterDecorator(name)` 71 | 72 | 注销一个之前注册的装饰器。 73 | 74 | ```js 75 | Handlebars.unregisterDecorator("foo"); 76 | ``` 77 | 78 | ## `Handlebars.create()` 79 | 80 | 创建一个独立的 Handlebars 环境。 81 | 82 | ```js 83 | var OtherHandlebars = Handlebars.create(); 84 | ``` 85 | 86 | 每个环境都有它独立的助手代码和代码片段。本函数只在需要独立的助手代码或代码片段时有用。通常来说,`Handlebars` 87 | 环境已经足够。 88 | 89 | 在当前环境中创建的模版属于当前环境。这意味着如果想要在多个环境中运行当前模版,必须用 `Handlebars.template` 90 | 对每个环境重新编译或重新构造。以上描述对于代码片段也是一样的。 91 | 92 | ## `Handlebars.noConflict()` 93 | 94 | 从全局命名域中删除当前的 Handlebars 实例,重置全局 `Handlebars` 变量。 95 | 96 | ```js 97 | var myHandlebars = Handlebars.noConflict(); 98 | ``` 99 | 100 | 允许在无视版本冲突的情况下同时应用独立版本的库。 101 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "2.0.0", 4 | "description": "The handlebars documentation site", 5 | "license": "MIT", 6 | "private": true, 7 | "type": "module", 8 | "scripts": { 9 | "prepare": "husky", 10 | "docs:dev": "vitepress dev src", 11 | "docs:build": "vitepress build src", 12 | "docs:preview": "vitepress preview src", 13 | "format": "prettier --write \"src/**/*.{js,css,json,md,vue}\"", 14 | "lint": "prettier --check \"src/**/*.{js,css,json,md,vue}\"", 15 | "lint-staged": "lint-staged", 16 | "test": "vitest", 17 | "codemirror:lang-handlebars": "lezer-generator src/.vitepress/components/playground/lib/codemirror-languages/handlebars.grammar -o src/.vitepress/components/playground/lib/codemirror-languages/handlebars.parser.js", 18 | "codemirror:lang-js-object": "lezer-generator src/.vitepress/components/playground/lib/codemirror-languages/js-object.grammar -o src/.vitepress/components/playground/lib/codemirror-languages/js-object.parser.js" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/handlebars-lang/docs.git" 23 | }, 24 | "bugs": { 25 | "url": "https://github.com/handlebars-lang/docs/issues" 26 | }, 27 | "homepage": "https://github.com/handlebars-lang/docs#readme", 28 | "dependencies": { 29 | "@codemirror/commands": "^6.8.0", 30 | "@codemirror/lang-html": "^6.4.9", 31 | "@codemirror/lang-javascript": "^6.2.3", 32 | "@codemirror/language": "^6.10.8", 33 | "@codemirror/theme-one-dark": "^6.1.2", 34 | "@codemirror/view": "^6.36.4", 35 | "@lezer/common": "^1.2.3", 36 | "@lezer/highlight": "^1.2.1", 37 | "codemirror": "^6.0.1", 38 | "handlebars": "^4.7.8", 39 | "json5": "^2.2.3", 40 | "p-debounce": "^5.0.0", 41 | "prettier": "^3.5.0", 42 | "semver": "^7.7.1", 43 | "shiki": "^3.1.0", 44 | "vue": "^3.5.13" 45 | }, 46 | "devDependencies": { 47 | "@lezer/generator": "^1.7.2", 48 | "@lezer/lr": "^1.4.2", 49 | "husky": "^9.1.7", 50 | "lint-staged": "^16.2.6", 51 | "vite-plugin-static-copy": "^3.1.4", 52 | "vitepress": "^1.6.3", 53 | "vitest": "^3.0.5" 54 | }, 55 | "lint-staged": { 56 | "*.{js,css,json,md,vue}": "npm run format" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ko/guide/installation/integrations.md: -------------------------------------------------------------------------------- 1 | # 통합 2 | 3 | 다음 패키지들은 다양한 환경에서 Handlebars를 통합합니다. 이 패키지들은 Handlebars 팀에 의해 **공식으로 지원되지 않습니 4 | 다**. 5 | 6 | Webpack 환경에서 Handlebars를 사용할 수 있게 해주는 여러 Webpack 플러그인이 있습니다. 7 | 8 | ## Webpack: handlebars-loader 9 | 10 | [handlebars-loader](https://github.com/pcardune/handlebars-loader) 는 [precompiled](./precompilation.html) 템플릿을 11 | import 할 수 있게 해줍니다. handlebars 템플릿을 `template.handlebars` 파일에 작성하세요. 그리고 12 | 13 | ```js 14 | const compiledTemplate = require("./template.handlebars"); 15 | ``` 16 | 17 | 또는 18 | 19 | ```js 20 | import compiledTemplate from "./template.handlebars"; 21 | ``` 22 | 23 | 를 사용해 임포트하세요. 24 | 25 | ## Webpack: handlebars-webpack-plugin 26 | 27 | [handlebars-webpack-plugin](https://github.com/sagold/handlebars-webpack-plugin)는 애플리케이션을 컴파일할 때 Handlebars 28 | 를 사용하여 HTML 페이지를 정적으로 빌드합니다. 29 | 30 | ## Webpack: html-bundler-webpack-plugin 31 | 32 | [html-bundler-webpack-plugin](https://github.com/webdiscus/html-bundler-webpack-plugin) 은 33 | [Handlebars를 포함한](https://github.com/webdiscus/html-bundler-webpack-plugin#using-the-handlebars) 다양한 템플릿 엔진 34 | 을사용하여 템플릿을 렌더링하고 생성된 HTML에 스타일 및 스크립트를 번들링합니다. 35 | 36 | ## Babel: handlebars-inline-precompile 37 | 38 | [babel-plugin-handlebars-inline-precompile](https://github.com/jamiebuilds/babel-plugin-handlebars-inline-precompile) 39 | JavaScript 소스 코드에서 템플릿 리터럴로 제공되는 Handlebars 템플릿을 사전 컴파일합니다: 40 | 41 | ```js 42 | import hbs from "handlebars-inline-precompile"; 43 | const compiledTemplate = hbs`{{name}}`; 44 | ``` 45 | 46 | 설치 지침은 패키지의 문서를 참조하십시오. 47 | 48 | ## Browserify: hbsfy 49 | 50 | [hbsfy](https://www.npmjs.com/package/hbsfy) 패키지를 사용하면 browserify 환경에서 사전 컴파일된 템플릿을 가져올 수 있습 51 | 니다: 52 | 53 | ```js 54 | const compiledTemplate = require("./template.handlebars"); 55 | ``` 56 | 57 | ## Parcel:parcel-plugin-handlebars 58 | 59 | Parcel용 옛 플러그인이 있습니다 : https://www.npmjs.com/package/parcel-plugin-handlebars 60 | 61 | 그러나 더 최신 상태인 여러 패키지 중 하나를 사용하는 것이 좋습니다: 62 | https://www.npmjs.com/search?q=parcel-plugin-handlebars 63 | 64 | 가장 최신 버전: https://www.npmjs.com/package/@inventory/parcel-plugin-handlebars 65 | 66 | ## Parcel:parcel-plugin-handlebars-precompile 67 | 68 | TODO: 여기에 텍스트를 작성하세요 69 | 70 | https://www.npmjs.com/package/parcel-plugin-handlebars-precompile 71 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/WorkspaceElementDecorator.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 56 | 57 | 94 | -------------------------------------------------------------------------------- /src/ko/api-reference/utilities.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: [1, 3] 3 | --- 4 | 5 | # 유틸리티 함수 6 | 7 | ## 헬퍼 유틸리티 8 | 9 | 이 메서드는 사용자 정의 헬퍼를 구현할 때 유용합니다. 10 | 11 | ### `Handlebars.SafeString(string)` 12 | 13 | 템플릿이 렌더링될 때 string이 이스케이프되지 않도록 합니다. 14 | 15 | ```js 16 | new Handlebars.SafeString("
    HTML Content!
    "); 17 | ``` 18 | 19 | 안전한 문자열로 표시될 문자열을 구성할 때, 외부 콘텐츠는 `Handlebars.escapeExpression` 메서드를 사용하여 적절히이스케이 20 | 프되어야 보안 문제를 방지할 수 있습니다. 21 | 22 | ### `Handlebars.escapeExpression(string)` 23 | 24 | ::: v-pre 25 | 26 | 전달된 문자열을 HTML 이스케이프하여 HTML 콘텐츠 내에서 텍스트로 렌더링할 때 안전하게 만듭니다. 27 | 28 | ```js 29 | Handlebars.Utils.escapeExpression(string); 30 | ``` 31 | 32 | 문자열 값에 대해 `&`, `<`, `>`, `"`, `'`, `` ` ``, `=` 를 HTML 엔티티 값으로 대체합니다. `SafeString` 값은 변경되지 않습 33 | 니다. 34 | 35 | `{{{` 표현을 제외한 모든 표현의 출력은 이 메서드를 통해 전달됩니다. 헬퍼가 `SafeString` 인스턴스를 통해 HTML 콘텐츠를반 36 | 환할 때도 가능한 코드 삽입을 방지하기 위해 이 메서드를 사용해야 합니다. 37 | 38 | 이 메서드는 `Handlebars.Utils.escapeExpression`에 별칭으로 정의되어 있습니다. 39 | 40 | ::: 41 | 42 | ### `Handlebars.createFrame(data)` 43 | 44 | 블록 헬퍼가 자식 데이터 객체를 생성할 때 사용됩니다. 45 | 46 | ```js 47 | if (options.data) { 48 | var data = Handlebars.createFrame(options.data); 49 | data.foo = "bar"; 50 | options.data = data; 51 | } 52 | ``` 53 | 54 | 데이터 상태를 수정하는 헬퍼는 새 프레임을 생성하여 자신을 격리하고 부모의 상태를 손상시키지 않아야 합니다. 일반적으로, 55 | 헬퍼 실행당 하나의 프레임만 생성하면 됩니다. 예를 들어, `each` 반복자는 모든 자식 실행에 대해 재사용되는 단일 프레임을생 56 | 성합니다. 57 | 58 | ## 일반 유틸리티 59 | 60 | Handlebars는 `Handlebars.Utils` 객체를 통해 다양한 유틸리티 메서드를 제공합니다. 61 | 62 | ### `Handlebars.Utils.isEmpty(value)` 63 | 64 | 주어진 값이 비어 있는지 여부를 판단합니다. 65 | 66 | Handlebars.Utils.isEmpty(value) 67 | 68 | 이 메서드는 내장된 `if` 및 `with` 헬퍼가 실행 흐름을 제어하는 데 사용됩니다. Handlebars의 빈 값 정의는 다음과 같습니다: 69 | 70 | - 길이가 0인 배열 71 | - 0을 제외한 거짓 값 72 | 73 | 이는 [Mustache behavior](http://mustache.github.io/mustache.5.html#Sections)을 따르기 위한 것입니다. 74 | 75 | ### `Handlebars.Utils.extend(obj, value)` 76 | 77 | `obj`를 `value`에 정의된 모든 키로 확장하는 간단한 유틸리티 메서드입니다. 78 | 79 | Handlebars.Utils.extend(foo, {bar: true}) 80 | 81 | 이는 객체 `foo`에 키 `bar`를 값 `true`로 설정합니다. 82 | 83 | ### `Handlebars.Utils.toString(obj)` 84 | 85 | 일반적인 `toString` 메서드입니다. 86 | 87 | ### `Handlebars.Utils.isArray(obj)` 88 | 89 | 객체가 배열인지 여부를 판단합니다. 90 | 91 | ### `Handlebars.Utils.isFunction(obj)` 92 | 93 | 객체가 함수인지 여부를 판단합니다. 94 | 95 | ### `Handlebars.log(level, message)` 96 | 97 | `log` 헬퍼에서 사용하는 로거입니다. 98 | 99 | 원하는 경우 재정의할 수 있습니다. 100 | -------------------------------------------------------------------------------- /src/ko/guide/installation/precompilation.md: -------------------------------------------------------------------------------- 1 | # 템플릿 사전 컴파일 2 | 3 | 6 | 7 | Handlebars 사전 컴파일러를 사용하여 Handlebars 템플릿을 사전 컴파일하여 클라이언트에서 시간을 절약하고 handlebars 라이브 8 | 러리의 필요한 런타임 크기를 줄일 수 있습니다. 9 | 10 | ## 시작하기 11 | 12 | 우선, _Node.js 와 npm_ 이 필요합니다. 귀하의 운영 체제에서 이를 어떻게 설치하는지 알아보려면 13 | [https://nodejs.org/en/download/](https://nodejs.org/en/download/)로 이동하세요. 14 | 15 | 다음으로, 사전 컴파일러를 포함하는 Handlebars npm 패키지를 설치하세요. 16 | 17 | ```bash 18 | npm install -g handlebars 19 | ``` 20 | 21 | 템플릿이 포함된 `example.handlebars` 파일을 만드세요.: 22 | 23 | <<< @/snippets/precompilation/example.handlebars 24 | 25 | 사전 컴파일러를 실행하세요. 26 | 27 | ```bash 28 | handlebars example.handlebars -f example.precompiled.js 29 | ``` 30 | 31 | Handlebars 런타임과 사전 컴파일된 JavaScript를 include 하세요. 32 | 33 | <<< @/snippets/precompilation/index.html 34 | 35 | 런타임은 [installation page](index.md#downloading-handlebars)에서도 다운로드할 수 있습니다. 36 | 37 | ## 최적화 38 | 39 | 템플릿을 사전 컴파일하므로 컴파일러에 여러 최적화를 적용할 수 있습니다. 첫 번째는 컴파일러에 알려진 도우미 목록을 지정할 40 | 수 있도록합니다. 41 | 42 | ```bash 43 | handlebars -f -k each -k if -k unless 44 | ``` 45 | 46 | Handlebars 컴파일러는 이러한 도우미들에 대한 접근을 최적화하여 성능을 향상시킵니다. 모든 도우미가 컴파일 시점에 known 상 47 | 태일경우, `--knownOnly` 옵션은 가장 작은 생성된 코드를 제공하면서도 가장 빠른 실행을 제공합니다. 48 | 49 | ## 사용법 50 | 51 | !HANDLEBARS_HELP! 52 | 53 | 사전 컴파일러의 일반 모드를 사용하는 경우, 결과 템플릿은 확장자를 제외한 상대적인 템플릿 이름으로 Handlebars.templates 54 | 객체에 저장됩니다. 이러한 템플릿은 템플릿과 같은 방식으로 실행될 수 있습니다. 간편 모드를 사용하는 경우, 사전 컴파일러는 55 | 단일 JavaScript 메소드를 생성합니다. 이 메소드를 실행하려면 `Handlebars.template()` 메소드에 전달해야하며, 결과 객체는일 56 | 반적으로 사용할 수 있습니다. 57 | 58 | ## NodeJS 내에서의 사전 컴파일 템플릿 59 | 60 | NodeJS 내부에서 템플릿을 사전 컴파일하려면 "handlebars"를 명령 줄에서 호출하지 않고도 Handlebars.precompile을 사용할 수 61 | 있습니다. 이 함수의 결과인 문자열을 클라이언트에 전송하고, 클라이언트에서 다시 Handlebars.template으로 구문 분석할 수 있 62 | 습니다. 63 | 64 | <<< @/snippets/precompilation/precompile-in-nodejs.js 65 | 66 | 결과는 다음과 같습니다: 67 | 68 | <<< @/snippets/precompilation/precompile-in-nodejs.output.js 69 | 70 | 클라이언트 측에서는 다음과 같은 형식의 JavaScript 코드를 사용합니다. 71 | 72 | ```js 73 | Handlebars.partials["test1"] = Handlebars.template({ 74 | /** 컴파일된 ouput을 여기에 삽입하세요. **/ 75 | }); 76 | ``` 77 | 78 | 마지막으로, 이러한 템플릿을 JavaScript에서 동적으로 참조할 수 있습니다. 79 | 80 | ```js 81 | var result = Handlebars.partials["test1"]({ name: "yourname" }); 82 | // result를 활용해 원하는 작업을 수행하세요. 83 | ``` 84 | 85 | ## 통합 86 | 87 | 일부 npm 패키지는 Handlebars 사전 컴파일러를 빌드 시스템(예: Webpack, Browserify 등)에 통합하는 데 사용될 수 있습니다. 88 | 통합 페이지를 확인하세요.: 89 | 90 | [더 알아보기: 통합](integrations.md) 91 | -------------------------------------------------------------------------------- /src/ko/api-reference/runtime.md: -------------------------------------------------------------------------------- 1 | # Handlebars 런타임 2 | 3 | ## `Handlebars.registerPartial(name, partial)` 4 | 5 | 환경 내 모든 템플릿에서 접근할 수 있는 부분 템플릿을 등록합니다. 6 | 7 | ```js 8 | Handlebars.registerPartial("foo", partial); 9 | ``` 10 | 11 | 여러 부분 템플릿을 한 번에 등록하는 것도 지원합니다. 12 | 13 | ```js 14 | Handlebars.registerPartial({ foo: partial, bar: partial }); 15 | ``` 16 | 17 | 전체 라이브러리를 로드하는 경우, 부분 템플릿은 필요할 때 컴파일되는 문자열 값일 수 있습니다. 런타임만 로드하는 경우, 부 18 | 분 템플릿은 `Handlebars.template` 메서드를 사용하여 적절히 설정된 사전 컴파일된 템플릿이어야 합니다. 19 | 20 | ## `Handlebars.unregisterPartial(name)` 21 | 22 | 이전에 등록된 부분 템플릿을 등록 해제합니다. 23 | 24 | ```js 25 | Handlebars.unregisterPartial("foo"); 26 | ``` 27 | 28 | ## `Handlebars.registerHelper(name, helper)` 29 | 30 | 환경 내 모든 템플릿에서 접근할 수 있는 헬퍼를 등록합니다. 31 | 32 | ```js 33 | Handlebars.registerHelper("foo", function () {}); 34 | ``` 35 | 36 | 여러 헬퍼를 한 번에 등록하는 것도 지원합니다. 37 | 38 | ```js 39 | Handlebars.registerHelper({ foo: function () {}, bar: function () {} }); 40 | ``` 41 | 42 | ## `Handlebars.unregisterHelper(name)` 43 | 44 | 이전에 등록된 헬퍼를 등록 해제합니다. 45 | 46 | ```js 47 | Handlebars.unregisterHelper("foo"); 48 | ``` 49 | 50 | ## `Handlebars.registerDecorator(name, helper)` (폐기 예정) 51 | 52 | ::: warning 폐기 예정 안내 53 | 54 | 사용자 정의 데코레이터는 폐기 예정이며 Handlebars의 다음 주요 버전에서 사라질 수 있습니다. 이들은 다른 언어로 포팅하기어 55 | 려운 내부 API의 너무 많은 부분을 노출하며 코드 유지 관리가 어렵게 만듭니다. 56 | 57 | ::: 58 | 59 | 환경 내 모든 템플릿에서 접근할 수 있는 데코레이터를 등록합니다. 60 | 61 | ```js 62 | Handlebars.registerDecorator("foo", function () {}); 63 | ``` 64 | 65 | 여러 데코레이터를 한 번에 등록하는 것도 지원합니다. 66 | 67 | ```js 68 | Handlebars.registerDecorator({ foo: function () {}, bar: function () {} }); 69 | ``` 70 | 71 | ## `Handlebars.unregisterDecorator(name)` 72 | 73 | 이전에 등록된 데코레이터를 등록 해제합니다. 74 | 75 | ```js 76 | Handlebars.unregisterDecorator("foo"); 77 | ``` 78 | 79 | ## `Handlebars.create()` 80 | 81 | 고립된 Handlebars 환경을 만듭니다. 82 | 83 | ```js 84 | var OtherHandlebars = Handlebars.create(); 85 | ``` 86 | 87 | 각 환경은 자체 헬퍼와 부분 템플릿을 가집니다. 이는 별개의 헬퍼 또는 부분 템플릿이 필요한 사용 사례에서만 필요합니다. 대 88 | 부분의 사용 사례는 루트 `Handlebars` 환경을 직접 사용할 수 있습니다. 89 | 90 | 주어진 환경을 위해 생성된 템플릿은 해당 환경에 바인딩됩니다. 이는 여러 환경에서 실행되어야 하는 템플릿이 각 환경에 대해 91 | 다시 컴파일되거나 `Handlebars.template`을 통해 재구성되어야 함을 의미합니다. 이는 부분 템플릿에도 적용됩니다. 92 | 93 | ## `Handlebars.noConflict()` 94 | 95 | 이 Handlebars 인스턴스를 전역 네임스페이스에서 제거하고 전역 `Handlebars` 변수를 이전 값으로 복원합니다. 96 | 97 | ```js 98 | var myHandlebars = Handlebars.noConflict(); 99 | ``` 100 | 101 | 이를 통해 라이브러리의 다양한 버전을 동시에 사용하면서 버전 충돌에 대한 걱정 없이 사용할 수 있습니다. 102 | -------------------------------------------------------------------------------- /src/guide/hooks.md: -------------------------------------------------------------------------------- 1 | # Hooks 2 | 3 | There are several places where you can hook into Handlebars function calls. 4 | 5 | ## helperMissing 6 | 7 | This hook is called when a mustache or a block-statement 8 | 9 | - a simple mustache-expression is not a registered helper AND 10 | - is not a property of the current evaluation context. 11 | 12 | you can add custom handling for those situations by registering the helper `helperMissing`: 13 | 14 | 15 | 16 | 17 | 18 | The helper receives the same arguments and options (`hash`, `name` etc) as any custom helper or block-helper. The 19 | `options.name` is the name of the helper being called. 20 | 21 | ### Default behavior 22 | 23 | If no parameters are passed to the mustache, the default behavior is to do nothing and ignore the whole mustache 24 | expression or the whole block: 25 | 26 | 27 | 28 | 29 | 30 | 31 | If parameter is passed to the mustache, Handlebars with throw an exception: 32 | 33 | 34 | 35 | 36 | 37 | 38 | ## blockHelperMissing 39 | 40 | This hook is called, when a 41 | 42 | - block-expression calls a helper that is not registered, 43 | - but the name matches a property in the current evaluation context. 44 | 45 | You can handle this situation by registering a helper named `blockHelperMissing`. 46 | 47 | 48 | 49 | 50 | 51 | ### Default behavior 52 | 53 | The hook will be called with the resolved property value on the current context and the `options.name` field set to the 54 | name of the property. 55 | 56 | If the hook is not overridden, then the default implementation will mimic the behavior of Mustache and just call the 57 | block. 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/zh/contributing/index.md: -------------------------------------------------------------------------------- 1 | # 帮助改进此文档 2 | 3 | 7 | 8 | Handlebars 是一个开源项目。没有 _“文档部门”_ 使文档保持最新。 Handlebars 文档站需要你的帮助才能变得更加优秀. 9 | 10 | - [发行说明](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md) 11 | - [带有 'docs-needed' 标签的 Issues](https://github.com/handlebars-lang/handlebars.js/issues?q=is%3Aopen+is%3Aissue+label%3Adocs-needed) 12 | - [Handlebars 网站(旧](https://handlebars-archive.knappi.org) 13 | 14 | 以下各节将帮助你帮助我们改进文档。 15 | 16 | ## 如何提交更改? 17 | 18 | 该站点托管在 [Github](https://github.com/handlebars-lang/docs) 上,并使用 [VitePress](https://vitepress.dev/)。 19 | 20 | - 请为你要进行的影响此文档的任何更改创建一个 [pull requests](https://help.github.com/en/articles/about-pull-requests)。 21 | - 如果更改仅影响单页内容,则只需单击该页面底部的 `{{theme.editLink.text}}` 22 | 按钮。(请参阅 [编辑另一个用户存储库中的文件](https://help.github.com/en/articles/editing-files-in-another-users-repository)。) 23 | - 对于更复杂的更改(样式,多个页面,新页面,修复构建问题),你应该 [fork repo](https://help.github.com/en/articles/fork-a-repo) 24 | 并在完成之后提交 Pull Request。 [Contributing页][contributing-page-in-repo] 25 | 包含更多信息。它可以让你使用开发服务器并在提交更改之前预览更改。 26 | 27 | ## 如何编写内容? 28 | 29 | 该文档使用 Markdown 编写,并使用 [VitePress](https://vitepress.dev/) 渲染。 VitePress 使用 `markdown-it` 30 | 包来渲染 markdown。markdown-it 实现了 CommonMark 语法。 31 | 32 | 这意味着你可以使用以下资源中描述的语法: 33 | 34 | - [CommonMark 帮助](https://commonmark.org/help/) 35 | - [markdown-it 添加的语法扩展](https://github.com/markdown-it/markdown-it#syntax-extensions) 36 | - [VitePress 添加的语法扩展](https://vitepress.dev/) 37 | 38 | 除这些扩展之外,本站还添加了一些可以嵌入到源文件中的自定义 Vue 组件。 39 | 40 | - [互动示例](interactive-examples.md) 41 | 42 | ## 我应该怎么做? 43 | 44 | ::: danger 45 | 46 | - **尊重知识产权**: 提交的文本必须是你自己创建或是从 [handlebarsjs.com](https://handlebarsjs.com) 47 | 上复制的。有很多关于 Handlebars 的博客文章,但这些文章的知识产权归其作者所有。 48 | - **许可**: 提交内容即表示你同意在本网站的许可下将其发布在本网站上。 49 | 50 | - **行为准则**: 请尊重他人,避免使用色情或粗俗语言。 51 | 52 | ::: 53 | 54 | ## 我能贡献什么? 55 | 56 | - **在 [handlebars.js](https://github.com/handlebars-lang/handlebars.js) 存储库中寻找标记为 57 | [docs-needed](https://github.com/handlebars-lang/handlebars.js/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adocs-needed+) 58 | 的内容**。这些 Issues 描述了一些应当出现在文档中的内容。 59 | - **提出并提交新内容。** 如果不确定的话,可以先提出 Issue,然后再提交 Pull Requests。这样可以节省你的时间。 60 | - **改善现有内容。** 你可以提出导航栏的改进建议,修正错别字,改善语言并纠正错误内容。 61 | - **修复 CSS 样式问题。** 62 | 此页面上的样式绝非完美。请继续完善这个页面的样式。如需更大的更改,请先打开一个 Issue 以取得联系。 63 | 64 | [contributing-page-in-repo]: https://github.com/handlebars-lang/docs/blob/master/CONTRIBUTING.md 65 | [all-features-example-raw]: https://raw.githubusercontent.com/handlebars-lang/docs/master/src/examples/all-features.md 66 | -------------------------------------------------------------------------------- /src/zh/guide/partials.md: -------------------------------------------------------------------------------- 1 | # 代码片段 2 | 3 | Handlebars 允许代码片段的复用。代码片段是一段普通的 Handlebars 模板,但它们可以直接由其他模板调用。 4 | 5 | ## 基本代码片段 6 | 7 | 一个代码片段必须通过 `Handlebars.registerPartial` 注册。 8 | 9 | 10 | 11 | 这个方法将注册代码片段 `myPartial`。可以对代码片段进行预编译,并将预编译的模板传到第二个参数。 12 | 13 | 调用代码片段是通过「代码片段调用语法」完成的: 14 | 15 | 16 | 17 | 将渲染名为 `myPartial` 的代码片段。当代码片段执行时,它会在当前的代码块的上下文中运行。 18 | 19 | ## 动态代码片段 20 | 21 | 使用子表达式语法可以动态选择要执行的部分。 22 | 23 | 24 | 25 | 这将计算 `whichPartial`,然后渲染以函数的返回值作为名称的代码片段。 26 | 27 | 子表达式不会解析变量,因此 `whichPartial` 必须是一个函数。如果代码片段的名称是储存在一个变量里面的,则可以通过 `lookup` 28 | 助手代码来解决它。 29 | 30 | 31 | 32 | ## 代码片段上下文 33 | 34 | 通过将上下文传递给代码片段,你可以在自定义上下文中执行代码片段。 35 | 36 | 37 | 38 | ## 代码片段参数 39 | 40 | 可以通过 Hash 参数将自定义数据传递到代码片段。 41 | 42 | 43 | 44 | 代码片段运行时会将参数设置为 `value`。 45 | 46 | 这对于把数据从父级传递到代码片段的上下文中的时候特别有用: 47 | 48 | 49 | 50 | ## 代码片段代码块 51 | 52 | 一般来讲,尝试渲染一个未注册的代码片段会抛出错误。如果需要阻止错误抛出,可以在代码块中嵌套代码片段。 53 | 54 | 55 | 56 | 如果代码片段 `myPartial` 尚未注册,则 `Failover content` 将被渲染。 57 | 58 | 这种代码块的语法也可以用于将模板传递到代码片段中。有专门的代码片段执行此操作:`@partial-block`。考虑如下模板: 59 | 60 | 61 | 62 | `layout` 代码片段包含 63 | 64 | 65 | 66 | 这将渲染: 67 | 68 | 69 | 70 | 当以这种方式调用时,代码块将在 **调用时代码片段中的上下文** 71 | 中执行。此时深度路径查询和代码块参数是相对于代码片段的,而非代码片段的模板。 72 | 73 | 74 | 75 | 这将渲染模板中的 `person.firstname` 而非代码片段。 76 | 77 | ## 内联代码片段 78 | 79 | 模板可以通过 `inline` 修饰符定义代码块范围之内的代码片段。 80 | 81 | 82 | 83 | 这将为每个 child 渲染 `myPartial`。 84 | 85 | 每个内联代码片段均可用于当前代码块和所有子代码块(包括代码片段)。这使得「布局模板」和其他类似的功能成为可能: 86 | 87 | 88 | 89 | 其中 `layout` 可能是: 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/guide/installation/integrations.md: -------------------------------------------------------------------------------- 1 | # Integrations 2 | 3 | The following packages integrate Handlebars in different environments. These packages are **not** officially supported 4 | by the Handlebars team. 5 | 6 | There are multiple webpack-plugins that allow you to use Handlebars in a Webpack environment. 7 | 8 | ## Webpack: handlebars-loader 9 | 10 | The [handlebars-loader](https://github.com/pcardune/handlebars-loader) allow you to import 11 | [precompiled](./precompilation.html) template. Just write your handlebars-template into a `template.handlebars`-file and 12 | import it using 13 | 14 | ```js 15 | const compiledTemplate = require("./template.handlebars"); 16 | ``` 17 | 18 | or 19 | 20 | ```js 21 | import compiledTemplate from "./template.handlebars"; 22 | ``` 23 | 24 | ## Webpack: handlebars-webpack-plugin 25 | 26 | The [handlebars-webpack-plugin](https://github.com/sagold/handlebars-webpack-plugin) uses Handlebars to build your 27 | HTML-pages statically when compiling your application 28 | 29 | ## Webpack: html-bundler-webpack-plugin 30 | 31 | The [html-bundler-webpack-plugin](https://github.com/webdiscus/html-bundler-webpack-plugin) uses various templating 32 | engines, [including Handlebars](https://github.com/webdiscus/html-bundler-webpack-plugin#using-the-handlebars), to 33 | render templates and bundle styles and scripts into generated HTML. 34 | 35 | ## Babel: handlebars-inline-precompile 36 | 37 | The 38 | [babel-plugin-handlebars-inline-precompile](https://github.com/jamiebuilds/babel-plugin-handlebars-inline-precompile) 39 | precompiles Handlebars templates that are provided as template literals in the JavaScript source code: 40 | 41 | ```js 42 | import hbs from "handlebars-inline-precompile"; 43 | const compiledTemplate = hbs`{{name}}`; 44 | ``` 45 | 46 | Please refer to the documentation of the package for setup instructions. 47 | 48 | ## Browserify: hbsfy 49 | 50 | The [hbsfy](https://www.npmjs.com/package/hbsfy) package allows you to import precompiled templates in a browserify 51 | environment: 52 | 53 | ```js 54 | const compiledTemplate = require("./template.handlebars"); 55 | ``` 56 | 57 | ## Parcel: parcel-plugin-handlebars 58 | 59 | There is an old plugin for parcel: https://www.npmjs.com/package/parcel-plugin-handlebars 60 | 61 | But you should use one of the many forks of this package, which are more up-to-date: 62 | https://www.npmjs.com/search?q=parcel-plugin-handlebars 63 | 64 | The most recent one is: https://www.npmjs.com/package/@inventory/parcel-plugin-handlebars 65 | 66 | ## Parcel: parcel-plugin-handlebars-precompile 67 | 68 | TODO: Write text here 69 | 70 | https://www.npmjs.com/package/parcel-plugin-handlebars-precompile 71 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/lib/codemirror-languages/js-object.grammar: -------------------------------------------------------------------------------- 1 | //!top 2 | 3 | @top Program { expression* } 4 | 5 | //!expression 6 | 7 | commaSepObject { 8 | "" | content ("," content?)* 9 | } 10 | 11 | commaSepArray { 12 | content ("," content)* 13 | } 14 | 15 | propName { PropertyDefinition | "[" expression "]" ~destructure | Number ~destructure | String ~destructure } 16 | 17 | PropertyDefinition { word ~propName } 18 | 19 | Property { 20 | propName ~destructure (":" expression)? 21 | } 22 | 23 | ArrayExpression { 24 | "[" commaSepArray<"..."? expression | ""> ~destructure "]" 25 | } 26 | 27 | ObjectExpression { 28 | "{" commaSepObject ~destructure "}" 29 | } 30 | 31 | boolean { @specialize[@name=BooleanLiteral] } 32 | 33 | expression { 34 | Number | 35 | String | 36 | boolean | 37 | ArrayExpression | 38 | ObjectExpression 39 | } 40 | 41 | //!tokens 42 | @local tokens { 43 | blockCommentEnd { "*/" } 44 | blockCommentNewline { "\n" } 45 | @else blockCommentContent 46 | } 47 | 48 | @tokens { 49 | spaces[@export] { $[\u0009 \u000b\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+ } 50 | newline[@export] { $[\r\n\u2028\u2029] } 51 | LineComment[isolate] { "//" ![\n]* } 52 | identifierChar { @asciiLetter | $[_$\u{a1}-\u{10ffff}] } 53 | word { identifierChar (identifierChar | @digit)* } 54 | identifier { word } 55 | 56 | @precedence { spaces, newline, identifier } 57 | @precedence { spaces, newline } 58 | @precedence { spaces, newline, word } 59 | 60 | hex { @digit | $[a-fA-F] } 61 | 62 | Number { 63 | (@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*) 64 | (("e" | "E") ("+" | "-")? ("_" | @digit)+)? | 65 | @digit ("_" | @digit)* "n" | 66 | "0x" (hex | "_")+ "n"? | 67 | "0b" $[01_]+ "n"? | 68 | "0o" $[0-7_]+ "n"? 69 | } 70 | 71 | Escape { 72 | "\\" ("x" hex hex | "u" ("{" hex+ "}" | hex hex hex hex) | ![xu]) 73 | } 74 | 75 | stringContentSingle { ![\\\n']+ } 76 | stringContentDouble { ![\\\n"]+ } 77 | 78 | "(" ")" "[" "]" "{" "}" 79 | "." "," ";" ":" "@" 80 | } 81 | 82 | //!skip 83 | 84 | @skip {} { 85 | String[isolate] { 86 | '"' (stringContentDouble | Escape)* ('"' | "\n") | 87 | "'" (stringContentSingle | Escape)* ("'" | "\n") 88 | } 89 | 90 | BlockComment[isolate] { "/*" (blockCommentContent | blockCommentNewline)* blockCommentEnd } 91 | } 92 | 93 | @skip { spaces | newline | LineComment | BlockComment } 94 | 95 | //!external 96 | 97 | //!delim 98 | 99 | @detectDelim 100 | -------------------------------------------------------------------------------- /src/zh/contributing/interactive-examples.md: -------------------------------------------------------------------------------- 1 | # 创建交互式示例 2 | 3 | 我们可以定义交互式示例。示例或示例的一部分可以 **嵌入任何页面**。一种自动生成的链接使访问者可以在 **Playground** 4 | 中打开示例,在这里访问者可以更改模板,局部变量,输入等,并可以看到结果输出。 5 | 6 | ## 创建示例 7 | 8 | 为了定义示例,请在 `examples` 目录中创建一个新的 Markdown 文件。示例数据在引用示例页面的索引处。参见 9 | [all-features-example-raw](../../examples/all-features.md) 演示所有功能。 10 | 11 | 支持以下 Frontmatter 属性: 12 | 13 | -`layout`: 必须始终为 14 | `InteractivePlaygroundLayout` -`example`: 包含示例   -`template`: 主 Handlebars 模板   -`partials`: 一个对象,每个注册的代码片段都具有该属性,键是 partial-name,值是 partial 15 | content   -`preparationScript`: 在编译和运行模板之前执行的脚本。`Handlebars` 16 | 可      作为此脚本中的全局变量。   -`input`: 作为嵌入式 YAML 对象的模板。  -`errorExpected`: 一个布尔值(默认值: 17 | `false`),它指定此示例是否应抛出错误。通过      默认情况下,在执行过程中引发错误的示例会导致整个网站的构建失败。如果你需要创建一个      描述错误的示例,您需要将此选项设置为 18 | `true`。 19 | 20 | 使用最新版本的 Handlebars 自动渲染示例的输出。 21 | 22 | ## 示例数据 23 | 24 | 如果可能的话,示例应该使用通用数据集中提供的变量。因此,文件 25 | [src/\_examples/\_example-base-data.yaml](https://github.com/handlebars-lang/docs/blob/master/src/_examples/_example-base-data.yaml) 26 | 包含了可重复使用并适用于每个示例的数据。如果该文件中的数据不足,请添加新的数据,但请确保它们之间存在关联。 27 | 28 | ## 嵌入示例 29 | 30 | `` 组件允许您在当前段落中显示示例的一部分。 31 | 32 | ```md 33 | 34 | ``` 35 | 36 | 将渲染 37 | 38 | 39 | 40 | 该组件的属性有: 41 | 42 | - `examplePage`: src 文件夹下面的示例页面的路径 43 | - `show`: 示例中应插入页面的部分。可能为 `template`,`input`,   `output`, `error`, `preparationScript` 或 `partial` 44 | - `name` (可选): 仅当`show =“ partial”`时才需要此道具。它定义了应该是的部分名称    插入到示例中。 45 | 46 | 如果您想将示例的各个部分嵌入流文本中,则该组件非常有用。您可以插入输入的 JSON 使用 47 | ``,以下代码段将出现在页面中: 48 | 49 | 50 | 51 | 然后,为了向读者显示模板,您可以将 `show="template"` 与相同的 `examplePage` 一起使用。 52 | 53 | 54 | 55 | 您可以使用例如 `show=partial` 和 `name=person`来局部渲染。 56 | 57 | 58 | 59 | 如果您有助手代码的示例,则可能还需要包括脚本: 60 | 61 | 62 | 63 | ## 水平布局 64 | 65 | 如果要水平放置两个示例部件,则可以使用 `` 组件。 66 | 67 | ```md 68 | 69 | 70 | 71 | 72 | ``` 73 | 74 | 将渲染 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/Modal.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 54 | 55 | 111 | -------------------------------------------------------------------------------- /src/.vitepress/components/DownloadHandlebars.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 58 | 59 | 103 | -------------------------------------------------------------------------------- /src/zh/api-reference/runtime-options.md: -------------------------------------------------------------------------------- 1 | # 运行时参数 2 | 3 | ::: v-pre 4 | 5 | 'Handlebars.compile' 与 'Handlebars.precompile' 函数构造了另一个函数。构造的函数可以用 `template(context, options)` 6 | 调用。`context` 是输入的对象。 7 | 8 | `options` 是可能具有以下属性的对象: 9 | 10 | - `data` 输入一个对象以设定自定义的 `@variable` 的私有值。 11 | - `helpers` 输入以提供自定义助手代码以及全局的助手代码。在模版运行时,本项所定义的值将会替换全局对象所定义的任何值。 12 | - `partials` 13 | 输入以提供自定义代码片段以及全局定义的代码片段。在模版运行时,本项所定义的值将会替换全局对象所定义的任何值。 14 | - `allowCallsToHelperMissing` (从 4.3.0 开始, 不安全):如果设置为 `true`,类似 `{{helperMissing}}` 或 15 | `{{blockHelperMissing}}` 16 | 的调用将会被允许。请注意,这允许模版作者假造模版并在运行 Handlebars 的环境下远程执行代码。(见https://github.com/handlebars-lang/handlebars.js/issues/1558) 17 | 18 | ::: 19 | 20 | ## 控制原型访问的选项 21 | 22 | 从 4.6.0 版本开始,由于各种安全原因, Handlebars 默认禁止访问原型的属性以及上下文对象的方法。以下选项可以用来控制原型的可访问性。 23 | 24 | ::: danger 使用以下选项有安全风险。 25 | 26 | 允许这些属性可能会使得模版作者可以在运行 Handlebars 的机器上执行任意代码。尽管有限制,攻击者还是可能假造模版并且使得机器崩溃。 27 | 28 | 详细情况可以在 npm-security 中以及博客文章中找到(英文文档): 29 | 30 | [1164](https://www.npmjs.com/advisories/1164),[1316](https://www.npmjs.com/advisories/1316), 31 | [1324](https://www.npmjs.com/advisories/1324) 和 [1325](https://www.npmjs.com/advisories/1325) 以及博客文章 32 | [Mahmoud Gamal](http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html)。 33 | 34 | ::: 35 | 36 | - `allowProtoMethodsByDefault` (自 4.7.0 开始):默认为 false 的布尔值,定义了在对象的原型中定义的方法是否可以被解析。 37 | 38 | 即使本项被设置为 `true`,`constructor`,`__defineGetter__`,`__defineSetter__`,`__lookupGetter__` 与 39 | `__lookupSetter__` 还是会被禁止。只有在 `allowedProtoMethods` 内对应键被设置为 `true` 时,以上方法才可以被访问。 40 | 41 | 对本项给定任何值都会禁止 Handlebars 在一个 proto-method-access 尝试并失败的情况下向控制台写入警告。 42 | 43 | - `allowedProtoMethods` 44 | (自 4.6.0 开始):一个储存「字符串-布尔」类型的映射表。若「属性-名称」是父对象的方法,则将会被包含在表中。若未定义,将会使用 `allowProtoMethodsByDefault` 45 | 内定义的值。 46 | 47 | - `allowProtoPropertiesByDefault` 48 | (自 4.7.0 开始):默认为 false 的布尔变量。决定了在对象原型中定义的非方法的属性是否可以被解析。 49 | 50 | 即使该选项被设定为 `true`,属性 `__proto__` 依旧会被禁止。只有 `allowedProtoProperties` 中的对应键值被设定为 `true` 51 | 的时候它才能被访问。 52 | 53 | 对本项给定任何值都会禁止 Handlebars 在一个 proto-method-access 尝试并失败的情况下向控制台写入警告。 54 | 55 | - `allowedProtoProperties` 56 | (自 4.6.0 开始):一个储存「字符串-布尔」类型的映射表。若一个属性不是父对象的方法,则「属性- 名称」对将会被包含在这个表里。若未定义,将会使用 57 | `allowProtoPropertiesByDefault` 内定义的值。 58 | 59 | ```js 60 | const template = handlebars.compile("{{aString.trim}}"); 61 | const result = template({ aString: " abc " }); 62 | // result is empty, because trim is defined at String prototype 63 | ``` 64 | 65 | ```js 66 | const template = handlebars.compile("{{aString.trim}}"); 67 | const result = template( 68 | { aString: " abc " }, 69 | { 70 | allowedProtoMethods: { 71 | trim: true, 72 | }, 73 | }, 74 | ); 75 | // result = 'abc' 76 | ``` 77 | 78 | 如果你在某些地方无法传递运行时选项,例如在 [express-handlebars](https://www.npmjs.com/package/express-handlebars) 79 | 的情况下,你也可以使用这个包: 80 | [@handlebars/allow-prototype-access](https://www.npmjs.com/package/@handlebars/allow-prototype-access) 81 | 使 Handlebars 回退到 4.5.3 时的表现。 82 | -------------------------------------------------------------------------------- /src/api-reference/compilation.md: -------------------------------------------------------------------------------- 1 | # (Pre-)Compilation 2 | 3 | ## `Handlebars.compile(template, options)` 4 | 5 | Compiles a template so it can be executed immediately. 6 | 7 | ```js 8 | const template = Handlebars.compile("{{foo}}"); 9 | template({}); 10 | ``` 11 | 12 | Supports a variety of options that alter how the template executes. 13 | 14 | ::: v-pre 15 | 16 | - `data`: Set to `false` to disable `@data` tracking. 17 | - `compat`: Set to `true` to enable recursive field lookup. 18 | - `knownHelpers`: Hash containing list of helpers that are known to exist (truthy) at template execution time. Passing 19 | this allows the compiler to optimize a number of cases. Builtin helpers are automatically included in this list and 20 | may be omitted by setting that value to `false`. 21 | - `knownHelpersOnly`: Set to `true` to allow further optimizations based on the known helpers list. 22 | - `noEscape`: Set to `true` to not HTML escape any content. 23 | - `strict`: Run in strict mode. In this mode, templates will throw rather than silently ignore missing fields. This has 24 | the side effect of disabling inverse operations such as `{{^foo}}{{/foo}}` unless fields are explicitly included in 25 | the source object. 26 | - `assumeObjects`: Removes object existence checks when traversing paths. This is a subset of `strict` mode that 27 | generates optimized templates when the data inputs are known to be safe. 28 | - `preventIndent`: By default, an indented partial-call causes the output of the whole partial being indented by the 29 | same amount. This can lead to unexpected behavior when the partial writes `pre`-tags. Setting this option to `true` 30 | will disable the auto-indent feature. 31 | - `ignoreStandalone`: Disables standalone tag removal when set to `true`. When set, blocks and partials that are on 32 | their own line will not remove the whitespace on that line. 33 | - `explicitPartialContext`: Disables implicit context for partials. When enabled, partials that are not passed a context 34 | value will execute against an empty object. 35 | 36 | ::: 37 | 38 | ## `Handlebars.precompile(template, options)` 39 | 40 | Precompiles a given template so it can be sent to the client and executed without compilation. 41 | 42 | ```js 43 | var templateSpec = Handlebars.precompile("{{foo}}"); 44 | ``` 45 | 46 | Supports all of the same options parameters as the `Handlebars.compile` method. Additionally may pass: 47 | 48 | - `srcName`: Passed to generate the source map for the input file. When run in this manner, the return structure is 49 | `{code, map}` with `code` containing the template definition and `map` containing the source map. 50 | - `destName`: Optional parameter used in conjunction with `srcName` to provide a destination file name when generating 51 | source maps. 52 | 53 | ## `Handlebars.template(templateSpec)` 54 | 55 | Sets up a template that was precompiled with `Handlebars.precompile`. 56 | 57 | ```js 58 | var template = Handlebars.template(templateSpec); 59 | template({}); 60 | ``` 61 | -------------------------------------------------------------------------------- /src/ko/contributing/index.md: -------------------------------------------------------------------------------- 1 | # 문서 개선하기 2 | 3 | 7 | 8 | Handlebars는 오픈 소스 프로젝트입니다. 문서를 최신 상태로 유지하는 _“문서 부서”_ 가 없습니다. 이 문서 사이트는 유용하고 9 | 도움이 되는 사이트가 되기 위해 여러분의 도움이 필요합니다. 10 | 11 | [릴리스 노트](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
    12 | ['docs-needed' 레이블이 붙은 Issues](https://github.com/handlebars-lang/handlebars.js/issues?q=is%3Aopen+is%3Aissue+label%3Adocs-needed)
    13 | [옛 Handlebars 웹사이트](https://handlebars-archive.knappi.org) 14 | 15 | 다음 섹션은 문서 개선을 돕기 위해 작성되었습니다. 16 | 17 | ## Contribution은 어떻게 하나요? 18 | 19 | 이 사이트는 [Github](https://github.com/handlebars-lang/docs) 에 호스팅되고 [VuePress](https://v1.vuepress.vuejs.org/) 20 | 로 렌더링됩니다. 21 | 22 | - 페이지에 변경 사항이 있을 경우 [pull requests](https://help.github.com/en/articles/about-pull-requests)를 생성해 주세 23 | 요. 24 | - 변경 사항이 단일 페이지의 내용에만 영향을 미치는 경우, 페이지 하단의 `{{theme.editLink.text}}` 링크를 클릭 하여 변경할 25 | 수 있습니다. 자세한 내용은 26 |  [다른 사용자의 저장소에서 파일 편집하기](https://help.github.com/en/articles/editing-files-in-another-users-repository)를 27 | 참조하세요. 28 | - 더 복잡한 변경 사항(스타일링, 여러 페이지, 새 페이지, 빌드 문제 수정)은 저장소를 포크하고 작업이 완료되면 풀 리퀘스트 29 | 를 제출하세요. 저장소의 [CONTRIBUTING.md 페이지][contributing-page-in-repo]  에서 자세한 정보를 확인할 수 있습니다. 이 30 | 방법을 통해 개발 서버를 사용하고 변경 사항을 제출하기 전에 미리 볼 수 있습니다. 31 | 32 | ## 콘텐츠는 어떻게 작성하나요? 33 | 34 | 문서는 마크다운으로 작성되며 [VuePress](https://v1.vuepress.vuejs.org/) 로 렌더링됩니다. VuePress는 `markdown-it` 패키지 35 | 를 사용하여 마크다운을 렌더링합니다. `markdown-it`은 CommonMark dialect를 구현합니다. 36 | 37 | 따라서 다음 자료에 설명된 구문을 사용할 수 있습니다: 38 | 39 | - [CommonMark 도움말](https://commonmark.org/help/) 40 | - [markdown-it에서 추가한 구문 확장](https://github.com/markdown-it/markdown-it#syntax-extensions) 41 | - [VuePress에서 추가한 구문 확장](https://v1.vuepress.vuejs.org/guide/markdown.html) 42 | 43 | 이러한 모든 확장 외에도, 이 사이트는 소스 파일에 포함될 수 있는 일부 사용자 정의 Vue 컴포넌트를 추가합니다. 44 | 45 | - [인터랙티브 예제](interactive-examples.md) 46 | 47 | ## 어떤 행동을 해야 하나요? 48 | 49 | ::: danger 50 | 51 | - **지적 재산 존중**: 본인이 작성했거나 [handlebarsjs.com](https://handlebarsjs.com) 上에서 복사한 텍스트와 기타 미디어 52 | 만 제출해 주세요. Handlebars에 관한 많은 블로그 게시물이 있지만, 해당 게시물의 텍스트는 작성자의 지적 재산입니다. 53 | - **라이선스**: 콘텐츠를 제출하면 해당 콘텐츠가 이 사이트의 라이선스 하에 게시되는 것에 동의하게 됩니다. 54 | - **행동 강령**: 다른 사람을 존중하고 성적인 언어나 거친 표현을 피하세요. 55 | 56 | ::: 57 | 58 | ## 무엇을 기여할 수 있나요? 59 | 60 | - [handlebars.js](https://github.com/handlebars-lang/handlebars.js) 저장소에서 61 | [docs-needed](https://github.com/handlebars-lang/handlebars.js/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adocs-needed+) 62 | 레이블이 붙은 이슈를 찾아보세요. 문서화가 필요한 사항을 설명하는 이슈들입니다. 63 | - **새로운 콘텐츠를 제안하고 제출하세요.** 제안에 대해 확신이 없다면 풀 리퀘스트를 제출하기 전에 이슈를 생성할 수 있습니 64 | 다. 이를 통해 시간을 낭비하지 않도록 할 수 있습니다. 65 | - **기존 콘텐츠를 개선하세요.** 네비게이션을 제안하고, 오타를 수정하고, 언어를 개선하고, 잘못된 내용을 수정할 수 있습니 66 | 다. 67 | - **CSS 스타일링 문제를 수정하세요.** 이 페이지의 스타일링은 완벽하지 않습니다. 개선하고 싶다면 주저하지 말고 진행해 주 68 | 세요. 더 큰 변경 사항의 경우 이슈를 열어 연락해 주세요. 69 | 70 | [contributing-page-in-repo]: https://github.com/handlebars-lang/docs/blob/master/CONTRIBUTING.md 71 | [all-features-example-raw]: https://raw.githubusercontent.com/handlebars-lang/docs/master/src/examples/all-features.md 72 | -------------------------------------------------------------------------------- /src/api-reference/utilities.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: [1, 3] 3 | --- 4 | 5 | # Utility functions 6 | 7 | ## Helper utilities 8 | 9 | These methods come handy when you implement custom helpers. 10 | 11 | ### `Handlebars.SafeString(string)` 12 | 13 | Prevents `string` from being escaped when the template is rendered. 14 | 15 | ```js 16 | new Handlebars.SafeString("
    HTML Content!
    "); 17 | ``` 18 | 19 | When constructing the string that will be marked as safe, any external content should be properly escaped using the 20 | `Handlebars.escapeExpression` method to avoid potential security concerns. 21 | 22 | ### `Handlebars.escapeExpression(string)` 23 | 24 | HTML escapes the passed string, making it safe for rendering as text within HTML content. 25 | 26 | ```js 27 | Handlebars.Utils.escapeExpression(string); 28 | ``` 29 | 30 | Replaces `&`, `<`, `>`, `"`, `'`, `` ` ``, `=` with the HTML entity equivalent value for string values. `SafeString` 31 | values are left untouched. 32 | 33 | The output of all expressions except for triple-braced expressions are passed through this method. Helpers should also 34 | use this method when returning HTML content via a `SafeString` instance, to prevent possible code injection. 35 | 36 | This method is aliased at `Handlebars.Utils.escapeExpression`. 37 | 38 | ### `Handlebars.createFrame(data)` 39 | 40 | Used by block helpers to create child data objects. 41 | 42 | ```js 43 | if (options.data) { 44 | var data = Handlebars.createFrame(options.data); 45 | data.foo = "bar"; 46 | options.data = data; 47 | } 48 | ``` 49 | 50 | Helpers that modify the data state should create a new frame when doing so, to isolate themselves and avoid corrupting 51 | the state of any parents. Generally, only one frame needs to be created per helper execution. For example, the `each` 52 | iterator creates a single frame which is reused for all child execution. 53 | 54 | ## General Utilities 55 | 56 | Handlebars offers a variety of utility methods that are exposed through the `Handlebars.Utils` object. 57 | 58 | ### `Handlebars.Utils.isEmpty(value)` 59 | 60 | Determines if a given value is empty. 61 | 62 | Handlebars.Utils.isEmpty(value) 63 | 64 | This is used by the built-in `if` and `with` helpers to control their execution flow. The Handlebars definition of empty 65 | is any of: 66 | 67 | - Array with length 0 68 | - falsy values other than 0 69 | 70 | This is intended to match the [Mustache behavior](http://mustache.github.io/mustache.5.html#Sections). 71 | 72 | ### `Handlebars.Utils.extend(obj, value)` 73 | 74 | Simple utility method to augment `obj` with all keys defined on `value`. 75 | 76 | Handlebars.Utils.extend(foo, {bar: true}) 77 | 78 | Will set the key `bar` on object `foo` with the value `true`. 79 | 80 | ### `Handlebars.Utils.toString(obj)` 81 | 82 | Generic `toString` method. 83 | 84 | ### `Handlebars.Utils.isArray(obj)` 85 | 86 | Determines if an object is an array. 87 | 88 | ### `Handlebars.Utils.isFunction(obj)` 89 | 90 | Determines if an object is a function. 91 | 92 | ### `Handlebars.log(level, message)` 93 | 94 | Logger used by the `log` helper. 95 | 96 | May be overridden if desired. 97 | -------------------------------------------------------------------------------- /src/ko/contributing/interactive-examples.md: -------------------------------------------------------------------------------- 1 | # 인터랙티브 예제 만들기 2 | 3 | 인터랙티브 예제를 정의할 수 있습니다. 예제 또는 예제의 일부는 **어느 페이지에나 포함**될 수 있습니다. 자동 생성된 링크를 4 | 통해 방문자는 **플레이그라운드**에서 예제를 열어 템플릿, 부분 템플릿, 입력 등을 변경하고 결과 출력을 확인할 수 있습니다. 5 | 6 | ## 예제 만들기 7 | 8 | 예제를 정의하려면 examples 디렉토리에 새 마크다운 파일을 만듭니다. 예제 데이터는 참조된 예제 페이지의 frontmatter에 정의 9 | 됩니다. 모든 기능을 시연하는 [all-features-example-raw](../examples/all-features.md) 를 참조하세요. 10 | 11 | 다음 frontmatter 속성이 지원됩니다: 12 | 13 | -`layout`: 항상 `InteractivePlaygroundLayout`이어야 합니다. -`example`: 예제를 포함합니다. -`template`: 주요 Handlebars 14 | 템플릿   -`partials`: 각 등록된 부분 템플릿에 대한 속성을 포함하는 객체로, 키는 부분 템플릿 이름, 값은 부분 템플릿 내용 15 | 입니다.  -`preparationScript`: 템플릿을 컴파일하고 실행하기 전에 실행되는 스크립트입니다. 이 스크립트에서는 16 | `Handlebars`가 전역 변수로 제공됩니다.  -`input`: 내장 YAML 객체로 된 템플릿 입력입니다.   -`errorExpected`: 이 예제가오 17 | 류를 발생시킬 것으로 예상되는지 여부를 지정하는 부울 값(기본값: `false`)입니다. 기본적으로, 실행 중에 오류를 발생시키는 18 | 예제는 사이트 전체 빌드를 실패하게 만듭니다. 오류를 설명하는 예제를 작성하는 경우 이 플래그를 `true`로 설정해야 합니다. 19 | 20 | 예제의 출력은 최신 릴리스 버전의 Handlebars를 사용하여 자동으로 계산됩니다. 21 | 22 | ## 예제 데이터 23 | 24 | 가능하다면, 예제는 공통 데이터 세트의 변형을 사용해야 합니다. 따라서 파일 25 | [src/ko/examples/\_example-base-data.yaml](https://github.com/handlebars-lang/docs/blob/master/src/ko/examples/_example-base-data.yaml) 26 | 에는 각 예제에 재사용 및 적응할 수 있는 데이터가 포함되어 있습니다. 해당 파일의 데이터가 불충분하면 새 데이터를 추가할수 27 | 있지만, 관련이 있는지 확인해 주세요. 28 | 29 | ## 예제의 일부 포함 30 | 31 | `` 컴포넌트를 사용하여 현재 부분에 예제의 일부를 표시할 수 있습니다. 32 | 33 | ```md 34 | 35 | ``` 36 | 37 | 이렇게 하면 다음과 같은 결과가 나옵니다: 38 | 39 | 40 | 41 | 이 컴포넌트의 속성(props)은 다음과 같습니다: 42 | 43 | - `examplePage`: `src` 폴더 아래의 예제 페이지 경로 44 | - `show`: 페이지에 삽입할 예제 부분입니다. 가능한 값은 `template`,`input`,   `output`, `error`, `preparationScript` 및 45 | `partial` 입니다. 46 | - `name` (선택 사항): `show="partial"`일 때만 필요한 속성으로, 예제에 삽입할 부분 템플릿의 이름을 정의합니다. 47 | 48 | 이 컴포넌트는 예제의 일부를 흐르는 텍스트에 포함시키고자 할 때 매우 유용합니다. 49 | ``를 사용하여 입력 JSON을 삽입하면 다음 코드 조각이 페 50 | 이지에 나타납니다: 51 | 52 | 53 | 54 | 그런 다음, 독자에게 템플릿을 보여주기 위해 동일한 examplePage로 show="template"을 사용할 수 있습니다. 55 | 56 | 57 | 58 | 부분 템플릿을 렌더링하려면 예를 들어 `show=partial` 및 `name=person`을 사용할 수 있습니다. 59 | 60 | 61 | 62 | 헬퍼가 포함된 예제가 있는 경우 준비 스크립트를 포함시키고 싶을 수도 있습니다: 63 | 64 | 65 | 66 | ## 가로 레이아웃 67 | 68 | 두 개의 예제 부분을 가로로 레이아웃하고 싶다면 `` 컴포넌트를 사용할 수 있습니다. 69 | 70 | ```md 71 | 72 | 73 | 74 | 75 | ``` 76 | 77 | 이렇게 렌더링됩니다. 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/ko/guide/partials.md: -------------------------------------------------------------------------------- 1 | # 부분 템플릿(Partials) 2 | 3 | Handlebars는 부분 템플릿을 통해 템플릿 재사용을 허용합니다. 부분 템플릿은 다른 템플릿에 의해 직접 호출될 수 있는 일반적 4 | 인 Handlebars 템플릿입니다. 5 | 6 | ## 기본 부분 템플릿 7 | 8 | 부분 템플릿을 사용하려면 `Handlebars.registerPartial`을 통해 등록해야 합니다. 9 | 10 | 11 | 12 | 이 호출은 `myPartial` 부분 템플릿을 등록합니다. 부분 템플릿은 사전 컴파일될 수 있으며 사전 컴파일된 템플릿을 두 번째 매 13 | 개변수로 전달할 수 있습니다. 14 | 15 | 부분 템플릿 호출 구문을 통해 부분 템플릿을 호출할 수 있습니다. 16 | 17 | 18 | 19 | 이 구문은 `myPartial`이라는 이름의 부분 템플릿을 렌더링합니다. 부분 템플릿이 실행될 때 현재 실행 컨텍스트에서 실행됩니다 20 | . 21 | 22 | ## 동적 부분 템플릿 23 | 24 | 하위 표현식 구문을 사용하여 실행할 부분 템플릿을 동적으로 선택할 수 있습니다. 25 | 26 | 27 | 28 | 이는 `whichPartial`을 평가한 후, 이 함수가 반환하는 이름의 부분 템플릿을 렌더링합니다. 29 | 30 | 하위 표현식은 변수를 해결하지 않으므로 `whichPartial`은 함수여야 합니다. 단순 변수가 부분 템플릿 이름을 가지고 있다면 31 | `lookup` 헬퍼를 통해 해결할 수 있습니다. 32 | 33 | 34 | 35 | ## 부분 템플릿 컨텍스트 36 | 37 | 컨텍스트를 부분 템플릿 호출에 전달하여 부분 템플릿을 사용자 정의 컨텍스트에서 실행할 수 있습니다. 38 | 39 | 40 | 41 | ## 부분 템플릿 매개변수 42 | 43 | 해시 매개변수를 통해 부분 템플릿에 사용자 정의 데이터를 전달할 수 있습니다. 44 | 45 | 46 | 47 | 이는 부분 템플릿이 실행될 때 parameter를 `value`로 설정합니다. 48 | 49 | 이는 특히 상위 컨텍스트의 데이터를 부분 템플릿에 노출하는 데 유용합니다. 50 | 51 | 52 | 53 | ## 부분 템플릿 블록 54 | 55 | 부분 템플릿을 찾을 수 없을 때의 기본 동작은 구현에서 오류를 발생시키는 것입니다. 대신 대체 처리를 원할 경우 블록 구문을 56 | 사용하여 부분 템플릿을 호출할 수 있습니다.。 57 | 58 | 59 | 60 | 이는 `myPartial` 부분 템플릿이 등록되지 않은 경우 `Failover content`를 렌더링합니다. 61 | 62 | 이 블록 구문은 또한 템플릿을 부분 템플릿에 전달하여 특수 이름의 부분 템플릿 `@partial-block`에서 실행할 수 있도록 합니다 63 | . 64 | 65 | 66 | 67 | `layout` 부분 템플릿이 포함된 경우 68 | 69 | 70 | 71 | 다음과 같이 렌더링됩니다. 72 | 73 | 74 | 75 | 이와 같이 호출될 때 블록은 호출 시점의 부분 템플릿 컨텍스트에서 실행됩니다. 깊이 있는 경로와 블록 매개변수는 부분 템플릿 76 | 이 아닌 부분 블록을 기준으로 작동합니다. 77 | 78 | 79 | 80 | 이 템플릿에서 `person.firstname`을 렌더링합니다. 이는 부분 템플릿이 아닙니다. 81 | 82 | ## 인라인 부분 템플릿 83 | 84 | 템플릿은 `inline` 데코레이터를 통해 블록 범위의 부분 템플릿을 정의할 수 있습니다. 85 | 86 | 87 | 88 | 이는 각 자식에 대해 `myPartial` 부분 템플릿을 렌더링합니다. 89 | 90 | 각 인라인 부분 템플릿은 현재 블록과 모든 자식에게 사용 가능하며, 다른 부분 템플릿의 실행을 포함합니다. 이는 레이아웃 템 91 | 플릿과 유사한 기능을 제공합니다. 92 | 93 | 94 | 95 | `layout` 부분 템플릿은 다음과 같습니다: 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/.vitepress/components/playground/ShareUrlModal.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 57 | 58 | 104 | --------------------------------------------------------------------------------