├── .github
├── FUNDING.yml
└── workflows
│ ├── BuildDeployAbiesWebAssembly.yml
│ └── CreateRelease.yml
├── .gitignore
├── CHANGELOG.md
├── Generate-ReleaseNotes.cmd
├── Handlebars.Net.Helpers.sln
├── Handlebars.Net.Helpers.sln.DotSettings
├── LICENSE
├── README.md
├── azure-pipeline-ci.yml
├── azure-pipelines-nuget.yml
├── examples
├── AbiesWebAssembly
│ ├── AbiesWebAssembly.csproj
│ ├── Fluent.cs
│ ├── Program.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── launchSettings.json
│ └── wwwroot
│ │ ├── abies.js
│ │ ├── css
│ │ ├── app.css
│ │ └── bootstrap
│ │ │ ├── bootstrap.min.css
│ │ │ └── bootstrap.min.css.map
│ │ ├── favicon.png
│ │ ├── icon-192.png
│ │ └── index.html
├── BlazorAppWebAssembly
│ ├── App.razor
│ ├── BlazorAppWebAssembly.csproj
│ ├── Layout
│ │ ├── MainLayout.razor
│ │ ├── MainLayout.razor.css
│ │ ├── NavMenu.razor
│ │ └── NavMenu.razor.css
│ ├── Pages
│ │ ├── Counter.razor
│ │ ├── Home.razor
│ │ └── Weather.razor
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ └── wwwroot
│ │ ├── css
│ │ ├── app.css
│ │ └── bootstrap
│ │ │ ├── bootstrap.min.css
│ │ │ └── bootstrap.min.css.map
│ │ ├── favicon.png
│ │ ├── icon-192.png
│ │ ├── index.html
│ │ └── sample-data
│ │ └── weather.json
└── ConsoleApp
│ ├── ConsoleApp.csproj
│ └── Program.cs
├── resources
├── hbnet-icon.png
├── hbnet-icon_32x32.png
├── myget-add.png
├── myget-use.png
└── nuget-settings.png
├── src
├── Directory.Build.props
├── Handlebars.Net.Helpers.Core
│ ├── Attributes
│ │ └── HandlebarsWriterAttribute.cs
│ ├── Enums
│ │ ├── Category.cs
│ │ ├── HelperUsage.cs
│ │ └── WriterType.cs
│ ├── Extensions
│ │ └── ParameterInfoExtensions.cs
│ ├── GlobalUsings.cs
│ ├── Handlebars.Net.Helpers.Core.csproj
│ ├── Helpers
│ │ ├── BaseHelpers.cs
│ │ └── IHelpers.cs
│ ├── IO
│ │ └── PassthroughTextEncoder.cs
│ ├── Json
│ │ ├── DataContractJsonSerializerStrategy.cs
│ │ ├── IJsonSerializerStrategy.cs
│ │ ├── JsonArray.cs
│ │ ├── JsonObject.cs
│ │ ├── PocoJsonSerializerStrategy.cs
│ │ ├── ReflectionUtils.cs
│ │ └── SimpleJson.cs
│ ├── Options
│ │ ├── HandlebarsDynamicLinqHelperOptions.cs
│ │ └── HandlebarsHelpersOptions.cs
│ ├── Parsers
│ │ ├── ArgumentsParser.cs
│ │ └── StringValueParser.cs
│ └── Utils
│ │ ├── ArrayUtils.cs
│ │ ├── DateTimeService.cs
│ │ ├── DefaultValueCache.cs
│ │ ├── EnumUtils.cs
│ │ ├── IDateTimeService.cs
│ │ └── ObjectUtils.cs
├── Handlebars.Net.Helpers.DynamicLinq
│ ├── Handlebars.Net.Helpers.DynamicLinq.csproj
│ ├── Helpers
│ │ └── DynamicLinqHelpers.cs
│ ├── JArrayMerger.cs
│ ├── JObjectExtensions.cs
│ ├── Models
│ │ ├── DynamicJsonClassOptions.cs
│ │ ├── FloatBehavior.cs
│ │ └── IntegerBehavior.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.Humanizer
│ ├── Handlebars.Net.Helpers.Humanizer.csproj
│ ├── Helpers
│ │ └── HumanizerHelpers.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.Json
│ ├── Handlebars.Net.Helpers.Json.csproj
│ ├── Helpers
│ │ └── JsonPathHelpers.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── Utils
│ │ └── JsonUtils.cs
├── Handlebars.Net.Helpers.Random
│ ├── Handlebars.Net.Helpers.Random.csproj
│ ├── Helpers
│ │ └── RandomHelpers.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.XPath
│ ├── Handlebars.Net.Helpers.XPath.csproj
│ ├── Helpers
│ │ └── XPathHelpers.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.Xeger
│ ├── Handlebars.Net.Helpers.Xeger.csproj
│ ├── Helpers
│ │ └── XegerHelpers.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.Xslt
│ ├── Handlebars.Net.Helpers.Xslt.csproj
│ ├── Helpers
│ │ └── XsltHelpers.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── Handlebars.Net.Helpers.snk
├── Handlebars.Net.Helpers
│ ├── Compatibility
│ │ └── AppContextHelper.cs
│ ├── Extensions
│ │ ├── IHandlebarsExtensions.cs
│ │ └── MethodBaseExtensions.cs
│ ├── Handlebars.Net.Helpers.csproj
│ ├── HandlebarsHelpers.cs
│ ├── Helpers
│ │ ├── BooleanHelpers.cs
│ │ ├── ConstantsHelpers.cs
│ │ ├── DateTimeHelpers.cs
│ │ ├── EnumerableHelpers.cs
│ │ ├── EnvironmentHelpers.cs
│ │ ├── EvaluateHelper.cs
│ │ ├── MathHelpers.cs
│ │ ├── ObjectHelpers.cs
│ │ ├── RegexHelpers.cs
│ │ ├── StringHelpers.cs
│ │ └── UrlHelpers.cs
│ ├── Models
│ │ ├── EvaluateResult.cs
│ │ └── WrappedString.cs
│ ├── Plugin
│ │ └── PluginLoader.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── Utils
│ │ ├── ExecuteUtils.cs
│ │ ├── HtmlUtils.cs
│ │ ├── ReflectionUtils.cs
│ │ ├── RegexUtils.cs
│ │ └── RuntimeInformationUtils.cs
└── sign.txt
└── test
└── Handlebars.Net.Helpers.Tests
├── DynamicLinq
└── JArrayMergerTests.cs
├── Handlebars.Net.Helpers.Tests.csproj
├── Helpers
├── BooleanHelpersTests.cs
├── DateTimeHelpersTests.cs
├── EnumerableHelpersTests.cs
├── EnvironmentHelpersTests.cs
├── ExecuteUtilsTests.cs
├── HumanizerHelpersTests.cs
├── MathHelpersTests.cs
├── ObjectHelpersTests.cs
├── Parsers
│ └── StringValueParserTests.cs
├── RandomHelpersTests.cs
├── StringHelpersTests.cs
├── UrlHelpersTests.cs
├── XPathHelpersTests.cs
├── XegerHelpersTests.cs
└── XsltHelpersTests.cs
├── IO
└── PassthroughTextEncoderTests.cs
├── Models
└── WrappedStringTests.cs
├── Templates
├── BooleanHelpersTemplateTests.cs
├── ConstantsHelpersTemplateTests.cs
├── DateTimeHelpersTemplateTests.cs
├── DynamicLinqHelpersTemplateTests.cs
├── EnumerableHelpersTemplateTests.cs
├── EnvironmentHelpersTemplateTests.cs
├── EvaluateHelperTemplateTests.cs
├── HumanizerHelpersTemplateTests.cs
├── JsonPathHelpersTemplateTests.cs
├── MathHelpersTemplateTests.cs
├── ObjectHelpersTemplateTests.cs
├── PathHelpersTemplateTests.cs
├── RandomHelpersTemplateTests.cs
├── RegexHelpersTemplateTests.cs
├── StringHelpersTemplateTests.cs
├── XPathHelpersTemplateTests.cs
└── XsltHelpersTemplateTests.cs
└── Utils
└── ArrayUtilsTests.cs
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [StefH]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://www.paypal.me/stefheyenrath
13 |
--------------------------------------------------------------------------------
/.github/workflows/BuildDeployAbiesWebAssembly.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy AbiesWebAssembly
2 |
3 | on:
4 | push:
5 | branches:
6 | - example-Abies
7 |
8 | jobs:
9 | build-and-deploy:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout Code
14 | uses: actions/checkout@v4
15 |
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v4
18 | with:
19 | dotnet-version: '9.0.x'
20 |
21 | - name: Restore Dependencies
22 | run: dotnet restore ./examples/AbiesWebAssembly/AbiesWebAssembly.csproj
23 |
24 | - name: Build Project
25 | run: dotnet publish ./examples/AbiesWebAssembly/AbiesWebAssembly.csproj -c Release -o build
26 |
27 | - name: Deploy to GitHub Pages
28 | uses: peaceiris/actions-gh-pages@v4
29 | with:
30 | github_token: ${{ secrets.GITHUB_TOKEN }}
31 | publish_dir: ./build/wwwroot
32 | # destination_dir: Handlebars.Net.Helpers
--------------------------------------------------------------------------------
/.github/workflows/CreateRelease.yml:
--------------------------------------------------------------------------------
1 | name: CreateRelease
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*.*.*"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v2
14 |
15 | - name: Release
16 | uses: softprops/action-gh-release@v2
17 | with:
18 | generate_release_notes: true
19 |
--------------------------------------------------------------------------------
/Generate-ReleaseNotes.cmd:
--------------------------------------------------------------------------------
1 | rem https://github.com/StefH/GitHubReleaseNotes
2 |
3 | SET version=2.5.2
4 |
5 | GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid documentation duplicate --version %version% --token %GH_TOKEN%
--------------------------------------------------------------------------------
/Handlebars.Net.Helpers.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | WASM
3 | True
4 | True
5 | True
6 | True
7 | True
8 | True
9 | True
10 | True
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Stef Heyenrath
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/azure-pipeline-ci.yml:
--------------------------------------------------------------------------------
1 | pool:
2 | vmImage: 'windows-2022'
3 |
4 | variables:
5 | Prerelease: 'ci'
6 | buildId: "1$(Build.BuildId)"
7 | buildProjects: '**/src/**/Handlebars.Net*.csproj'
8 |
9 | steps:
10 | # Print buildId
11 | - script: |
12 | echo "BuildId = $(buildId)"
13 | displayName: 'Print buildId'
14 |
15 | - task: PowerShell@2
16 | displayName: "Use JDK11 by default"
17 | inputs:
18 | targetType: 'inline'
19 | script: |
20 | $jdkPath = $env:JAVA_HOME_11_X64
21 | Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
22 |
23 | - task: SonarCloudPrepare@1
24 | displayName: 'Prepare analysis on SonarCloud'
25 | condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
26 | inputs:
27 | SonarCloud: SonarCloud
28 | organization: stefh-github
29 | projectKey: 'Handlebars.Net.Helpers'
30 | projectName: 'Handlebars.Net.Helpers'
31 | extraProperties: |
32 | sonar.cs.opencover.reportsPaths=**/coverage.net6.0.opencover.xml
33 |
34 | # Build source, tests and run tests for net452 and net6.0 (with coverage)
35 | - script: |
36 | dotnet test ./test/Handlebars.Net.Helpers.Tests/Handlebars.Net.Helpers.Tests.csproj --configuration Debug --framework net452
37 | dotnet test ./test/Handlebars.Net.Helpers.Tests/Handlebars.Net.Helpers.Tests.csproj --configuration Debug --framework net6.0 --logger trx /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
38 | displayName: 'Build source, tests and run tests for net452 and net6.0 (with coverage)'
39 |
40 | - task: SonarCloudAnalyze@1
41 | displayName: 'SonarCloud: Run Code Analysis'
42 | condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
43 |
44 | - task: SonarCloudPublish@1
45 | displayName: 'SonarCloud: Publish Quality Gate Result'
46 | condition: and(succeeded(), eq(variables['RUN_SONAR'], 'yes'), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
47 |
48 | - task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
49 | displayName: 'WhiteSource Bolt'
50 | condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
51 |
52 | # Upload coverage to codecov.io
53 | - script: |
54 | %USERPROFILE%\.nuget\packages\codecov\1.10.0\tools\codecov.exe -f "./test/Handlebars.Net.Helpers.Tests/coverage.net6.0.opencover.xml" -t $(CODECOV_TOKEN)
55 | displayName: Upload coverage to codecov.io
56 |
57 | # https://github.com/microsoft/azure-pipelines-tasks/issues/12212
58 | - task: PublishTestResults@2
59 | condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
60 | inputs:
61 | testRunner: VSTest
62 | testResultsFiles: '**/*.trx'
63 |
64 | # Based on https://whereslou.com/2018/09/versioning-and-publishing-nuget-packages-automatically-using-azure-devops-pipelines/
65 | - task: DotNetCoreCLI@2
66 | displayName: Build Release
67 | inputs:
68 | command: 'build'
69 | arguments: /p:Configuration=Release # https://github.com/MicrosoftDocs/vsts-docs/issues/1976
70 | projects: $(buildProjects)
71 |
72 | - task: DotNetCoreCLI@2
73 | displayName: Pack
74 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
75 | inputs:
76 | command: pack
77 | configuration: 'Release'
78 | packagesToPack: $(buildProjects)
79 | nobuild: true
80 | packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
81 | verbosityPack: 'normal'
82 |
83 | - task: PublishBuildArtifacts@1
84 | displayName: Publish Artifacts
85 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
86 | inputs:
87 | PathtoPublish: '$(Build.ArtifactStagingDirectory)'
88 |
89 | # https://github.com/NuGet/Home/issues/8148
90 | - task: DotNetCoreCLI@2
91 | displayName: Push to MyGet
92 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
93 | inputs:
94 | command: custom
95 | custom: nuget
96 | arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n -s https://www.myget.org/F/handlebars_net_helpers/api/v3/index.json -k $(MyGetKey)
--------------------------------------------------------------------------------
/azure-pipelines-nuget.yml:
--------------------------------------------------------------------------------
1 | pool:
2 | vmImage: 'windows-2022'
3 |
4 | variables:
5 | Prerelease: ''
6 | buildId: "1$(Build.BuildId)"
7 | buildProjects: '**/src/**/Handlebars.Net.Helpers*.csproj'
8 |
9 | steps:
10 | # Print buildId
11 | - script: |
12 | echo "BuildId = $(buildId)"
13 | displayName: 'Print buildId'
14 |
15 | # Based on https://whereslou.com/2018/09/versioning-and-publishing-nuget-packages-automatically-using-azure-devops-pipelines/
16 | - task: DotNetCoreCLI@2
17 | displayName: Build Release
18 | inputs:
19 | command: 'build'
20 | arguments: /p:Configuration=Release # https://github.com/MicrosoftDocs/vsts-docs/issues/1976
21 | projects: $(buildProjects)
22 |
23 | - task: DotNetCoreCLI@2
24 | displayName: Pack
25 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
26 | inputs:
27 | command: pack
28 | configuration: 'Release'
29 | packagesToPack: $(buildProjects)
30 | nobuild: true
31 | packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
32 | verbosityPack: 'normal'
33 |
34 | - task: PublishBuildArtifacts@1
35 | displayName: Publish Artifacts
36 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
37 | inputs:
38 | PathtoPublish: '$(Build.ArtifactStagingDirectory)'
39 |
40 | - task: DotNetCoreCLI@2
41 | displayName: Push to NuGet
42 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
43 | inputs:
44 | command: custom
45 | custom: nuget
46 | arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n -s https://api.nuget.org/v3/index.json -k $(NuGetKey)
47 |
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/AbiesWebAssembly.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0
4 | true
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/Fluent.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using Abies.DOM;
3 | using static Abies.Html.Elements;
4 |
5 | namespace AbiesWebAssembly;
6 |
7 | public static class Fluent
8 | {
9 | public static Element button(Attribute[] attributes, Element[] children, [CallerLineNumber] int id = 0)
10 | => element("fluent-button", attributes, children, id);
11 | }
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | [assembly:System.Runtime.Versioning.SupportedOSPlatform("browser")]
5 |
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AbiesWebAssembly": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "environmentVariables": {
7 | "ASPNETCORE_ENVIRONMENT": "Development"
8 | },
9 | "applicationUrl": "https://127.0.0.1:58287/",
10 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/wwwroot/css/app.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | }
4 |
5 | h1:focus {
6 | outline: none;
7 | }
8 |
9 | a, .btn-link {
10 | color: #0071c1;
11 | }
12 |
13 | .btn-primary {
14 | color: #fff;
15 | background-color: #1b6ec2;
16 | border-color: #1861ac;
17 | }
18 |
19 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
20 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
21 | }
22 |
23 | .content {
24 | padding-top: 1.1rem;
25 | }
26 |
27 | .valid.modified:not([type=checkbox]) {
28 | outline: 1px solid #26b050;
29 | }
30 |
31 | .invalid {
32 | outline: 1px solid red;
33 | }
34 |
35 | .validation-message {
36 | color: red;
37 | }
38 |
39 | #blazor-error-ui {
40 | background: lightyellow;
41 | bottom: 0;
42 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
43 | display: none;
44 | left: 0;
45 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
46 | position: fixed;
47 | width: 100%;
48 | z-index: 1000;
49 | }
50 |
51 | #blazor-error-ui .dismiss {
52 | cursor: pointer;
53 | position: absolute;
54 | right: 0.75rem;
55 | top: 0.5rem;
56 | }
57 |
58 | .blazor-error-boundary {
59 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
60 | padding: 1rem 1rem 1rem 3.7rem;
61 | color: white;
62 | }
63 |
64 | .blazor-error-boundary::after {
65 | content: "An error has occurred."
66 | }
67 |
68 | .loading-progress {
69 | position: relative;
70 | display: block;
71 | width: 8rem;
72 | height: 8rem;
73 | margin: 20vh auto 1rem auto;
74 | }
75 |
76 | .loading-progress circle {
77 | fill: none;
78 | stroke: #e0e0e0;
79 | stroke-width: 0.6rem;
80 | transform-origin: 50% 50%;
81 | transform: rotate(-90deg);
82 | }
83 |
84 | .loading-progress circle:last-child {
85 | stroke: #1b6ec2;
86 | stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
87 | transition: stroke-dasharray 0.05s ease-in-out;
88 | }
89 |
90 | .loading-progress-text {
91 | position: absolute;
92 | text-align: center;
93 | font-weight: bold;
94 | inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
95 | }
96 |
97 | .loading-progress-text:after {
98 | content: var(--blazor-load-percentage-text, "Loading");
99 | }
100 |
101 | code {
102 | color: #c02d76;
103 | }
104 |
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/wwwroot/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/examples/AbiesWebAssembly/wwwroot/favicon.png
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/wwwroot/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/examples/AbiesWebAssembly/wwwroot/icon-192.png
--------------------------------------------------------------------------------
/examples/AbiesWebAssembly/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HandlebarsNetTestApp
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Not found
8 |
9 | Sorry, there's nothing at this address.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/BlazorAppWebAssembly.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Layout/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
6 |
7 |
8 |
11 |
12 |
13 | @Body
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Layout/MainLayout.razor.css:
--------------------------------------------------------------------------------
1 | .page {
2 | position: relative;
3 | display: flex;
4 | flex-direction: column;
5 | }
6 |
7 | main {
8 | flex: 1;
9 | }
10 |
11 | .sidebar {
12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
13 | }
14 |
15 | .top-row {
16 | background-color: #f7f7f7;
17 | border-bottom: 1px solid #d6d5d5;
18 | justify-content: flex-end;
19 | height: 3.5rem;
20 | display: flex;
21 | align-items: center;
22 | }
23 |
24 | .top-row ::deep a, .top-row ::deep .btn-link {
25 | white-space: nowrap;
26 | margin-left: 1.5rem;
27 | text-decoration: none;
28 | }
29 |
30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
31 | text-decoration: underline;
32 | }
33 |
34 | .top-row ::deep a:first-child {
35 | overflow: hidden;
36 | text-overflow: ellipsis;
37 | }
38 |
39 | @media (max-width: 640.98px) {
40 | .top-row {
41 | justify-content: space-between;
42 | }
43 |
44 | .top-row ::deep a, .top-row ::deep .btn-link {
45 | margin-left: 0;
46 | }
47 | }
48 |
49 | @media (min-width: 641px) {
50 | .page {
51 | flex-direction: row;
52 | }
53 |
54 | .sidebar {
55 | width: 250px;
56 | height: 100vh;
57 | position: sticky;
58 | top: 0;
59 | }
60 |
61 | .top-row {
62 | position: sticky;
63 | top: 0;
64 | z-index: 1;
65 | }
66 |
67 | .top-row.auth ::deep a:first-child {
68 | flex: 1;
69 | text-align: right;
70 | width: 0;
71 | }
72 |
73 | .top-row, article {
74 | padding-left: 2rem !important;
75 | padding-right: 1.5rem !important;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Layout/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
9 |
10 |
29 |
30 | @code {
31 | private bool collapseNavMenu = true;
32 |
33 | private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
34 |
35 | private void ToggleNavMenu()
36 | {
37 | collapseNavMenu = !collapseNavMenu;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Layout/NavMenu.razor.css:
--------------------------------------------------------------------------------
1 | .navbar-toggler {
2 | background-color: rgba(255, 255, 255, 0.1);
3 | }
4 |
5 | .top-row {
6 | height: 3.5rem;
7 | background-color: rgba(0,0,0,0.4);
8 | }
9 |
10 | .navbar-brand {
11 | font-size: 1.1rem;
12 | }
13 |
14 | .bi {
15 | display: inline-block;
16 | position: relative;
17 | width: 1.25rem;
18 | height: 1.25rem;
19 | margin-right: 0.75rem;
20 | top: -1px;
21 | background-size: cover;
22 | }
23 |
24 | .bi-house-door-fill-nav-menu {
25 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
26 | }
27 |
28 | .bi-plus-square-fill-nav-menu {
29 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
30 | }
31 |
32 | .bi-list-nested-nav-menu {
33 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
34 | }
35 |
36 | .nav-item {
37 | font-size: 0.9rem;
38 | padding-bottom: 0.5rem;
39 | }
40 |
41 | .nav-item:first-of-type {
42 | padding-top: 1rem;
43 | }
44 |
45 | .nav-item:last-of-type {
46 | padding-bottom: 1rem;
47 | }
48 |
49 | .nav-item ::deep a {
50 | color: #d7d7d7;
51 | border-radius: 4px;
52 | height: 3rem;
53 | display: flex;
54 | align-items: center;
55 | line-height: 3rem;
56 | }
57 |
58 | .nav-item ::deep a.active {
59 | background-color: rgba(255,255,255,0.37);
60 | color: white;
61 | }
62 |
63 | .nav-item ::deep a:hover {
64 | background-color: rgba(255,255,255,0.1);
65 | color: white;
66 | }
67 |
68 | @media (min-width: 641px) {
69 | .navbar-toggler {
70 | display: none;
71 | }
72 |
73 | .collapse {
74 | /* Never collapse the sidebar for wide screens */
75 | display: block;
76 | }
77 |
78 | .nav-scrollable {
79 | /* Allow sidebar to scroll for tall menus */
80 | height: calc(100vh - 3.5rem);
81 | overflow-y: auto;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Pages/Counter.razor:
--------------------------------------------------------------------------------
1 | @page "/counter"
2 |
3 | Counter
4 |
5 | Counter
6 |
7 | Current count: @currentCount
8 |
9 |
10 |
11 | @code {
12 | private int currentCount = 0;
13 |
14 | private void IncrementCount()
15 | {
16 | currentCount++;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Program.cs:
--------------------------------------------------------------------------------
1 | using BlazorAppWebAssembly;
2 | using Microsoft.AspNetCore.Components.Web;
3 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
4 |
5 | var builder = WebAssemblyHostBuilder.CreateDefault(args);
6 | builder.RootComponents.Add("#app");
7 | builder.RootComponents.Add("head::after");
8 |
9 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
10 |
11 | await builder.Build().RunAsync();
12 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:32881",
8 | "sslPort": 44390
9 | }
10 | },
11 | "profiles": {
12 | "http": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
17 | "applicationUrl": "http://localhost:5196",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "https": {
23 | "commandName": "Project",
24 | "dotnetRunMessages": true,
25 | "launchBrowser": true,
26 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
27 | "applicationUrl": "https://localhost:7087;http://localhost:5196",
28 | "environmentVariables": {
29 | "ASPNETCORE_ENVIRONMENT": "Development"
30 | }
31 | },
32 | "IIS Express": {
33 | "commandName": "IISExpress",
34 | "launchBrowser": true,
35 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
36 | "environmentVariables": {
37 | "ASPNETCORE_ENVIRONMENT": "Development"
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using System.Net.Http.Json
3 | @using Microsoft.AspNetCore.Components.Forms
4 | @using Microsoft.AspNetCore.Components.Routing
5 | @using Microsoft.AspNetCore.Components.Web
6 | @using Microsoft.AspNetCore.Components.Web.Virtualization
7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http
8 | @using Microsoft.JSInterop
9 | @using BlazorAppWebAssembly
10 | @using BlazorAppWebAssembly.Layout
11 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/wwwroot/css/app.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | }
4 |
5 | h1:focus {
6 | outline: none;
7 | }
8 |
9 | a, .btn-link {
10 | color: #0071c1;
11 | }
12 |
13 | .btn-primary {
14 | color: #fff;
15 | background-color: #1b6ec2;
16 | border-color: #1861ac;
17 | }
18 |
19 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
20 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
21 | }
22 |
23 | .content {
24 | padding-top: 1.1rem;
25 | }
26 |
27 | .valid.modified:not([type=checkbox]) {
28 | outline: 1px solid #26b050;
29 | }
30 |
31 | .invalid {
32 | outline: 1px solid red;
33 | }
34 |
35 | .validation-message {
36 | color: red;
37 | }
38 |
39 | #blazor-error-ui {
40 | background: lightyellow;
41 | bottom: 0;
42 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
43 | display: none;
44 | left: 0;
45 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
46 | position: fixed;
47 | width: 100%;
48 | z-index: 1000;
49 | }
50 |
51 | #blazor-error-ui .dismiss {
52 | cursor: pointer;
53 | position: absolute;
54 | right: 0.75rem;
55 | top: 0.5rem;
56 | }
57 |
58 | .blazor-error-boundary {
59 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
60 | padding: 1rem 1rem 1rem 3.7rem;
61 | color: white;
62 | }
63 |
64 | .blazor-error-boundary::after {
65 | content: "An error has occurred."
66 | }
67 |
68 | .loading-progress {
69 | position: relative;
70 | display: block;
71 | width: 8rem;
72 | height: 8rem;
73 | margin: 20vh auto 1rem auto;
74 | }
75 |
76 | .loading-progress circle {
77 | fill: none;
78 | stroke: #e0e0e0;
79 | stroke-width: 0.6rem;
80 | transform-origin: 50% 50%;
81 | transform: rotate(-90deg);
82 | }
83 |
84 | .loading-progress circle:last-child {
85 | stroke: #1b6ec2;
86 | stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
87 | transition: stroke-dasharray 0.05s ease-in-out;
88 | }
89 |
90 | .loading-progress-text {
91 | position: absolute;
92 | text-align: center;
93 | font-weight: bold;
94 | inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
95 | }
96 |
97 | .loading-progress-text:after {
98 | content: var(--blazor-load-percentage-text, "Loading");
99 | }
100 |
101 | code {
102 | color: #c02d76;
103 | }
104 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/wwwroot/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/examples/BlazorAppWebAssembly/wwwroot/favicon.png
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/wwwroot/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/examples/BlazorAppWebAssembly/wwwroot/icon-192.png
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | BlazorAppWebAssembly
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 | An unhandled error has occurred.
26 |
Reload
27 |
🗙
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/BlazorAppWebAssembly/wwwroot/sample-data/weather.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "2022-01-06",
4 | "temperatureC": 1,
5 | "summary": "Freezing"
6 | },
7 | {
8 | "date": "2022-01-07",
9 | "temperatureC": 14,
10 | "summary": "Bracing"
11 | },
12 | {
13 | "date": "2022-01-08",
14 | "temperatureC": -13,
15 | "summary": "Freezing"
16 | },
17 | {
18 | "date": "2022-01-09",
19 | "temperatureC": -16,
20 | "summary": "Balmy"
21 | },
22 | {
23 | "date": "2022-01-10",
24 | "temperatureC": -2,
25 | "summary": "Chilly"
26 | }
27 | ]
28 |
--------------------------------------------------------------------------------
/examples/ConsoleApp/ConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/resources/hbnet-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/resources/hbnet-icon.png
--------------------------------------------------------------------------------
/resources/hbnet-icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/resources/hbnet-icon_32x32.png
--------------------------------------------------------------------------------
/resources/myget-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/resources/myget-add.png
--------------------------------------------------------------------------------
/resources/myget-use.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/resources/myget-use.png
--------------------------------------------------------------------------------
/resources/nuget-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/3785ba7eb61dd343c6ace3b26cf94e3c8f85d04f/resources/nuget-settings.png
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(MsBuildAllProjects);$(MsBuildThisFileFullPath)
4 |
5 |
6 |
7 | net451;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;net6.0;net8.0
8 | 2.5.2
9 | 12
10 | enable
11 | Copyright © 2020-2025 Stef Heyenrath
12 | Stef Heyenrath
13 | See CHANGELOG.md
14 | https://raw.githubusercontent.com/Handlebars-Net/Handlebars.Net.Helpers/master/resources/hbnet-icon.png
15 | https://github.com/Handlebars-Net/Handlebars.Net.Helpers
16 | MIT
17 | git
18 | https://github.com/Handlebars-Net/Handlebars.Net.Helpers
19 |
20 |
21 |
22 | true
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | $(Prerelease)-1$(BUILD_BUILDID)
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Attributes/HandlebarsWriterAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HandlebarsDotNet.Helpers.Enums;
3 |
4 | namespace HandlebarsDotNet.Helpers.Attributes;
5 |
6 | [AttributeUsage(AttributeTargets.Method)]
7 | public class HandlebarsWriterAttribute : Attribute
8 | {
9 | public WriterType Type { get; }
10 |
11 | public string? Name { get; set; }
12 |
13 | public HelperUsage Usage { get; set; }
14 |
15 | public bool PassContext { get; set; }
16 |
17 | public HandlebarsWriterAttribute(WriterType type, string? name = null) : this(type, HelperUsage.Both, name)
18 | {
19 | }
20 |
21 | public HandlebarsWriterAttribute(WriterType type, HelperUsage usage, string? name = null) : this(type, usage, false, name)
22 | {
23 | }
24 |
25 | public HandlebarsWriterAttribute(WriterType type, HelperUsage usage, bool passContext, string? name = null)
26 | {
27 | Type = type;
28 | Name = name;
29 | Usage = usage;
30 | PassContext = passContext;
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Enums/Category.cs:
--------------------------------------------------------------------------------
1 | namespace HandlebarsDotNet.Helpers.Enums;
2 |
3 | public enum Category
4 | {
5 | Constants,
6 | Enumerable,
7 | Environment,
8 | Math,
9 | Regex,
10 | String,
11 | Url,
12 | DateTime,
13 | XPath,
14 | Xeger,
15 | Random,
16 | JsonPath,
17 | DynamicLinq,
18 | Humanizer,
19 | Boolean,
20 | Object,
21 | Xslt,
22 | Custom // Custom helpers. Not used by the library itself.
23 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Enums/HelperUsage.cs:
--------------------------------------------------------------------------------
1 | namespace HandlebarsDotNet.Helpers.Enums;
2 |
3 | public enum HelperUsage
4 | {
5 | Both,
6 | Normal,
7 | Block
8 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Enums/WriterType.cs:
--------------------------------------------------------------------------------
1 | namespace HandlebarsDotNet.Helpers.Enums;
2 |
3 | public enum WriterType
4 | {
5 | Value,
6 |
7 | String
8 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Extensions/ParameterInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace HandlebarsDotNet.Helpers.Extensions;
4 |
5 | public static class ParameterInfoExtensions
6 | {
7 | public static bool IsParam(this ParameterInfo? parameterInfo)
8 | {
9 | return parameterInfo?.IsDefined(typeof(ParamArrayAttribute)) == true;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using global::System;
2 | global using global::System.IO;
3 | #if !(NET35 || NET40)
4 | global using global::System.Threading;
5 | global using global::System.Threading.Tasks;
6 | #endif
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Handlebars.Net.Helpers.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HandlebarsDotNet.Helpers
5 | HandlebarsDotNet.Helpers.Core
6 | Core functionality for Handlebars.Net.Helpers
7 | Handlebars.Net.Helpers.Core
8 | handlebars;helpers;extensions;core;models;interfaces;common
9 | handlebars;helper;models;interfaces
10 | {7CBD113C-A754-480B-B0D0-AA9DF734F612}
11 | true
12 | ../Handlebars.Net.Helpers.snk
13 | $(DefineConstants);SIMPLE_JSON_INTERNAL
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 | $(DefineConstants);SIMPLE_JSON_DATACONTRACT;SIMPLE_JSON_DYNAMIC
27 |
28 |
29 |
30 | $(DefineConstants);SIMPLE_JSON_TYPEINFO
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Helpers/BaseHelpers.cs:
--------------------------------------------------------------------------------
1 | using HandlebarsDotNet.Helpers.Options;
2 | using Stef.Validation;
3 |
4 | namespace HandlebarsDotNet.Helpers.Helpers;
5 |
6 | public abstract class BaseHelpers(IHandlebars context, HandlebarsHelpersOptions options)
7 | {
8 | protected readonly IHandlebars Context = Guard.NotNull(context);
9 | protected readonly HandlebarsHelpersOptions Options = Guard.NotNull(options);
10 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Helpers/IHelpers.cs:
--------------------------------------------------------------------------------
1 | using HandlebarsDotNet.Helpers.Enums;
2 |
3 | namespace HandlebarsDotNet.Helpers.Helpers;
4 |
5 | public interface IHelpers
6 | {
7 | Category Category { get; }
8 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/IO/PassthroughTextEncoder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 |
4 | namespace HandlebarsDotNet.Helpers.IO;
5 |
6 | ///
7 | /// A text encoder that implements and directly passes through the input text to the target without any encoding.
8 | ///
9 | public class PassthroughTextEncoder : ITextEncoder
10 | {
11 | ///
12 | /// Writes the given StringBuilder text directly to the target TextWriter.
13 | ///
14 | /// The StringBuilder containing the text.
15 | /// The TextWriter to write the text to.
16 | public void Encode(StringBuilder text, TextWriter target)
17 | {
18 | target.Write(text);
19 | }
20 |
21 | ///
22 | /// Writes the given string text directly to the target TextWriter.
23 | ///
24 | /// The string containing the text.
25 | /// The TextWriter to write the text to.
26 | public void Encode(string text, TextWriter target)
27 | {
28 | target.Write(text);
29 | }
30 |
31 | ///
32 | /// Writes the given text enumerator directly to the target TextWriter.
33 | ///
34 | /// The type of the text enumerator.
35 | /// The enumerator containing the text.
36 | /// The TextWriter to write the text to.
37 | public void Encode(T text, TextWriter target) where T : IEnumerator
38 | {
39 | while (text.MoveNext())
40 | {
41 | target.Write(text.Current);
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Json/DataContractJsonSerializerStrategy.cs:
--------------------------------------------------------------------------------
1 | using System.CodeDom.Compiler;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Runtime.Serialization;
5 |
6 | namespace HandlebarsDotNet.Helpers.Json;
7 |
8 | #if SIMPLE_JSON_DATACONTRACT
9 | [GeneratedCode("simple-json", "1.0.0")]
10 | #if SIMPLE_JSON_INTERNAL
11 | internal
12 | #else
13 | public
14 | #endif
15 | class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy
16 | {
17 | public DataContractJsonSerializerStrategy()
18 | {
19 | GetCache = new ReflectionUtils.ThreadSafeDictionary>(GetterValueFactory);
20 | SetCache = new ReflectionUtils.ThreadSafeDictionary>>(SetterValueFactory);
21 | }
22 |
23 | internal override IDictionary GetterValueFactory(Type type)
24 | {
25 | bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
26 | if (!hasDataContract)
27 | {
28 | return base.GetterValueFactory(type);
29 | }
30 |
31 | string jsonKey;
32 | IDictionary result = new Dictionary();
33 | foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
34 | {
35 | if (propertyInfo.CanRead)
36 | {
37 | MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
38 | if (!getMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
39 | result[jsonKey] = ReflectionUtils.GetGetMethod(propertyInfo);
40 | }
41 | }
42 | foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
43 | {
44 | if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
45 | result[jsonKey] = ReflectionUtils.GetGetMethod(fieldInfo);
46 | }
47 | return result;
48 | }
49 |
50 | internal override IDictionary> SetterValueFactory(Type type)
51 | {
52 | bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
53 | if (!hasDataContract)
54 | return base.SetterValueFactory(type);
55 | string jsonKey;
56 | IDictionary> result = new Dictionary>();
57 | foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
58 | {
59 | if (propertyInfo.CanWrite)
60 | {
61 | MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);
62 | if (!setMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
63 | result[jsonKey] = new KeyValuePair(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));
64 | }
65 | }
66 | foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
67 | {
68 | if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
69 | result[jsonKey] = new KeyValuePair(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));
70 | }
71 | // todo implement sorting for DATACONTRACT.
72 | return result;
73 | }
74 |
75 | private static bool CanAdd(MemberInfo info, out string jsonKey)
76 | {
77 | jsonKey = null;
78 | if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)
79 | return false;
80 | DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
81 | if (dataMemberAttribute == null)
82 | return false;
83 | jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;
84 | return true;
85 | }
86 | }
87 |
88 | #endif
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Json/IJsonSerializerStrategy.cs:
--------------------------------------------------------------------------------
1 | using System.CodeDom.Compiler;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace HandlebarsDotNet.Helpers.Json;
5 |
6 | [GeneratedCode("simple-json", "1.0.0")]
7 | #if SIMPLE_JSON_INTERNAL
8 | internal
9 | #else
10 | public
11 | #endif
12 | interface IJsonSerializerStrategy
13 | {
14 | [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")]
15 | bool TrySerializeNonPrimitiveObject(object? input, [NotNullWhen(true)] out object? output);
16 |
17 | object? DeserializeObject(object? value, Type type);
18 | }
--------------------------------------------------------------------------------
/src/Handlebars.Net.Helpers.Core/Json/JsonArray.cs:
--------------------------------------------------------------------------------
1 | using System.CodeDom.Compiler;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 |
5 | namespace HandlebarsDotNet.Helpers.Json;
6 |
7 | ///
8 | /// Represents the json array.
9 | ///
10 | [GeneratedCode("simple-json", "1.0.0")]
11 | [EditorBrowsable(EditorBrowsableState.Never)]
12 | #if SIMPLE_JSON_OBJARRAYINTERNAL
13 | internal
14 | #else
15 | public
16 | #endif
17 | class JsonArray : List