├── _config.yml
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── custom.md
│ ├── feature_request.md
│ └── bug_report.md
├── LazZiya.TagHelpers
├── files
│ ├── icon.ico
│ ├── icon.png
│ ├── license.txt
│ └── Templates
│ │ ├── LocalizationValidationScripts_local.html
│ │ └── LocalizationValidationScripts_jsdeliver.html
├── RenderMode.cs
├── PagingAjaxMode.cs
├── LanguageNavModels.cs
├── PhoneNumberTagHelper.cs
├── EmailTagHelper.cs
├── LocalizationValidiationScriptsTagHelper.cs
├── Utilities
│ ├── GenericTempDataExtensions.cs
│ ├── RomanNumerals.cs
│ └── NumberFormats.cs
├── SelectEnumTagHelper.cs
├── LazZiya.TagHelpers.csproj
├── AlertStylesTagHelper.cs
├── LocalizationValidiationScriptsTagHelperComponent.cs
├── Properties
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Alerts
│ ├── AlertModels.cs
│ └── AlertPageModelExtensions.cs
├── AlertTagHelper.cs
├── LanguageNavTagHelper.cs
├── PagingTagHelper.cs
└── LazZiya.TagHelpers.xml
├── LICENSE
├── TagHelpers.sln
├── README.md
├── ReleseHistory.md
├── .gitattributes
└── .gitignore
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: lazziya
2 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/files/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LazZiya/TagHelpers/HEAD/LazZiya.TagHelpers/files/icon.ico
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/files/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LazZiya/TagHelpers/HEAD/LazZiya.TagHelpers/files/icon.png
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/RenderMode.cs:
--------------------------------------------------------------------------------
1 | namespace LazZiya.TagHelpers
2 | {
3 | ///
4 | /// choose render mode style,
5 | /// classic: regular dropdown select list
6 | /// Bootstrap4: HTML5 div with Bootstrap4 support
7 | ///
8 | public enum RenderMode
9 | {
10 | ///
11 | /// regular dropdown list
12 | ///
13 | Classic = 0,
14 |
15 | ///
16 | /// HTML5 div with Bootstrap 4 support
17 | ///
18 | Bootstrap = 1,
19 |
20 | ///
21 | /// Render as form control
22 | ///
23 | FormControl = 2,
24 | ///
25 | /// HTML5 div with Bootstrap 5 support
26 | ///
27 | Bootstrap5 = 3
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/PagingAjaxMode.cs:
--------------------------------------------------------------------------------
1 | namespace LazZiya.TagHelpers
2 | {
3 | ///
4 | /// ajax update modes
5 | ///
6 | public enum PagingAjaxMode
7 | {
8 | ///
9 | /// update before target content
10 | ///
11 | before,
12 |
13 | ///
14 | /// update after target content
15 | ///
16 | after,
17 |
18 | ///
19 | /// replace target content
20 | ///
21 | replace
22 | }
23 |
24 | ///
25 | /// The http request method
26 | ///
27 | public enum AjaxMethod
28 | {
29 | ///
30 | /// get request
31 | ///
32 | get,
33 |
34 | ///
35 | /// post request
36 | ///
37 | post
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LanguageNavModels.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LazZiya.TagHelpers
4 | {
5 | ///
6 | /// The label to display for language dropdown list on language names
7 | ///
8 | public enum LanguageLabel
9 | {
10 | ///
11 | /// Culture name
12 | ///
13 | Name,
14 |
15 | ///
16 | /// Culture display name
17 | ///
18 | DisplayName,
19 |
20 | ///
21 | /// Culture English name
22 | ///
23 | EnglishName,
24 |
25 | ///
26 | /// Culture native name
27 | ///
28 | NativeName,
29 |
30 | ///
31 | /// Two letter ISO language name
32 | ///
33 | TwoLetterISOLanguageName
34 | }
35 |
36 | internal class LanguageItem
37 | {
38 | public string Name { get; set; }
39 | public string DisplayText { get; set; }
40 | public string Url { get; set; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 [Ziya Mollamahmut](http://ziyad.info)
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 |
--------------------------------------------------------------------------------
/TagHelpers.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.31903.286
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LazZiya.TagHelpers", "LazZiya.TagHelpers\LazZiya.TagHelpers.csproj", "{080D63B6-33A9-47D5-99FF-F636542694EB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {080D63B6-33A9-47D5-99FF-F636542694EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {080D63B6-33A9-47D5-99FF-F636542694EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {080D63B6-33A9-47D5-99FF-F636542694EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {080D63B6-33A9-47D5-99FF-F636542694EB}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {ED31C13F-823E-406C-87BA-4BC36A23816A}
24 | BuildVersion_StartDate = 2000/1/1
25 | EndGlobalSection
26 | EndGlobal
27 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/files/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 |
4 | Copyright (c) 2018 [Ziya Mollamahmut](http://ziyad.info)
5 |
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 |
9 | of this software and associated documentation files (the "Software"), to deal
10 |
11 | in the Software without restriction, including without limitation the rights
12 |
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 |
15 | copies of the Software, and to permit persons to whom the Software is
16 |
17 | furnished to do so, subject to the following conditions:
18 |
19 |
20 |
21 | The above copyright notice and this permission notice shall be included in all
22 |
23 | copies or substantial portions of the Software.
24 |
25 |
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 |
29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 |
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 |
33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 |
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 |
37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 |
39 | SOFTWARE.
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/PhoneNumberTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Razor.TagHelpers;
2 | using System.Threading.Tasks;
3 |
4 | namespace LazZiya.TagHelpers
5 | {
6 | ///
7 | /// creates a display for phone number
8 | ///
9 | public class PhoneNumberTagHelper : TagHelper
10 | {
11 | ///
12 | /// boolean value to indicate if the phone number has been confirmed
13 | ///
14 | public bool PhoneNumberConfirmed { get; set; }
15 |
16 | ///
17 | /// process creating phone number tag helper
18 | ///
19 | ///
20 | ///
21 | ///
22 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
23 | {
24 | output.TagName = "span";
25 |
26 | var content = await output.GetChildContentAsync();
27 |
28 | var target = content.GetContent();
29 | output.Content.SetContent(target.Replace("+", "+"));
30 | output.Attributes.SetAttribute("dir", "ltr");
31 |
32 | if (PhoneNumberConfirmed)
33 | output.PreContent.SetHtmlContent("");
34 | else
35 | output.PreContent.SetHtmlContent("");
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/EmailTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Razor.TagHelpers;
2 | using System.Threading.Tasks;
3 |
4 | namespace LazZiya.TagHelpers
5 | {
6 | ///
7 | /// creates email link with mark if email is confirmed
8 | ///
9 | public class EmailTagHelper : TagHelper
10 | {
11 | ///
12 | /// boolean value to indicate if the email is confirmed or not
13 | ///
14 | public bool EmailConfirmed { get; set; }
15 |
16 | ///
17 | /// process in creating email tag helper
18 | ///
19 | ///
20 | ///
21 | ///
22 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
23 | {
24 | output.TagName = "a"; // Replaces with tag
25 |
26 | var content = await output.GetChildContentAsync();
27 | var target = content.GetContent();
28 |
29 | output.Attributes.SetAttribute("href", "mailto:" + target);
30 | output.Content.SetContent(target);
31 |
32 | if (EmailConfirmed)
33 | output.PreContent.SetHtmlContent("");
34 | else
35 | output.PreContent.SetHtmlContent("");
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/files/Templates/LocalizationValidationScripts_local.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
34 |
35 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LocalizationValidiationScriptsTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
2 | using Microsoft.AspNetCore.Razor.TagHelpers;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 |
6 | namespace LazZiya.TagHelpers
7 | {
8 | ///
9 | /// defines location to load localization valdiation scripts
10 | ///
11 | public enum ScriptSource
12 | {
13 | ///
14 | /// valdiation scripts are located under wwwroot/lib folder
15 | ///
16 | Local,
17 |
18 | ///
19 | /// valdiation scripts will be loaded from jsdelivr
20 | ///
21 | JsDeliver
22 | }
23 |
24 | ///
25 | /// Tag helper for client side localized validation scripts.
26 | ///
27 | [HtmlTargetElement("localization-validation-scripts")]
28 | public class LocalizationValidationScriptsTagHelperComponentTagHelper : TagHelperComponentTagHelper
29 | {
30 | ///
31 | /// (optional) define where to load scripts from, Local or JsDelivr.
32 | /// Default: JsDelivr
33 | ///
34 | [HtmlAttributeName("source")]
35 | public ScriptSource Source { get; set; } = ScriptSource.JsDeliver;
36 |
37 | ///
38 | /// (optional) set cldr version to load.
39 | /// Default: 35.1
40 | ///
41 | [HtmlAttributeName("cldr-core-version")]
42 | public string CldrVersion { get; set; } = "35.1.0";
43 |
44 | ///
45 | /// Tag helper for client side localized validation scripts.
46 | ///
47 | public LocalizationValidationScriptsTagHelperComponentTagHelper(ITagHelperComponentManager manager, ILoggerFactory loggerFactory) : base(manager, loggerFactory)
48 | {
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Utilities/GenericTempDataExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.ViewFeatures;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
6 | using Newtonsoft.Json;
7 | #else
8 | using System.Text.Json;
9 | #endif
10 |
11 | namespace LazZiya.TagHelpers.Utilities
12 | {
13 | ///
14 | /// Generic extension to TempData for adding complex object and fix serialization problem
15 | ///
16 | ///
17 | public static class GenericTempDataExtensions
18 | {
19 | ///
20 | /// Add object to temp data
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | public static void Put(this ITempDataDictionary tempData, string key, T value) where T : class
27 | {
28 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
29 | tempData[key] = JsonConvert.SerializeObject(value);
30 | #else
31 | tempData[key] = JsonSerializer.Serialize(value);
32 | #endif
33 | }
34 |
35 | ///
36 | /// Read object from temp data
37 | ///
38 | ///
39 | ///
40 | ///
41 | ///
42 | public static T Get(this ITempDataDictionary tempData, string key) where T : class
43 | {
44 | tempData.TryGetValue(key, out object o);
45 |
46 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
47 | var obj = JsonConvert.DeserializeObject((string)o);
48 | #else
49 | var obj = JsonSerializer.Deserialize((string)o);
50 | #endif
51 | return o == null ? null : obj;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LazZiya.TagHelpers
2 |
3 | ## What is it?
4 | A collection of useful TagHelpers for any ASP.NET Core project.
5 |
6 | ## Documentation :
7 | See all documentation in [DOCS.Ziya.info.tr][1].
8 |
9 | ### [Paging TagHelper][1]
10 | Create a pagination control _styled with bootstrap 4.x_ using simple html tag.
11 |
12 | ````html
13 |
16 |
17 | ````
18 | [][1]
19 |
20 | ### [Alert TagHelper ][1]
21 | Create bootstrap alerts using very simple html tag.
22 |
23 | #### Front end alert
24 | ````html
25 |
26 | My alert text ...
27 |
28 | ````
29 |
30 | #### Backend alert
31 | ````cs
32 | TempData.Success("My alert text ...")
33 | ````
34 |
35 | Catch all backend alerts in frontend:
36 | ````html
37 |
38 | ````
39 |
40 | [][1]
41 |
42 | ### [Language Navigation TagHelper][1]
43 | Create a language dropdown navigation for websites. Supported cultures will be used to create the navigation items.
44 |
45 | ````html
46 |
47 | ````
48 | [][1]
49 |
50 | ### [Localization Validation Scripts TagHelper][1]
51 | Add all client side scripts that are required for validating localized inputs like decimal numbers, dates, ..etc.
52 | ````html
53 |
54 | ````
55 | [][1]
56 |
57 | ## Live demos:
58 | http://demo.ziyad.info/en/
59 |
60 | [1]:https://docs.ziya.info.tr
61 |
--------------------------------------------------------------------------------
/ReleseHistory.md:
--------------------------------------------------------------------------------
1 | # LazZiya.TagHelpers Release History
2 |
3 | ## v3.0.0-preview1
4 | _02 Sep 2019_
5 |
6 | - **DotNetCore 3.0 Support :** Added support for dotnet core 3.0.
7 | - **LanguageTagHelper :** Auto RTL direction for Language TagHelper dropdown
8 |
9 | ## v2.2.1
10 | _20 June 2019_
11 |
12 | - **Hotfix for Alert TagHelper :** See related isse here https://github.com/LazZiya/TagHelpers/issues/2
13 |
14 | ## v2.2.0
15 | _07 June 2019_
16 |
17 | - **Alert TagHelper :** Show bootstrap alerts from c# backend or razor side using simple html tags.
18 | - Documentation : http://www.ziyad.info/en/articles/37-Alert_TagHelpers
19 | - Live demo : http://demo.ziyad.info/en/Alerts
20 |
21 | ## v2.1.0
22 | _26 May 2019_
23 |
24 | - **LocalizationValidationScripts TagHelper :** TagHelperComponent to inject all cldr-data and localization validation scripts to razor pages.
25 | - Documentation : http://www.ziyad.info/en/articles/34-Localization_Validation_Scripts
26 | - Live demo : http://demo.ziyad.info/en/Trips
27 |
28 | ## v2.0.0
29 | _14 April 2019_
30 |
31 | - **Backward compatibility :** support for multiple target frameworks starting from .Net Core v1.0+
32 | - **LanguageNav TagHelper :** Create language navigation for multicultural web applications
33 | - Documentation : http://www.ziyad.info/en/articles/32-Language_Navigation_TagHelper
34 | - Live demo : http://demo.ziyad.info/en/LanguageNav
35 |
36 | ## v1.0.3
37 | _14 February 2019_
38 |
39 | - **SelectEnum TagHelper :** Create dropdown list from enum with localization support
40 | - Documentation : http://www.ziyad.info/en/articles/28-Select_Enum_TagHelper
41 | - Live demo : http://demo.ziyad.info/en/SelectEnum
42 |
43 | ## v1.0.1
44 | _17 September 2019_
45 |
46 | - **Paging TagHelper :** easily create pagination control
47 | - Documentation : http://www.ziyad.info/en/articles/21-Paging_TagHelper_for_ASP_NET_Core
48 | - Live demo : http://demo.ziyad.info/en/Paging
49 | - Step by step tutorial : http://www.ziyad.info/en/articles/38-How_to_build_an_efficient_pagination_system
50 |
51 | ## Project site:
52 | http://ziyad.info/en/articles/27-LazZiya_TagHelpers
53 |
54 | ## Live Demos :
55 | http://demo.ziyad.info/en/
56 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Utilities/RomanNumerals.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace LazZiya.TagHelpers.Utilities
5 | {
6 | ///
7 | /// Convert decimals to roman numerals
8 | ///
9 | public static class RomanNumerals
10 | {
11 | ///
12 | /// Dictionary of roman numbers and their equavilant decimals
13 | ///
14 | ///
15 | public static Dictionary RomanNumbers =
16 | new Dictionary
17 | {
18 | { 1000000, "M̅" },
19 | { 900000, "C̅M̅" },
20 |
21 | { 500000, "D̅" },
22 | { 400000, "C̅D̅" },
23 |
24 | { 100000, "C̅" },
25 | { 90000, "X̅C̅" },
26 |
27 | { 50000, "L̅" },
28 | { 40000, "X̅L̅" },
29 |
30 | { 10000, "X̅" },
31 | { 9000, "I̅X̅" },
32 |
33 | { 5000, "V̅" },
34 | { 4000, "I̅V̅" },
35 |
36 | { 1000, "M" },
37 | { 900, "DM" },
38 |
39 | { 500, "D" },
40 | { 400, "CD" },
41 |
42 | { 100, "C" },
43 | { 90, "XC" },
44 |
45 | { 50, "L" },
46 | { 40, "XL" },
47 |
48 | { 10, "X" },
49 | { 9, "IX" },
50 |
51 | { 5, "V" },
52 | { 4, "IV" },
53 |
54 | { 1, "I" },
55 | };
56 |
57 | ///
58 | /// Convert decimal number to roman number
59 | ///
60 | /// unsigned number
61 | /// Roman number
62 | public static string ToRoman(this uint number)
63 | {
64 | var romanNum = string.Empty;
65 |
66 | while (number > 0)
67 | {
68 | var item = RomanNumbers
69 | .OrderByDescending(x => x.Key)
70 | .First(x => x.Key <= number);
71 | romanNum += item.Value;
72 | number -= item.Key;
73 | }
74 |
75 | return romanNum;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/files/Templates/LocalizationValidationScripts_jsdeliver.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
34 |
35 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/SelectEnumTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Rendering;
2 | using Microsoft.AspNetCore.Razor.TagHelpers;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.Linq;
7 |
8 | namespace LazZiya.TagHelpers
9 | {
10 | ///
11 | /// creates a dropdown list from custom enum with supports for localization
12 | ///
13 | public class SelectEnumTagHelper : TagHelper
14 | {
15 | private readonly ILogger _log;
16 |
17 | ///
18 | /// (int)MyEnum.ValueName
19 | ///
20 | public int SelectedValue { get; set; }
21 |
22 | ///
23 | /// typeof(MyEnum)
24 | ///
25 | public Type EnumType { get; set; }
26 |
27 | ///
28 | /// A delegate function for getting locaized value.
29 | ///
30 | public Func TextLocalizerDelegate { get; set; }
31 |
32 | ///
33 | /// Initialize a new instance of SelectEnum taghelper
34 | ///
35 | ///
36 | public SelectEnumTagHelper(ILogger log)
37 | {
38 | _log = log;
39 | }
40 |
41 | ///
42 | /// start creating select-enum tag helper
43 | ///
44 | ///
45 | ///
46 | public override void Process(TagHelperContext context, TagHelperOutput output)
47 | {
48 | output.TagName = "select";
49 |
50 | foreach (int e in Enum.GetValues(EnumType))
51 | {
52 | var op = new TagBuilder("option");
53 |
54 | op.Attributes.Add("value", $"{e}");
55 |
56 | var displayText = TextLocalizerDelegate == null
57 | ? GetEnumFieldDisplayName(e)
58 | : GetEnumFieldLocalizedDisplayName(e);
59 |
60 | op.InnerHtml.Append(displayText);
61 |
62 | if (e == SelectedValue)
63 | op.Attributes.Add("selected", "selected");
64 |
65 | output.Content.AppendHtml(op);
66 | }
67 | }
68 |
69 | private string GetEnumFieldDisplayName(int value)
70 | {
71 | // get enum field name
72 | var fieldName = Enum.GetName(EnumType, value);
73 |
74 | //get Display(Name = "Field name")
75 | var displayName = EnumType.GetField(fieldName).GetCustomAttributes(false).OfType().SingleOrDefault()?.Name;
76 |
77 | return displayName ?? fieldName;
78 | }
79 |
80 | private string GetEnumFieldLocalizedDisplayName(int value)
81 | {
82 | var text = GetEnumFieldDisplayName(value);
83 |
84 | return TextLocalizerDelegate(text);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LazZiya.TagHelpers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0;netcoreapp2.1;netcoreapp2.2;netcoreapp3.0;netcoreapp3.1;net5.0;net6.0
5 | files\icon.ico
6 | Ziya Mollamahmut
7 | Ziyad.info
8 | Collection of tag helpers for ASP.NET Core web applications, like Paging, SelectEnum and LanguageNav dropdown tag helpers for MVC and Razor Pages.
9 | Ziyad.info
10 | https://docs.ziyad.info/en/LazZiya.TagHelpers/v6.0/index.md
11 | icon.png
12 | true
13 | asp.net, core, razor, mvc, taghelpers, taghelper,tag,helper,language,culture,dropdown, pagination, select, enum
14 |
15 | - New public param "url-template" use custom url template for the paging buttons.
16 | - Fixed #21 https://github.com/LazZiya/TagHelpers/issues/21
17 | - Fixed #27 https://github.com/LazZiya/TagHelpers/issues/27
18 | - See all release notes in https://github.com/LazZiya/TagHelpers/releases
19 |
20 | 6.0.2
21 |
22 | 6.0.2.0
23 | 6.0.2.0
24 | false
25 | MIT
26 | https://raw.githubusercontent.com/LazZiya/TagHelpers/master/LazZiya.TagHelpers/files/icon.png
27 | https://github.com/LazZiya/TagHelpers
28 |
29 |
30 |
31 | LazZiya.TagHelpers.xml
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Always
58 |
59 |
60 | Always
61 |
62 |
63 |
64 |
65 |
66 |
67 | True
68 | True
69 | Resources.resx
70 |
71 |
72 |
73 |
74 |
75 | ResXFileCodeGenerator
76 | Resources.Designer.cs
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/AlertStylesTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Razor.TagHelpers;
2 | using LazZiya.TagHelpers.Alerts;
3 | using System.Threading.Tasks;
4 |
5 | namespace LazZiya.TagHelpers
6 | {
7 | ///
8 | /// Create primary alert
9 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
10 | ///
11 | public class AlertPrimaryTagHelper : AlertTagHelper
12 | {
13 | ///
14 | /// Create primary alert
15 | ///
16 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
17 | {
18 | base.AlertStyle = AlertStyle.Primary;
19 | await base.ProcessAsync(context, output);
20 | }
21 | }
22 |
23 | ///
24 | /// Create secondary alert
25 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
26 | ///
27 | public class AlertSecondaryTagHelper : AlertTagHelper
28 | {
29 | ///
30 | /// Create secondary alert
31 | ///
32 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
33 | {
34 | base.AlertStyle = AlertStyle.Secondary;
35 | await base.ProcessAsync(context, output);
36 | }
37 | }
38 |
39 | ///
40 | /// Create success alert
41 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
42 | ///
43 | public class AlertSuccessTagHelper : AlertTagHelper
44 | {
45 | ///
46 | /// Create success alert
47 | ///
48 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
49 | {
50 | base.AlertStyle = AlertStyle.Success;
51 | await base.ProcessAsync(context, output);
52 | }
53 | }
54 |
55 | ///
56 | /// Create danger alert
57 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
58 | ///
59 | public class AlertDangerTagHelper : AlertTagHelper
60 | {
61 | ///
62 | /// Create danger alert
63 | ///
64 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
65 | {
66 | base.AlertStyle = AlertStyle.Danger;
67 | await base.ProcessAsync(context, output);
68 | }
69 | }
70 |
71 | ///
72 | /// Create warning alert
73 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
74 | ///
75 | public class AlertWarningTagHelper : AlertTagHelper
76 | {
77 | ///
78 | /// Create danger alert
79 | ///
80 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
81 | {
82 | base.AlertStyle = AlertStyle.Warning;
83 | await base.ProcessAsync(context, output);
84 | }
85 | }
86 |
87 | ///
88 | /// Create info alert
89 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
90 | ///
91 | public class AlertInfoTagHelper : AlertTagHelper
92 | {
93 | ///
94 | /// Create info alert
95 | ///
96 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
97 | {
98 | base.AlertStyle = AlertStyle.Info;
99 | await base.ProcessAsync(context, output);
100 | }
101 | }
102 |
103 | ///
104 | /// Create light alert
105 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
106 | ///
107 | public class AlertLightTagHelper : AlertTagHelper
108 | {
109 | ///
110 | /// Create light alert
111 | ///
112 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
113 | {
114 | base.AlertStyle = AlertStyle.Light;
115 | await base.ProcessAsync(context, output);
116 | }
117 | }
118 |
119 | ///
120 | /// Create dark alert
121 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
122 | ///
123 | public class AlertDarkTagHelper : AlertTagHelper
124 | {
125 | ///
126 | /// Create dark alert
127 | ///
128 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
129 | {
130 | base.AlertStyle = AlertStyle.Dark;
131 | await base.ProcessAsync(context, output);
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LocalizationValidiationScriptsTagHelperComponent.cs:
--------------------------------------------------------------------------------
1 | using LazZiya.TagHelpers.Properties;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.Razor.TagHelpers;
4 | using System;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Linq;
8 |
9 | namespace LazZiya.TagHelpers
10 | {
11 | ///
12 | /// Tag helper component for client side localized validation scripts.
13 | ///
14 | public class LocalizationValidationScriptsTagHelperComponent : TagHelperComponent
15 | {
16 |
17 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
18 | private readonly IHostingEnvironment _hosting;
19 |
20 | ///
21 | /// Tag helper component for client side localized validation scripts.
22 | ///
23 | ///
24 | public LocalizationValidationScriptsTagHelperComponent(IHostingEnvironment hosting)
25 | {
26 | _hosting = hosting;
27 | }
28 | #else
29 | private readonly IWebHostEnvironment _hosting;
30 |
31 | ///
32 | /// inserts all localizaiton validation scripts into relevant tag
33 | ///
34 | ///
35 | public LocalizationValidationScriptsTagHelperComponent(IWebHostEnvironment hosting)
36 | {
37 | _hosting = hosting;
38 | }
39 | #endif
40 | ///
41 | /// default order is 0
42 | ///
43 | public override int Order => 1;
44 |
45 | ///
46 | /// generate the taghelper
47 | ///
48 | ///
49 | ///
50 | public override void Process(TagHelperContext context, TagHelperOutput output)
51 | {
52 | if (string.Equals(context.TagName, "localization-validation-scripts", StringComparison.OrdinalIgnoreCase))
53 | {
54 | //read source attribute
55 | var sourceAttribute = GetAttribute(context, "source", ScriptSource.JsDeliver);
56 |
57 | //get the value of the source property
58 | Enum.TryParse(sourceAttribute.Value.ToString(), out ScriptSource _scriptSource);
59 | //assign relevant script file accordingly
60 | var _script = _scriptSource == ScriptSource.JsDeliver
61 | ? Resources.LocalizationValidationScripts_jsdeliver
62 | : Resources.LocalizationValidationScripts_local;
63 |
64 | //read cldr-core-version attribute
65 | var cldrCoreVersionAttribute = GetAttribute(context, "cldr-core-version", "35.1.0");
66 | var cldrCoreVersion = cldrCoreVersionAttribute.Value.ToString();
67 |
68 | var culture = _scriptSource == ScriptSource.JsDeliver
69 | ? CultureInfo.CurrentCulture.Name
70 | : GetCultureName();
71 |
72 | // Some cultures do not have scripts in jsDelivr e.g. en-us, es-es,
73 | // so switch to parent culture
74 | string[] nonSupportedCultres = { "en-us", "es-es" };
75 | culture = nonSupportedCultres.Any(x => x.Equals(culture, StringComparison.OrdinalIgnoreCase))
76 | ? culture.Split('-')[0]
77 | : culture;
78 |
79 | output.PostContent.AppendHtml(_script.Replace("{culture}", culture)
80 | .Replace("{cldr-core-version}", cldrCoreVersion));
81 | }
82 | }
83 |
84 | private TagHelperAttribute GetAttribute(TagHelperContext context, string tagName, object defaultValue)
85 | {
86 | //get the source property from the taghelper
87 | context.AllAttributes.TryGetAttribute(tagName, out TagHelperAttribute attribute);
88 |
89 | return attribute ?? new TagHelperAttribute(tagName, defaultValue);
90 | }
91 |
92 | ///
93 | /// find json files related to the current culture, if not found return parent culture, if not found return default culture.
94 | /// see ClientSideValidationScripts.html for how to configure paths
95 | ///
96 | /// culture name e.g. tr
97 | private string GetCultureName()
98 | {
99 | // use this pattern to check if the relevant json folder are available
100 | const string localePattern = "lib\\cldr-data\\main\\{0}";
101 | var currentCulture = CultureInfo.CurrentCulture;
102 | var cultureToUse = "en"; //Default regionalisation to use
103 |
104 | if (Directory.Exists(Path.Combine(_hosting.WebRootPath, string.Format(localePattern, currentCulture.Name))))
105 | cultureToUse = currentCulture.Name;
106 | else if (Directory.Exists(Path.Combine(_hosting.WebRootPath, string.Format(localePattern, currentCulture.TwoLetterISOLanguageName))))
107 | cultureToUse = currentCulture.TwoLetterISOLanguageName;
108 |
109 | return cultureToUse;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace LazZiya.TagHelpers.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LazZiya.TagHelpers.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to <!-- cldr scripts (needed for globalize) -->
65 | ///<script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr.js"></script>
66 | ///<script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr/event.js"></script>
67 | ///<script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr/supplemental.js"></script>
68 | ///
69 | ///<!-- globalize scripts -->
70 | ///<script src="https://cdn.jsdelivr.net/gh/globalizejs/globalize@1.4.2/dist/globalize.js"></script>
71 | ///<script src="https://cdn.jsdelivr.net/gh/globalizejs/g [rest of string was truncated]";.
72 | ///
73 | internal static string LocalizationValidationScripts_jsdeliver {
74 | get {
75 | return ResourceManager.GetString("LocalizationValidationScripts_jsdeliver", resourceCulture);
76 | }
77 | }
78 |
79 | ///
80 | /// Looks up a localized string similar to <!-- cldr scripts (needed for globalize) -->
81 | ///<script src="/lib/cldr/dist/cldr.min.js"></script>
82 | ///<script src="/lib/cldr/dist/cldr/event.min.js"></script>
83 | ///<script src="/lib/cldr/dist/cldr/supplemental.min.js"></script>
84 | ///
85 | ///<!-- globalize scripts -->
86 | ///<script src="/lib/globalize/dist/globalize.min.js"></script>
87 | ///<script src="/lib/globalize/dist/globalize/number.min.js"></script>
88 | ///<script src="/lib/globalize/dist/globalize/date.min.js"></script>
89 | ///<script src="/lib/globalize/dist/globalize/currency.min.js"></s [rest of string was truncated]";.
90 | ///
91 | internal static string LocalizationValidationScripts_local {
92 | get {
93 | return ResourceManager.GetString("LocalizationValidationScripts_local", resourceCulture);
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Alerts/AlertModels.cs:
--------------------------------------------------------------------------------
1 | namespace LazZiya.TagHelpers.Alerts
2 | {
3 | ///
4 | /// Define alert style depending on Bootstrap4.x alert classes
5 | ///
6 | internal enum AlertStyle {
7 | ///
8 | /// alert-primary
9 | ///
10 | Primary,
11 |
12 | ///
13 | /// alert-secondary
14 | ///
15 | Secondary,
16 |
17 | ///
18 | /// alert-success
19 | ///
20 | Success,
21 |
22 | ///
23 | /// alert-danger
24 | ///
25 | Danger,
26 |
27 | ///
28 | /// alert-warning
29 | ///
30 | Warning,
31 |
32 | ///
33 | /// alert-info
34 | ///
35 | Info,
36 |
37 | ///
38 | /// alert-light
39 | ///
40 | Light,
41 |
42 | ///
43 | /// alert-dark
44 | ///
45 | Dark
46 | }
47 |
48 | ///
49 | /// Choose where to get alert icons from
50 | ///
51 | public enum IconsSource
52 | {
53 | ///
54 | /// Bootstrap
55 | ///
56 | Bootstrap,
57 |
58 | ///
59 | /// Bootstrap5
60 | ///
61 | Bootstrap5,
62 |
63 | ///
64 | /// FontAwesome
65 | ///
66 | FontAwesome
67 | }
68 |
69 | internal struct Bootstrap5Icons
70 | {
71 | internal const string Success = "";
72 |
73 | internal const string Warning = "";
74 |
75 | internal const string Info = "";
76 |
77 | internal const string Danger = "";
78 |
79 | internal const string Default = Info;
80 | }
81 |
82 | internal struct BootstrapIcons
83 | {
84 | internal const string Success = "bi bi-check-circle-fill";
85 | internal const string Warning = "bi bi-exclamation-triangle-fill";
86 | internal const string Info = "bi bi-info-circle-fill";
87 | internal const string Danger = "bi bi-x-circle-fill";
88 | internal const string Default = "bi bi-info-circle";
89 | }
90 |
91 | internal struct FontAwesomeIcons
92 | {
93 | internal const string Success = "fas fa-check-circle";
94 | internal const string Warning = "fas fa-exclamation-triangle";
95 | internal const string Info = "fas fa-info-circle";
96 | internal const string Danger = "fas fa-times-circle";
97 | internal const string Default = "fas fa-chevron-circle-right";
98 | }
99 |
100 | ///
101 | /// Alert item that can be created in the backend manually for pushing alert to the temp data
102 | ///
103 | internal class Alert
104 | {
105 | ///
106 | /// Key to find alerts in TempData dictionary
107 | ///
108 | public const string TempDataKey = "TempDataAlert";
109 |
110 | ///
111 | /// Alert style depending on Bootstrap 4.x classes
112 | ///
113 | public AlertStyle AlertStyle { get; set; } = AlertStyle.Primary;
114 |
115 | ///
116 | /// Header text for the alert message
117 | ///
118 | public string AlertHeading { get; set; }
119 |
120 | ///
121 | /// Alert message body
122 | ///
123 | public string AlertMessage { get; set; }
124 |
125 | ///
126 | /// true for dismissable alert
127 | ///
128 | public bool Dismissable { get; set; } = true;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Alerts/AlertPageModelExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using LazZiya.TagHelpers.Utilities;
3 | using Microsoft.AspNetCore.Mvc.ViewFeatures;
4 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
5 | using Newtonsoft.Json;
6 | #else
7 | using System.Text.Json;
8 | #endif
9 |
10 | namespace LazZiya.TagHelpers.Alerts
11 | {
12 | ///
13 | /// Extensions for TempData for creating coder friendly alerts easily
14 | ///
15 | public static class TempDataExtensions
16 | {
17 | ///
18 | /// Create primary alert
19 | ///
20 | /// TempData
21 | /// message body
22 | /// message header
23 | /// Show closing button
24 | public static void Primary(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
25 | {
26 | AddAlert(tempData, AlertStyle.Primary, alertMessage, alertHeader, dismissable);
27 | }
28 |
29 | ///
30 | /// Create secondary alert
31 | ///
32 | /// TempData
33 | /// message body
34 | /// message header
35 | /// Show closing button
36 | public static void Secondary(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
37 | {
38 | AddAlert(tempData, AlertStyle.Secondary, alertMessage, alertHeader, dismissable);
39 | }
40 |
41 | ///
42 | /// Create success alert
43 | ///
44 | /// TempData
45 | /// message body
46 | /// message header
47 | /// Show closing button
48 | public static void Success(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
49 | {
50 | AddAlert(tempData, AlertStyle.Success, alertMessage, alertHeader, dismissable);
51 | }
52 |
53 | ///
54 | /// Create danger alert
55 | ///
56 | /// TempData
57 | /// message body
58 | /// message header
59 | /// Show closing button
60 | public static void Danger(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
61 | {
62 | AddAlert(tempData, AlertStyle.Danger, alertMessage, alertHeader, dismissable);
63 | }
64 |
65 | ///
66 | /// Create warning alert
67 | ///
68 | /// TempData
69 | /// message body
70 | /// message header
71 | /// Show closing button
72 | public static void Warning(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
73 | {
74 | AddAlert(tempData, AlertStyle.Warning, alertMessage, alertHeader, dismissable);
75 | }
76 |
77 | ///
78 | /// Create info alert
79 | ///
80 | /// TempData
81 | /// message body
82 | /// message header
83 | /// Show closing button
84 | public static void Info(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
85 | {
86 | AddAlert(tempData, AlertStyle.Info, alertMessage, alertHeader, dismissable);
87 | }
88 |
89 | ///
90 | /// Create light alert
91 | ///
92 | /// TempData
93 | /// message body
94 | /// message header
95 | /// Show closing button
96 | public static void Light(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
97 | {
98 | AddAlert(tempData, AlertStyle.Light, alertMessage, alertHeader, dismissable);
99 | }
100 |
101 | ///
102 | /// Create dark alert
103 | ///
104 | /// TempData
105 | /// message body
106 | /// message header
107 | /// Show closing button
108 | public static void Dark(this ITempDataDictionary tempData, string alertMessage, string alertHeader = "", bool dismissable = true)
109 | {
110 | AddAlert(tempData, AlertStyle.Dark, alertMessage, alertHeader, dismissable);
111 | }
112 |
113 | private static void AddAlert(ITempDataDictionary tempData, AlertStyle alertStyle, string message, string header, bool dismissable)
114 | {
115 | #if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2
116 | var alerts = tempData.ContainsKey(Alert.TempDataKey)
117 | ? JsonConvert.DeserializeObject>(tempData[Alert.TempDataKey].ToString())
118 | : new List();
119 | #else
120 | var alerts = tempData.ContainsKey(Alert.TempDataKey)
121 | ? JsonSerializer.Deserialize>(tempData[Alert.TempDataKey].ToString())
122 | : new List();
123 | #endif
124 | alerts.Add(new Alert
125 | {
126 | AlertStyle = alertStyle,
127 | AlertHeading = header,
128 | AlertMessage = message,
129 | Dismissable = dismissable
130 | });
131 |
132 | tempData.Put>(Alert.TempDataKey, alerts);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\files\templates\localizationvalidationscripts_jsdeliver.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
123 |
124 |
125 | ..\files\templates\localizationvalidationscripts_local.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
126 |
127 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/Utilities/NumberFormats.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace LazZiya.TagHelpers.Utilities
5 | {
6 | ///
7 | /// Number formats for different cultures.
8 | /// https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/numberingSystems.json
9 | ///
10 | public static class NumberFormats
11 | {
12 | ///
13 | /// Receives a number in system format, and converts it to any other format.
14 | /// See
15 | ///
16 | ///
17 | ///
18 | ///
19 | public static string ToNumberFormat(this int number, string targetFormat)
20 | {
21 | string _str = string.Empty;
22 | switch (targetFormat)
23 | {
24 | case NumberFormats.Default: _str = number.ToString("N0"); break;
25 | case NumberFormats.Hex: _str = number.ToString("X"); break;
26 | case NumberFormats.Roman: _str = ((uint)number).ToRoman(); break;
27 | default:
28 | var numberStr = number.ToString();
29 | var newNum = string.Empty;
30 |
31 | for (int i = 0; i < numberStr.Length; i++)
32 | newNum += targetFormat.Split(' ')[int.Parse(numberStr[i].ToString())];
33 |
34 | _str = string.Join("", newNum);
35 | break;
36 | }
37 |
38 | return _str;
39 | }
40 |
41 | ///
42 | /// System default numbering format
43 | ///
44 | public const string Default = "default";
45 |
46 | ///
47 | /// 0123456789
48 | ///
49 | public const string Arabic = "0 1 2 3 4 5 6 7 8 9";
50 |
51 | ///
52 | /// Use hexadecimal numbering system
53 | ///
54 | public const string Hex = "hex";
55 |
56 | ///
57 | /// I II III IV V VI
58 | ///
59 | public const string Roman = "roman";
60 |
61 | ///
62 | /// ٠١٢٣٤٥٦٧٨٩
63 | ///
64 | public const string Hindi = "٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩";
65 |
66 | ///
67 | /// 𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯
68 | ///
69 | public const string Brah = "𑁦 𑁧 𑁨 𑁩 𑁪 𑁫 𑁬 𑁭 𑁮 𑁯";
70 |
71 | ///
72 | /// ০১২৩৪৫৬৭৮৯
73 | ///
74 | public const string Beng = "০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯";
75 |
76 | ///
77 | /// ०१२३४५६७८९
78 | ///
79 | public const string Deva = "० १ २ ३ ४ ५ ६ ७ ८ ९";
80 |
81 | ///
82 | /// ۰۱۲۳۴۵۶۷۸۹
83 | ///
84 | public const string Farsi = "۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹";
85 |
86 | ///
87 | /// 0123456789
88 | ///
89 | public const string Fullwide = "0 1 2 3 4 5 6 7 8 9";
90 |
91 | ///
92 | /// ೦೧೨೩೪೫೬೭೮೯
93 | ///
94 | public const string Knda = "೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯";
95 |
96 | ///
97 | /// ૦૧૨૩૪૫૬૭૮૯
98 | ///
99 | public const string Gujr = "૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯";
100 |
101 | ///
102 | /// ੦੧੨੩੪੫੬੭੮੯
103 | ///
104 | public const string Guru = "੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯";
105 |
106 | ///
107 | /// 〇一二三四五六七八九
108 | ///
109 | public const string Hanidec = "〇 一 二 三 四 五 六 七 八 九";
110 |
111 | ///
112 | /// ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙
113 | ///
114 | public const string Java = "꧐ ꧑ ꧒ ꧓ ꧔ ꧕ ꧖ ꧗ ꧘ ꧙";
115 |
116 | ///
117 | /// ០១២៣៤៥៦៧៨៩
118 | ///
119 | public const string Khmr = "០ ១ ២ ៣ ៤ ៥ ៦ ៧ ៨ ៩";
120 |
121 | ///
122 | /// ໐໑໒໓໔໕໖໗໘໙
123 | ///
124 | public const string Laoo = "໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙";
125 |
126 | ///
127 | /// 0123456789
128 | ///
129 | public const string Latin = "0 1 2 3 4 5 6 7 8 9";
130 |
131 | ///
132 | /// 𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗
133 | ///
134 | public const string Mathbold = "𝟎 𝟏 𝟐 𝟑 𝟒 𝟓 𝟔 𝟕 𝟖 𝟗";
135 |
136 | ///
137 | /// 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡
138 | ///
139 | public const string Mathborder = "𝟘 𝟙 𝟚 𝟛 𝟜 𝟝 𝟞 𝟟 𝟠 𝟡";
140 |
141 | ///
142 | /// 𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿
143 | ///
144 | public const string Mathmono = "𝟶 𝟷 𝟸 𝟹 𝟺 𝟻 𝟼 𝟽 𝟾 𝟿";
145 |
146 | ///
147 | /// 𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵
148 | ///
149 | public const string Mathanb = "𝟬 𝟭 𝟮 𝟯 𝟰 𝟱 𝟲 𝟳 𝟴 𝟵";
150 |
151 | ///
152 | /// 𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫
153 | ///
154 | public const string Mathsans = "𝟢 𝟣 𝟤 𝟥 𝟦 𝟧 𝟨 𝟩 𝟪 𝟫";
155 |
156 | ///
157 | /// ൦൧൨൩൪൫൬൭൮൯
158 | ///
159 | public const string Mlym = "൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯";
160 |
161 | ///
162 | /// ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙
163 | ///
164 | public const string Mong = "᠐ ᠑ ᠒ ᠓ ᠔ ᠕ ᠖ ᠗ ᠘ ᠙";
165 |
166 | ///
167 | /// ၀၁၂၃၄၅၆၇၈၉
168 | ///
169 | public const string Mymr = "၀ ၁ ၂ ၃ ၄ ၅ ၆ ၇ ၈ ၉";
170 |
171 | ///
172 | /// ႐႑႒႓႔႕႖႗႘႙
173 | ///
174 | public const string Mymrshan = "႐ ႑ ႒ ႓ ႔ ႕ ႖ ႗ ႘ ႙";
175 |
176 | ///
177 | /// ꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹
178 | ///
179 | public const string Mymtlng = "꧰ ꧱ ꧲ ꧳ ꧴ ꧵ ꧶ ꧷ ꧸ ꧹";
180 |
181 | ///
182 | /// ߀߁߂߃߄߅߆߇߈߉
183 | ///
184 | public const string Nkoo = "߀ ߁ ߂ ߃ ߄ ߅ ߆ ߇ ߈ ߉";
185 |
186 | ///
187 | /// ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙
188 | ///
189 | public const string Olck = "᱐ ᱑ ᱒ ᱓ ᱔ ᱕ ᱖ ᱗ ᱘ ᱙";
190 |
191 | ///
192 | /// ୦୧୨୩୪୫୬୭୮୯
193 | ///
194 | public const string Orya = "୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯";
195 |
196 | ///
197 | /// 𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩
198 | ///
199 | public const string Osma = "𐒠 𐒡 𐒢 𐒣 𐒤 𐒥 𐒦 𐒧 𐒨 𐒩";
200 |
201 | ///
202 | /// ෦෧෨෩෪෫෬෭෮෯
203 | ///
204 | public const string Sinh = "෦ ෧ ෨ ෩ ෪ ෫ ෬ ෭ ෮ ෯";
205 |
206 | ///
207 | /// ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙
208 | ///
209 | public const string Talu = "᧐ ᧑ ᧒ ᧓ ᧔ ᧕ ᧖ ᧗ ᧘ ᧙";
210 |
211 | ///
212 | /// ௦௧௨௩௪௫௬௭௮௯
213 | ///
214 | public const string Tamldec = "௦ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯";
215 |
216 | ///
217 | /// ౦౧౨౩౪౫౬౭౮౯
218 | ///
219 | public const string Telu = "౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯";
220 |
221 | ///
222 | /// ๐๑๒๓๔๕๖๗๘๙
223 | ///
224 | public const string Thai = "๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙";
225 |
226 | ///
227 | /// ༠༡༢༣༤༥༦༧༨༩
228 | ///
229 | public const string Tibt = "༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩";
230 |
231 | ///
232 | /// ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩
233 | ///
234 | public const string Vaii = "꘠ ꘡ ꘢ ꘣ ꘤ ꘥ ꘦ ꘧ ꘨ ꘩";
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/AlertTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Rendering;
2 | using Microsoft.AspNetCore.Razor.TagHelpers;
3 | using System;
4 | using System.Collections.Generic;
5 | using LazZiya.TagHelpers.Alerts;
6 | using System.Threading.Tasks;
7 | using LazZiya.TagHelpers.Utilities;
8 | using Microsoft.AspNetCore.Mvc.ViewFeatures;
9 | using Microsoft.Extensions.Localization;
10 | using System.Linq;
11 |
12 | namespace LazZiya.TagHelpers
13 | {
14 | ///
15 | /// Create alert messages styled with bootstrap 4.x
16 | /// Alert contents must be replaced between alert tags e.g. job done!]]>
17 | ///
18 | public class AlertTagHelper : TagHelper
19 | {
20 | internal AlertStyle AlertStyle { get; set; } = AlertStyle.Primary;
21 |
22 | ///
23 | /// Header text for the alert
24 | ///
25 | public string AlertHeading { get; set; }
26 |
27 | ///
28 | /// Show closing button, default is true
29 | ///
30 | public bool Dismissable { get; set; } = true;
31 |
32 | ///
33 | /// Show multiple alerts as slides
34 | ///
35 | public bool SlideAlerts { get; set; } = true;
36 |
37 | ///
38 | /// Show alert icons from fontawesome.
39 | /// Requires fontawesome css or bootstrap
40 | ///
41 | public bool ShowIcons { get; set; } = true;
42 |
43 | ///
44 | /// Choose where to get icons source from. "Bootstrap" or "FontAwesome".
45 | ///
46 | public IconsSource IconsSource { get; set; } = IconsSource.FontAwesome;
47 |
48 | ///
49 | /// Choose render mode: Bootstrap5 if your project is using bootstrap5, otherwise default is Bootstrap for earlier versions.
50 | ///
51 | public RenderMode RenderMode { get; set; } = RenderMode.Bootstrap;
52 |
53 | ///
54 | /// Parse localizer instance to localize alert message
55 | ///
56 | public IStringLocalizer Localizer { get; set; }
57 |
58 | ///
59 | /// ViewContext property is not required to be passed as parameter, it will be assigned automatically by the tag helper.
60 | /// View context is required to access TempData dictionary that contains the alerts coming from backend
61 | ///
62 | [ViewContext]
63 | public ViewContext ViewContext { get; set; } = null;
64 |
65 | ///
66 | /// Create alert messages styled with bootstrap 4.x
67 | ///
68 | public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
69 | {
70 | output.TagName = "div";
71 |
72 | if (ViewContext != null)
73 | {
74 | var alerts = ViewContext.TempData.ContainsKey(Alert.TempDataKey)
75 | ? ViewContext.TempData.Get>(Alert.TempDataKey)
76 | : new List();
77 | if (alerts.Count > 1 && SlideAlerts)
78 | output.Content.AppendHtml(AddAlertCarousel(alerts));
79 | else
80 | alerts.ForEach(a => output.Content.AppendHtml(AddAlert(a)));
81 |
82 | ViewContext.TempData.Remove(Alert.TempDataKey);
83 | }
84 |
85 | // read alerts contents from inner html
86 | var msg = await output.GetChildContentAsync();
87 |
88 | if (!string.IsNullOrWhiteSpace(msg.GetContent()))
89 | {
90 | var manualAlert = AddAlert(new Alert
91 | {
92 | AlertHeading = this.AlertHeading,
93 | AlertMessage = msg.GetContent(),
94 | AlertStyle = this.AlertStyle,
95 | Dismissable = this.Dismissable
96 | });
97 | output.Content.AppendHtml(manualAlert);
98 | }
99 |
100 | }
101 |
102 | private TagBuilder AddAlert(Alert alert)
103 | {
104 | var _alert = new TagBuilder("div");
105 |
106 | string alertIcon;
107 | switch (alert.AlertStyle)
108 | {
109 | case AlertStyle.Success:
110 | alertIcon =
111 | IconsSource == IconsSource.Bootstrap ? BootstrapIcons.Success :
112 | IconsSource == IconsSource.Bootstrap5 ? Bootstrap5Icons.Success :
113 | FontAwesomeIcons.Success;
114 | break;
115 |
116 | case AlertStyle.Warning:
117 | alertIcon =
118 | IconsSource == IconsSource.Bootstrap ? BootstrapIcons.Warning :
119 | IconsSource == IconsSource.Bootstrap5 ? Bootstrap5Icons.Warning :
120 | FontAwesomeIcons.Warning;
121 | break;
122 |
123 | case AlertStyle.Info:
124 | alertIcon =
125 | IconsSource == IconsSource.Bootstrap ? BootstrapIcons.Info :
126 | IconsSource == IconsSource.Bootstrap5 ? Bootstrap5Icons.Info :
127 | FontAwesomeIcons.Info;
128 | break;
129 |
130 | case AlertStyle.Danger:
131 | alertIcon =
132 | IconsSource == IconsSource.Bootstrap ? BootstrapIcons.Danger :
133 | IconsSource == IconsSource.Bootstrap5 ? Bootstrap5Icons.Danger :
134 | FontAwesomeIcons.Danger;
135 | break;
136 | default:
137 | alertIcon =
138 | IconsSource == IconsSource.Bootstrap ? BootstrapIcons.Default :
139 | IconsSource == IconsSource.Bootstrap5 ? Bootstrap5Icons.Default :
140 | FontAwesomeIcons.Default;
141 | break;
142 | }
143 |
144 | var alertStyle = Enum.GetName(typeof(AlertStyle), alert.AlertStyle).ToLowerInvariant();
145 | _alert.AddCssClass($"alert alert-{alertStyle}");
146 | _alert.Attributes.Add("role", "alert");
147 |
148 | if (alert.Dismissable)
149 | {
150 | if (RenderMode == RenderMode.Bootstrap5)
151 | {
152 | _alert.AddCssClass("alert-dismissible fade show");
153 | _alert.InnerHtml.AppendHtml("");
154 | }
155 | else
156 | _alert.InnerHtml.AppendHtml("");
157 | }
158 |
159 | if (!string.IsNullOrWhiteSpace(alert.AlertHeading))
160 | {
161 | var heading = Localizer == null ? alert.AlertHeading : Localizer[alert.AlertHeading];
162 | _alert.InnerHtml.AppendHtml($"{heading}
");
163 | }
164 |
165 | if (!string.IsNullOrWhiteSpace(alert.AlertMessage))
166 | {
167 | var msg = Localizer == null ? alert.AlertMessage : Localizer[alert.AlertMessage];
168 |
169 | if (RenderMode == RenderMode.Bootstrap5 && IconsSource == IconsSource.Bootstrap5)
170 | {
171 | _alert.AddCssClass("d-flex align-items-center");
172 | var icon = ShowIcons ? alertIcon : string.Empty;
173 | _alert.InnerHtml.AppendHtml($"{icon}{msg}
");
174 | }
175 | else
176 | {
177 | var icon = ShowIcons ? $" " : string.Empty;
178 | _alert.InnerHtml.AppendHtml($"{icon}{msg}
");
179 | }
180 | }
181 |
182 | return _alert;
183 | }
184 |
185 | private TagBuilder AddAlertCarousel(List alerts)
186 | {
187 | var carouselId = "alertCarouselControls";
188 |
189 | var indic = new TagBuilder("ol");
190 | indic.AddCssClass("carousel-indicators");
191 |
192 | for (int i = 0; i < alerts.Count; i++)
193 | {
194 | var indicItem = new TagBuilder("li");
195 |
196 | if (RenderMode == RenderMode.Bootstrap5)
197 | {
198 | indicItem.Attributes.Add("data-bs-target", $"#{carouselId}");
199 | indicItem.Attributes.Add("data-bs-slide-to", $"{i}");
200 | }
201 | else
202 | {
203 | indicItem.Attributes.Add("data-target", $"#{carouselId}");
204 | indicItem.Attributes.Add("data-slide-to", $"{i}");
205 | }
206 | if (i == 0)
207 | indicItem.AddCssClass("active");
208 | indic.InnerHtml.AppendHtml(indicItem);
209 | }
210 |
211 | var carouselInner = new TagBuilder("div");
212 | carouselInner.AddCssClass("carousel-inner");
213 | for (int i = 0; i < alerts.Count; i++)
214 | {
215 | var slide = new TagBuilder("div");
216 | if (i == 0)
217 | slide.AddCssClass("carousel-item active");
218 | else
219 | slide.AddCssClass("carousel-item");
220 |
221 | // remove dismissabel property from inner alerts
222 | // only the most outer alert will have dismissable property
223 | alerts[i].Dismissable = false;
224 | slide.InnerHtml.AppendHtml(AddAlert(alerts[i]));
225 |
226 | carouselInner.InnerHtml.AppendHtml(slide);
227 | }
228 |
229 | var carouselDiv = new TagBuilder("div");
230 | carouselDiv.AddCssClass("carousel slide");
231 |
232 | carouselDiv.Attributes.Add("id", carouselId);
233 | if (RenderMode == RenderMode.Bootstrap5)
234 | carouselDiv.Attributes.Add("data-bs-ride", "carousel");
235 | else
236 | carouselDiv.Attributes.Add("data-ride", "carousel");
237 |
238 | carouselDiv.InnerHtml.AppendHtml(indic);
239 | carouselDiv.InnerHtml.AppendHtml(carouselInner);
240 |
241 | // This is the main alert that will hold the alerts carousel
242 | var mainAlert = new TagBuilder("div");
243 | mainAlert.Attributes.Add("role", "alert");
244 | mainAlert.InnerHtml.AppendHtml(carouselDiv);
245 |
246 | if (RenderMode == RenderMode.Bootstrap5)
247 | {
248 | mainAlert.AddCssClass("alert alert-dismissible fade show p-0");
249 | mainAlert.InnerHtml.AppendHtml("");
250 | }
251 | else
252 | {
253 | mainAlert.AddCssClass("alert alert-dismissible p-0");
254 | mainAlert.InnerHtml.AppendHtml("");
255 | }
256 | return mainAlert;
257 | }
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LanguageNavTagHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Mvc.Rendering;
3 | using Microsoft.AspNetCore.Mvc.ViewFeatures;
4 | using Microsoft.AspNetCore.Razor.TagHelpers;
5 | using Microsoft.Extensions.Options;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using System.Linq;
10 | using System.Text;
11 |
12 | namespace LazZiya.TagHelpers
13 | {
14 | ///
15 | /// creates a language navigation menu, depends on supported cultures
16 | ///
17 | public class LanguageNavTagHelper : TagHelper
18 | {
19 | ///
20 | /// optional: manually specify list of supported cultures
21 | ///
22 | /// en-US,tr, ar
23 | ///
24 | ///
25 | public string SupportedCultures { get; set; }
26 |
27 | ///
28 | /// optional: what to display as label for language dropdown
29 | /// default: LanguageLabel.EnglishName
30 | ///
31 | public LanguageLabel LanguageLabel { get; set; } = LanguageLabel.EnglishName;
32 |
33 | ///
34 | /// ViewContext property is not required to be passed as parameter, it will be auto assigned by the tag helpoer.
35 | /// current view context to access RouteData.Values and Request.Query collection
36 | ///
37 | [ViewContext]
38 | public ViewContext ViewContext { get; set; }
39 |
40 | ///
41 | /// Choose render mode: classis for regular dropdown list, Bootstrap4 for HTML5 div with Bootstrap4 style.
42 | ///
43 | public RenderMode RenderMode { get; set; } = RenderMode.Bootstrap;
44 |
45 | ///
46 | /// Set the handler url for setting culture cookie on language change
47 | ///
48 | public string CookieHandlerUrl { get; set; }
49 |
50 | ///
51 | /// The url to redirect to on langugae change.
52 | /// The url must have at one place holder for culture value.
53 | /// e.g. /{0}/Home
54 | ///
55 | public string RedirectToUrl { get; set; }
56 |
57 | ///
58 | /// Show relevant country flag for specific culture.
59 | /// Flags will be shown only if the culture is country specific.
60 | /// e.g. "tr" will not render any flag, but "tr-sy" will render Turkish flag.
61 | /// Required reference to flag-icon-css
62 | ///
63 | public bool Flags { get; set; } = false;
64 |
65 | ///
66 | /// true: Show flags in squared images,
67 | /// false: Show flags in rounded images,
68 | ///
69 | public bool FlagsSquared { get; set; } = false;
70 |
71 | ///
72 | /// Whether show border or not
73 | ///
74 | public bool Border { get; set; } = true;
75 |
76 | ///
77 | /// required for listing supported cultures.
78 | /// The handler must contain two place holders for culture name and return url.
79 | /// e.g.:
80 | ///
81 | private readonly IOptions _ops;
82 |
83 | ///
84 | /// creates a language navigation menu, depends on supported cultures
85 | ///
86 | ///
87 | public LanguageNavTagHelper(IOptions ops)
88 | {
89 | _ops = ops;
90 | }
91 |
92 | ///
93 | /// start creating the language navigation dropdown
94 | ///
95 | ///
96 | ///
97 | public override void Process(TagHelperContext context, TagHelperOutput output)
98 | {
99 | var langDictionary = CreateNavDictionary();
100 |
101 | switch (RenderMode)
102 | {
103 | case RenderMode.Bootstrap:
104 | CreateBootstrapItems(ref output, langDictionary);
105 | break;
106 | case RenderMode.Bootstrap5:
107 | CreateBootstrap5Items(ref output, langDictionary);
108 | break;
109 | case RenderMode.Classic:
110 | CreateClassicItems(ref output, langDictionary);
111 | break;
112 | case RenderMode.FormControl:
113 | CreateFormControlItems(ref output, langDictionary);
114 | break;
115 | }
116 | }
117 |
118 | ///
119 | /// create classic list items list
120 | /// English]]>
121 | ///
122 | /// language name-URL dictionary
123 | /// reference to TagHelperOuput
124 | ///
125 | private void CreateClassicItems(ref TagHelperOutput output, List langDictionary)
126 | {
127 | output.TagName = "select";
128 | output.Attributes.Add("onchange", "this.options[this.selectedIndex].value && (window.location = this.options[this.selectedIndex].value);");
129 |
130 | foreach (var lang in langDictionary.OrderBy(x => x.DisplayText))
131 | {
132 | var option = new TagBuilder("option");
133 | option.Attributes.Add("value", lang.Url);
134 | option.InnerHtml.AppendHtml(lang.DisplayText);
135 |
136 | if (CultureInfo.CurrentCulture.Name == lang.Name)
137 | option.Attributes.Add("selected", "selected");
138 |
139 | output.Content.AppendHtml(option);
140 | }
141 | }
142 |
143 | ///
144 | /// create a dropdown form control
145 | /// English]]>
146 | ///
147 | /// language name-URL dictionary
148 | /// reference to TagHelperOuput
149 | ///
150 | private void CreateFormControlItems(ref TagHelperOutput output, List langDictionary)
151 | {
152 | output.TagName = "select";
153 |
154 | foreach (var lang in langDictionary.OrderBy(x => x.DisplayText))
155 | {
156 | var option = new TagBuilder("option");
157 | option.Attributes.Add("value", lang.Name);
158 | option.InnerHtml.AppendHtml(lang.DisplayText);
159 |
160 | if (CultureInfo.CurrentCulture.Name == lang.Name)
161 | option.Attributes.Add("selected", "selected");
162 |
163 | output.Content.AppendHtml(option);
164 | }
165 | }
166 |
167 | ///
168 | /// create classic list items list
169 | /// English
]]>
170 | ///
171 | /// language name-URL dictionary
172 | /// reference to TagHelperOuput
173 | ///
174 | private void CreateBootstrapItems(ref TagHelperOutput output, List langDictionary)
175 | {
176 | var div = new TagBuilder("div");
177 |
178 | if (CultureInfo.CurrentCulture.TextInfo.IsRightToLeft)
179 | div.AddCssClass("dropdown-menu dropdown-menu-left");
180 | else
181 | div.AddCssClass("dropdown-menu dropdown-menu-right");
182 |
183 | div.Attributes.Add("aria-labeledby", "dropdownlang");
184 |
185 | foreach (var lang in langDictionary.Where(x => x.Name != CultureInfo.CurrentCulture.Name).OrderBy(x => x.DisplayText))
186 | {
187 |
188 | var a = new TagBuilder("a");
189 | a.AddCssClass("dropdown-item small");
190 | a.Attributes.Add("href", lang.Url);
191 |
192 | if (Flags)
193 | {
194 | var flagName = lang.Name.Split('-');
195 | if (flagName.Length == 2)
196 | {
197 |
198 | if (FlagsSquared)
199 | a.InnerHtml.AppendHtml($" ");
200 | else
201 | a.InnerHtml.AppendHtml($" ");
202 | }
203 | }
204 |
205 | a.InnerHtml.Append(lang.DisplayText);
206 |
207 | div.InnerHtml.AppendHtml(a);
208 | }
209 |
210 | output.TagName = "div";
211 | output.Attributes.Add("class", "dropdown");
212 |
213 | var toggle = CreateToggle();
214 | output.Content.AppendHtml(toggle);
215 |
216 | output.Content.AppendHtml(div);
217 | }
218 |
219 | ///
220 | /// create classic list items list
221 | /// English]]>
222 | ///
223 | /// language name-URL dictionary
224 | /// reference to TagHelperOuput
225 | ///
226 | private void CreateBootstrap5Items(ref TagHelperOutput output, List langDictionary)
227 | {
228 | var ul = new TagBuilder("ul");
229 |
230 | if (CultureInfo.CurrentCulture.TextInfo.IsRightToLeft)
231 | ul.AddCssClass("dropdown-menu dropdown-menu-left");
232 | else
233 | ul.AddCssClass("dropdown-menu dropdown-menu-right");
234 |
235 | ul.Attributes.Add("aria-labeledby", "dropdownlang");
236 |
237 | foreach (var lang in langDictionary.Where(x => x.Name != CultureInfo.CurrentCulture.Name).OrderBy(x => x.DisplayText))
238 | {
239 | var li = new TagBuilder("li");
240 | var a = new TagBuilder("a");
241 | a.AddCssClass("dropdown-item small");
242 | a.Attributes.Add("href", lang.Url);
243 |
244 | if (Flags)
245 | {
246 | var flagName = lang.Name.Split('-');
247 | if (flagName.Length == 2)
248 | {
249 | if (FlagsSquared)
250 | a.InnerHtml.AppendHtml($" ");
251 | else
252 | a.InnerHtml.AppendHtml($" ");
253 | }
254 | }
255 |
256 | a.InnerHtml.Append(lang.DisplayText);
257 | li.InnerHtml.AppendHtml(a);
258 | ul.InnerHtml.AppendHtml(li);
259 | }
260 |
261 | output.TagName = "div";
262 | output.Attributes.Add("class", "dropdown");
263 |
264 | var toggle = CreateToggle();
265 | output.Content.AppendHtml(toggle);
266 |
267 | output.Content.AppendHtml(ul);
268 | }
269 |
270 | ///
271 | /// create dictonary for all supported cultures
272 | /// Key: Language display name for label
273 | /// Value: Navigation URL
274 | ///
275 | ///
276 | private List CreateNavDictionary()
277 | {
278 | var dic = new List();
279 | var cultures = GetSupportedCultures();
280 |
281 | foreach (var cul in cultures)
282 | {
283 | var redUrl = RedirectToUrl ?? "/{0}";
284 |
285 | var url = string.Format(Uri.UnescapeDataString(redUrl), cul.Name);
286 |
287 | if (!string.IsNullOrWhiteSpace(CookieHandlerUrl))
288 | {
289 | url = string.Format(Uri.UnescapeDataString(CookieHandlerUrl), cul.Name, url);
290 | }
291 |
292 | var label = GetLanguageLabel(cul);
293 | dic.Add(new LanguageItem { Name = cul.Name, DisplayText = label, Url = url });
294 | }
295 |
296 | return dic;
297 | }
298 |
299 | ///
300 | /// private list of supported CultureInfo,
301 | ///
302 | private IEnumerable GetSupportedCultures()
303 | {
304 | // if the user didn't specify manually list of supported cultures,
305 | // then create cultures list with reference to supported cultures defined in localization settings in startup
306 | if (string.IsNullOrWhiteSpace(SupportedCultures))
307 | return _ops.Value.SupportedCultures;
308 |
309 | //if the user will specify supported cultures manually, then this list will be created accordingly
310 | var cList = new List();
311 | foreach (var c in SupportedCultures.Split(new[] { ',', '|', ';', ' ' }, System.StringSplitOptions.RemoveEmptyEntries))
312 | {
313 | cList.Add(new CultureInfo(c));
314 | }
315 |
316 | return cList;
317 | }
318 |
319 | private string GetLanguageLabel(CultureInfo cul)
320 | {
321 | switch (LanguageLabel)
322 | {
323 | case LanguageLabel.Name: return cul.Name;
324 | case LanguageLabel.DisplayName: return cul.DisplayName;
325 | case LanguageLabel.EnglishName: return cul.EnglishName;
326 | case LanguageLabel.NativeName: return cul.NativeName;
327 | case LanguageLabel.TwoLetterISOLanguageName: return cul.TwoLetterISOLanguageName;
328 |
329 | default: return cul.EnglishName;
330 | }
331 | }
332 |
333 | private TagBuilder CreateToggle()
334 | {
335 | var toggle = new TagBuilder("a");
336 |
337 | var cssBuilder = new StringBuilder("btn-sm btn-default border-secondary dropdown-toggle");
338 |
339 | if (Border) cssBuilder.Append(" border");
340 | toggle.AddCssClass(cssBuilder.ToString());
341 |
342 | toggle.Attributes.Add("id", "dropdownLang");
343 | toggle.Attributes.Add("href", "#");
344 | toggle.Attributes.Add("role", "button");
345 |
346 | if (RenderMode == RenderMode.Bootstrap5)
347 | toggle.Attributes.Add("data-bs-toggle", "dropdown");
348 | else
349 | toggle.Attributes.Add("data-toggle", "dropdown");
350 |
351 | toggle.Attributes.Add("aria-haspopup", "true");
352 | toggle.Attributes.Add("aria-expanded", "false");
353 |
354 | var labelTxt = GetLanguageLabel(CultureInfo.CurrentCulture);
355 |
356 | if (Flags)
357 | {
358 | var flagName = CultureInfo.CurrentCulture.Name.Split('-');
359 | if (flagName.Length == 2)
360 | {
361 | if (FlagsSquared)
362 | toggle.InnerHtml.AppendHtml($" ");
363 | else
364 | toggle.InnerHtml.AppendHtml($" ");
365 | }
366 | }
367 |
368 | toggle.InnerHtml.AppendHtml(labelTxt);
369 |
370 | return toggle;
371 | }
372 | /*
373 | private TagBuilder CreateToggle5()
374 | {
375 | var toggle = new TagBuilder("a");
376 | toggle.AddCssClass("btn-sm btn-default border border-secondary dropdown-toggle");
377 | toggle.Attributes.Add("id", "dropdownLang");
378 | toggle.Attributes.Add("href", "#");
379 | toggle.Attributes.Add("role", "button");
380 | toggle.Attributes.Add("data-bs-toggle", "dropdown");
381 | toggle.Attributes.Add("aria-haspopup", "true");
382 | toggle.Attributes.Add("aria-expanded", "false");
383 |
384 | var labelTxt = GetLanguageLabel(CultureInfo.CurrentCulture);
385 |
386 | if (Flags)
387 | {
388 | var flagName = CultureInfo.CurrentCulture.Name.Split('-');
389 | if (flagName.Length == 2)
390 | {
391 | if (FlagsSquared)
392 | toggle.InnerHtml.AppendHtml($" ");
393 | else
394 | toggle.InnerHtml.AppendHtml($" ");
395 | }
396 | }
397 |
398 | toggle.InnerHtml.AppendHtml(labelTxt);
399 |
400 | return toggle;
401 | }*/
402 | }
403 | }
404 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/PagingTagHelper.cs:
--------------------------------------------------------------------------------
1 | using LazZiya.TagHelpers.Utilities;
2 | using Microsoft.AspNetCore.Mvc.Rendering;
3 | using Microsoft.AspNetCore.Mvc.ViewFeatures;
4 | using Microsoft.AspNetCore.Razor.TagHelpers;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.Logging;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 |
11 | namespace LazZiya.TagHelpers
12 | {
13 | ///
14 | /// Creates a pagination control
15 | ///
16 | public class PagingTagHelper : TagHelper
17 | {
18 | private IConfiguration Configuration { get; }
19 | private readonly ILogger _logger;
20 |
21 | ///
22 | /// Dictonary object to hold all ajax attributes
23 | ///
24 | private AttributeDictionary AjaxAttributes { get; set; }
25 |
26 | ///
27 | /// A URL template for paging buttons
28 | /// e.g.
29 | ///
30 | ///
31 | public string UrlTemplate { get; set; }
32 |
33 | ///
34 | /// ViewContext property is not required to be passed as parameter, it will be assigned automatically by the tag helper.
35 | /// View context is required to access TempData dictionary that contains the alerts coming from backend
36 | ///
37 | [ViewContext]
38 | public ViewContext ViewContext { get; set; } = null;
39 |
40 | ///
41 | /// Creates a pagination control
42 | ///
43 | public PagingTagHelper(IConfiguration configuration, ILogger logger)
44 | {
45 | Configuration = configuration;
46 | _logger = logger;
47 | }
48 |
49 | #region Settings
50 |
51 | ///
52 | /// current page number.
53 | /// default: 1
54 | /// example: p=1
55 | ///
56 | public int PageNo { get; set; } = 1;
57 |
58 | ///
59 | /// how many items to get from db per page per request
60 | /// default: 10
61 | /// example: pageSize=10
62 | ///
63 | public int PageSize { get; set; } = 10;
64 |
65 | ///
66 | /// Total count of records in the db
67 | /// default: 0
68 | ///
69 | public int TotalRecords { get; set; } = 0;
70 |
71 | ///
72 | /// if count of pages is too much, restrict shown pages count to specific number
73 | /// default: 10
74 | ///
75 | public int? MaxDisplayedPages { get; set; }
76 |
77 | ///
78 | /// name of the settings section in appSettings.json
79 | /// default: "default"
80 | ///
81 | public string SettingsJson { get; set; } = "default";
82 |
83 | ///
84 | /// Force adding url path to the navigation url
85 | /// in some scenarios when the page is under some area/subFolder
86 | /// The navigation links are pointing to the home page.
87 | /// To force adding url path enable this property
88 | ///
89 | public bool? FixUrlPath { get; set; } = true;
90 |
91 | #endregion
92 |
93 | #region Page size navigation
94 | ///
95 | /// A list of dash delimitted numbers for page size dropdown.
96 | /// default: "10-25-50"
97 | ///
98 | public string PageSizeDropdownItems { get; set; }
99 |
100 | #endregion
101 |
102 | #region QueryString
103 |
104 | ///
105 | /// Query string paramter name for current page.
106 | /// default: p
107 | /// exmaple: p=1
108 | ///
109 | public string QueryStringKeyPageNo { get; set; }
110 |
111 | ///
112 | /// Query string parameter name for page size
113 | /// default: s
114 | /// example: s=25
115 | ///
116 | public string QueryStringKeyPageSize { get; set; }
117 |
118 | #endregion
119 |
120 | #region Display settings
121 |
122 | ///
123 | /// Show drop down list for different page size options
124 | /// default: true
125 | /// options: true, false
126 | ///
127 | public bool? ShowPageSizeNav { get; set; }
128 |
129 | ///
130 | /// Show a three dots after first page or before last page
131 | /// when there is a gap in pages at the beginnig or end
132 | ///
133 | public bool? ShowGap { get; set; }
134 |
135 | ///
136 | /// Show/hide First-Last buttons
137 | /// default: true, if set to false and total pages > max displayed pages it will be true
138 | ///
139 | public bool? ShowFirstLast { get; set; }
140 |
141 | ///
142 | /// Show/hide Previous-Next buttons
143 | /// default: true
144 | ///
145 | public bool? ShowPrevNext { get; set; }
146 |
147 | ///
148 | /// Show or hide total pages count
149 | /// default: true
150 | ///
151 | public bool? ShowTotalPages { get; set; }
152 |
153 | ///
154 | /// Show or hide total records count
155 | /// default: true
156 | ///
157 | public bool? ShowTotalRecords { get; set; }
158 | #endregion
159 |
160 | #region Texts
161 | ///
162 | /// The text to display at page size dropdown list label
163 | /// default: Page size
164 | ///
165 | public string TextPageSize { get; set; }
166 |
167 |
168 | ///
169 | /// Text to show on the "Go To First" Page button
170 | ///
171 | ///
172 | ///
173 | public string TextFirst { get; set; }
174 |
175 | ///
176 | /// Text to show on "Go to last page" button
177 | ///
178 | ///
179 | ///
180 | public string TextLast { get; set; }
181 |
182 | ///
183 | /// Next button text
184 | ///
185 | ///
186 | ///
187 | public string TextNext { get; set; }
188 |
189 | ///
190 | /// previous button text
191 | ///
192 | ///
193 | ///
194 | public string TextPrevious { get; set; }
195 |
196 | ///
197 | /// Display text for total pages label
198 | /// default: page
199 | ///
200 | public string TextTotalPages { get; set; }
201 |
202 | ///
203 | /// Display text for total records label
204 | /// default: records
205 | ///
206 | public string TextTotalRecords { get; set; }
207 |
208 | ///
209 | /// The number display format for page numbers. Use a list of numbers splitted by space e.g. "0 1 2 3 4 5 6 7 8 9" or use one from a pre-defined numbers formats in :
210 | ///
211 | ///
212 | public string NumberFormat { get; set; }
213 | #endregion
214 |
215 | #region Screen Reader
216 | ///
217 | /// Text for screen readers only
218 | ///
219 | public string SrTextFirst { get; set; }
220 |
221 | ///
222 | /// text for screen readers only
223 | ///
224 | public string SrTextLast { get; set; }
225 |
226 | ///
227 | /// text for screenreaders only
228 | ///
229 | public string SrTextNext { get; set; }
230 |
231 | ///
232 | /// text for screen readers only
233 | ///
234 | public string SrTextPrevious { get; set; }
235 |
236 | #endregion
237 |
238 | #region Styling
239 |
240 | ///
241 | /// Select bootstrap version
242 | ///
243 | public RenderMode RenderMode { get; set; } = RenderMode.Bootstrap;
244 |
245 | ///
246 | /// add custom class to content div
247 | ///
248 | public string Class { get; set; }
249 |
250 | ///
251 | /// css class for pagination div
252 | ///
253 | public string ClassPagingControlDiv { get; set; }
254 |
255 | ///
256 | /// css class for page count/record count div
257 | ///
258 | public string ClassInfoDiv { get; set; }
259 |
260 | ///
261 | /// styling class for page size div
262 | ///
263 | public string ClassPageSizeDiv { get; set; }
264 |
265 | ///
266 | /// pagination control class
267 | /// default: pagination
268 | ///
269 | public string ClassPagingControl { get; set; }
270 |
271 | ///
272 | /// class name for the active page
273 | /// default: active
274 | /// examples: disabled, active, ...
275 | ///
276 | public string ClassActivePage { get; set; }
277 |
278 | ///
279 | /// name of the class when jumping button is disabled.
280 | /// jumping buttons are prev-next and first-last buttons
281 | /// default: disabled
282 | /// example: disabled, d-hidden
283 | ///
284 | public string ClassDisabledJumpingButton { get; set; }
285 |
286 | ///
287 | /// css class for total records info
288 | /// default: badge badge-light
289 | ///
290 | public string ClassTotalRecords { get; set; }
291 |
292 | ///
293 | /// css class for total pages info
294 | /// default: badge badge-light
295 | ///
296 | public string ClassTotalPages { get; set; }
297 |
298 | ///
299 | /// css class for page link, use for styling bg and text colors
300 | ///
301 | public string ClassPageLink { get; set; }
302 |
303 | #endregion
304 |
305 | #region Ajax
306 | ///
307 | /// Set to true to use ajax pagination
308 | ///
309 | public bool Ajax { get; set; } = false;
310 |
311 | ///
312 | /// The message to display in a confirmation window before a request is submitted.
313 | ///
314 | public string AjaxConfirm { get; set; }
315 |
316 | ///
317 | /// The mode that specifies how to insert the response into the target DOM element. Valid values are before, after and replace. Default is replace
318 | ///
319 | public PagingAjaxMode AjaxMode { get; set; } = PagingAjaxMode.replace;
320 |
321 | ///
322 | /// A value, in milliseconds, that controls the duration of the animation when showing or hiding the loading element.
323 | ///
324 | public int AjaxLoadingDuration { get; set; }
325 |
326 | ///
327 | /// The id attribute of an HTML element that is displayed while the Ajax function is loading. Default is #loading-spinner
328 | ///
329 | public string AjaxLoading { get; set; } = "#loading-spinner";
330 |
331 | ///
332 | /// The name of the JavaScript function to call immediately before the page is updated.
333 | ///
334 | public string AjaxBegin { get; set; }
335 |
336 | ///
337 | /// The JavaScript function to call when response data has been instantiated but before the page is updated.
338 | ///
339 | public string AjaxComplete { get; set; }
340 |
341 | ///
342 | /// The JavaScript function to call if the page update fails.
343 | ///
344 | public string AjaxFailure { get; set; }
345 |
346 | ///
347 | /// The JavaScript function to call after the page is successfully updated.
348 | ///
349 | public string AjaxSuccess { get; set; }
350 |
351 | ///
352 | /// The ID of the DOM element to update by using the response from the server.
353 | ///
354 | public string AjaxUpdate { get; set; }
355 |
356 | ///
357 | /// The URL to make the request to.
358 | ///
359 | public string AjaxUrl { get; set; }
360 | #endregion
361 |
362 | private int TotalPages => (int)Math.Ceiling(TotalRecords / (double)PageSize);
363 |
364 | private class Boundaries
365 | {
366 | public int Start { get; set; }
367 | public int End { get; set; }
368 | }
369 |
370 | ///
371 | /// process creating paging tag helper
372 | ///
373 | ///
374 | ///
375 | public override void Process(TagHelperContext context, TagHelperOutput output)
376 | {
377 | SetDefaults();
378 |
379 | if (TotalPages > 0)
380 | {
381 | var pagingControl = new TagBuilder("ul");
382 | pagingControl.AddCssClass($"{ClassPagingControl}");
383 |
384 | // If ajax is anabled, create a dictionary of all ajax attributes
385 | if (Ajax)
386 | {
387 | // Add loader element
388 | output.PreElement.SetHtmlContent("");
389 |
390 | AjaxAttributes = SetupAjaxAttributes();
391 | }
392 |
393 | // show-hide first-last buttons on user options
394 | if (ShowFirstLast == true)
395 | {
396 | ShowFirstLast = true;
397 | }
398 |
399 | if(string.IsNullOrWhiteSpace(UrlTemplate))
400 | UrlTemplate = CreatePagingUrlTemplate();
401 |
402 | if (ShowFirstLast == true)
403 | {
404 | var first = CreatePagingLink(1, TextFirst, SrTextFirst, ClassDisabledJumpingButton);
405 | pagingControl.InnerHtml.AppendHtml(first);
406 | }
407 |
408 | if (ShowPrevNext == true)
409 | {
410 | var prevPage = PageNo - 1 <= 1 ? 1 : PageNo - 1;
411 | var prev = CreatePagingLink(prevPage, TextPrevious, SrTextPrevious, ClassDisabledJumpingButton);
412 | pagingControl.InnerHtml.AppendHtml(prev);
413 | }
414 |
415 | if (MaxDisplayedPages == 1)
416 | {
417 | var numTag = CreatePagingLink(PageNo, null, null, ClassActivePage);
418 | pagingControl.InnerHtml.AppendHtml(numTag);
419 | }
420 | else if (MaxDisplayedPages > 1)
421 | {
422 | // Boundaries are the start-end currently displayed pages
423 | var boundaries = CalculateBoundaries(PageNo, TotalPages, MaxDisplayedPages.Value);
424 |
425 | string gapStr = " ... ";
426 |
427 | if (ShowGap == true && boundaries.End > MaxDisplayedPages)
428 | {
429 | // add page no 1
430 | var num1Tag = CreatePagingLink(1, null, null, ClassActivePage);
431 | pagingControl.InnerHtml.AppendHtml(num1Tag);
432 |
433 | // Add gap after first page
434 | pagingControl.InnerHtml.AppendHtml(gapStr);
435 | }
436 |
437 | for (int i = boundaries.Start; i <= boundaries.End; i++)
438 | {
439 | var numTag = CreatePagingLink(i, null, null, ClassActivePage);
440 | pagingControl.InnerHtml.AppendHtml(numTag);
441 | }
442 |
443 | if (ShowGap == true && boundaries.End < TotalPages)
444 | {
445 | // Add gap before last page
446 | pagingControl.InnerHtml.AppendHtml(gapStr);
447 |
448 | // add last page
449 | var numLastTag = CreatePagingLink(TotalPages, null, null, ClassActivePage);
450 | pagingControl.InnerHtml.AppendHtml(numLastTag);
451 | }
452 | }
453 |
454 | if (ShowPrevNext == true)
455 | {
456 | var nextPage = PageNo + 1 > TotalPages ? TotalPages : PageNo + 1;
457 | var next = CreatePagingLink(nextPage, TextNext, SrTextNext, ClassDisabledJumpingButton);
458 | pagingControl.InnerHtml.AppendHtml(next);
459 | }
460 |
461 | if (ShowFirstLast == true)
462 | {
463 | var last = CreatePagingLink(TotalPages, TextLast, SrTextLast, ClassDisabledJumpingButton);
464 | pagingControl.InnerHtml.AppendHtml(last);
465 | }
466 |
467 | var pagingControlDiv = new TagBuilder("div");
468 | pagingControlDiv.AddCssClass($"{ClassPagingControlDiv}");
469 | pagingControlDiv.InnerHtml.AppendHtml(pagingControl);
470 |
471 | output.TagName = "div";
472 | output.Attributes.SetAttribute("class", $"{Class}");
473 | output.Content.AppendHtml(pagingControlDiv);
474 |
475 | if (ShowPageSizeNav == true)
476 | {
477 | var psDropdown = CreatePageSizeControl();
478 |
479 | var psDiv = new TagBuilder("div");
480 | psDiv.AddCssClass($"{ClassPageSizeDiv}");
481 | psDiv.InnerHtml.AppendHtml(psDropdown);
482 |
483 | output.Content.AppendHtml(psDiv);
484 | }
485 |
486 | if (ShowTotalPages == true || ShowTotalRecords == true)
487 | {
488 | var infoDiv = AddDisplayInfo();
489 |
490 | output.Content.AppendHtml(infoDiv);
491 | }
492 |
493 | }
494 | }
495 |
496 | private AttributeDictionary SetupAjaxAttributes()
497 | {
498 | if (string.IsNullOrWhiteSpace(AjaxUpdate))
499 | throw new ArgumentNullException(nameof(AjaxUpdate));
500 |
501 | if (string.IsNullOrWhiteSpace(AjaxUrl))
502 | throw new ArgumentNullException(nameof(AjaxUrl));
503 |
504 | var ajaxAttributes = new AttributeDictionary
505 | {
506 | { "data-ajax", "true" },
507 | { "data-ajax-mode", $"{AjaxMode}" },
508 | { "data-ajax-update", AjaxUpdate }
509 | };
510 |
511 | if (!string.IsNullOrWhiteSpace(AjaxBegin))
512 | ajaxAttributes.Add("data-ajax-begin", AjaxBegin);
513 |
514 | if (!string.IsNullOrWhiteSpace(AjaxComplete))
515 | ajaxAttributes.Add("data-ajax-complete", AjaxComplete);
516 |
517 | if (!string.IsNullOrWhiteSpace(AjaxConfirm))
518 | ajaxAttributes.Add("data-ajax-confirm", AjaxConfirm);
519 |
520 | if (!string.IsNullOrWhiteSpace(AjaxFailure))
521 | ajaxAttributes.Add("data-ajax-failure", AjaxFailure);
522 |
523 | if (!string.IsNullOrWhiteSpace(AjaxLoading))
524 | ajaxAttributes.Add("data-ajax-loading", AjaxLoading);
525 |
526 | if (AjaxLoadingDuration > 0)
527 | ajaxAttributes.Add("data-ajax-loading-duration", $"{AjaxLoadingDuration}");
528 |
529 | if (!string.IsNullOrWhiteSpace(AjaxSuccess))
530 | ajaxAttributes.Add("data-ajax-success", AjaxSuccess);
531 |
532 | return ajaxAttributes;
533 | }
534 |
535 | ///
536 | /// This method will assign the values by checking three places
537 | /// 1- Property value if set from HTML code
538 | /// 2- Default values in appSettings.json
539 | /// 3- Hard coded default value in code
540 | ///
541 | private void SetDefaults()
542 | {
543 | var _settingsJson = SettingsJson ?? "default";
544 |
545 | _logger.LogInformation($"----> PagingTagHelper SettingsJson: {SettingsJson} - {_settingsJson}");
546 |
547 | MaxDisplayedPages = MaxDisplayedPages == null ? int.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:max-displayed-pages"], out int _dp) ? _dp : 10 : MaxDisplayedPages;
548 |
549 | PageSizeDropdownItems = PageSizeDropdownItems ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:page-size-dropdown-items"] ?? "10-25-50";
550 |
551 | QueryStringKeyPageNo = QueryStringKeyPageNo ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:query-string-key-page-no"] ?? "p";
552 |
553 | QueryStringKeyPageSize = QueryStringKeyPageSize ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:query-string-key-page-size"] ?? "s";
554 |
555 | ShowGap = ShowGap == null ?
556 | bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-gap"], out bool _sg) ? _sg : true : ShowGap;
557 |
558 | ShowFirstLast = ShowFirstLast == null ?
559 | bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-first-last"], out bool _sfl) ? _sfl : true : ShowFirstLast;
560 |
561 | ShowPrevNext = ShowPrevNext == null ? bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-prev-next"], out bool _sprn) ? _sprn : true : ShowPrevNext;
562 |
563 | ShowPageSizeNav = ShowPageSizeNav == null ? bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-page-size-nav"], out bool _spsn) ? _spsn : true : ShowPageSizeNav;
564 |
565 | ShowTotalPages = ShowTotalPages == null ? bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-total-pages"], out bool _stp) ? _stp : true : ShowTotalPages;
566 |
567 | ShowTotalRecords = ShowTotalRecords == null ? bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:show-total-records"], out bool _str) ? _str : true : ShowTotalRecords;
568 |
569 | NumberFormat = NumberFormat ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:number-format"] ?? NumberFormats.Default;
570 |
571 | TextPageSize = TextPageSize ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-page-size"];
572 |
573 | TextFirst = TextFirst ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-first"] ?? "«";
574 |
575 | TextLast = TextLast ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-last"] ?? "»";
576 |
577 | TextPrevious = TextPrevious ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-previous"] ?? "‹";
578 |
579 | TextNext = TextNext ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-next"] ?? "›";
580 |
581 | TextTotalPages = TextTotalPages ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-total-pages"] ?? "pages";
582 |
583 | TextTotalRecords = TextTotalRecords ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:text-total-records"] ?? "records";
584 |
585 | SrTextFirst = SrTextFirst ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:sr-text-first"] ?? "First";
586 |
587 | SrTextLast = SrTextLast ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:sr-text-last"] ?? "Last";
588 |
589 | SrTextPrevious = SrTextPrevious ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:sr-text-previous"] ?? "Previous";
590 |
591 | SrTextNext = SrTextNext ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:sr-text-next"] ?? "Next";
592 |
593 | Class = Class ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class"] ?? "row";
594 |
595 | ClassActivePage = ClassActivePage ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-active-page"] ?? "active";
596 |
597 | ClassDisabledJumpingButton = ClassDisabledJumpingButton ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-disabled-jumping-button"] ?? "disabled";
598 |
599 | ClassInfoDiv = ClassInfoDiv ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-info-div"] ?? "col-2";
600 |
601 | ClassPageSizeDiv = ClassPageSizeDiv ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-page-size-div"] ?? "col-1";
602 |
603 | ClassPagingControlDiv = ClassPagingControlDiv ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-paging-control-div"] ?? "col";
604 |
605 | ClassPagingControl = ClassPagingControl ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-paging-control"] ?? "pagination";
606 |
607 | ClassTotalPages = ClassTotalPages ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-total-pages"] ?? (RenderMode == RenderMode.Bootstrap ? "badge badge-light" : "badge bg-light text-dark");
608 |
609 | ClassTotalRecords = ClassTotalRecords ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-total-records"] ?? (RenderMode == RenderMode.Bootstrap ? "badge badge-dark" : "badge bg-dark");
610 |
611 | ClassPageLink = ClassPageLink ?? Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:class-page-link"] ?? "";
612 |
613 | FixUrlPath = FixUrlPath == null ?
614 | bool.TryParse(Configuration[$"lazziya:pagingTagHelper:{_settingsJson}:fix-url-path"], out bool _fPath) ? _fPath : true : FixUrlPath;
615 |
616 | _logger.LogInformation($"----> PagingTagHelper - " +
617 | $"{nameof(PageNo)}: {PageNo}, " +
618 | $"{nameof(PageSize)}: {PageSize}, " +
619 | $"{nameof(TotalRecords)}: {TotalRecords}, " +
620 | $"{nameof(TotalPages)}: {TotalPages}, " +
621 | $"{nameof(QueryStringKeyPageNo)}: {QueryStringKeyPageNo}, " +
622 | $"{nameof(QueryStringKeyPageSize)}: {QueryStringKeyPageSize}, " +
623 | $"");
624 | }
625 |
626 | private TagBuilder AddDisplayInfo()
627 | {
628 | var infoDiv = new TagBuilder("div");
629 | infoDiv.AddCssClass($"{ClassInfoDiv}");
630 |
631 | var txt = string.Empty;
632 | if (ShowTotalPages == true)
633 | {
634 | infoDiv.InnerHtml.AppendHtml($"{TotalPages.ToNumberFormat(NumberFormat)} {TextTotalPages}");
635 | }
636 |
637 | if (ShowTotalRecords == true)
638 | {
639 | infoDiv.InnerHtml.AppendHtml($"{TotalRecords.ToNumberFormat(NumberFormat)} {TextTotalRecords}");
640 | }
641 |
642 | return infoDiv;
643 | }
644 |
645 | ///
646 | /// Calculate the boundaries of the currently rendered page numbers
647 | ///
648 | ///
649 | ///
650 | ///
651 | ///
652 | private Boundaries CalculateBoundaries(int currentPageNo, int totalPages, int maxDisplayedPages)
653 | {
654 | int _start, _end;
655 |
656 | int _gap = (int)Math.Ceiling(maxDisplayedPages / 2.0);
657 |
658 | if (maxDisplayedPages > totalPages)
659 | maxDisplayedPages = totalPages;
660 |
661 | if (totalPages == 1)
662 | {
663 | _start = _end = 1;
664 | }
665 | // << < 1 2 (3) 4 5 6 7 8 9 10 > >>
666 | else if (currentPageNo < maxDisplayedPages)
667 | {
668 | _start = 1;
669 | _end = maxDisplayedPages;
670 | }
671 | // << < 91 92 93 94 95 96 97 (98) 99 100 > >>
672 | else if (currentPageNo + maxDisplayedPages == totalPages)
673 | {
674 | _start = totalPages - maxDisplayedPages > 0 ? totalPages - maxDisplayedPages - 1 : 1;
675 | _end = totalPages - 2;
676 | }
677 | // << < 91 92 93 94 95 96 97 (98) 99 100 > >>
678 | else if (currentPageNo + maxDisplayedPages == totalPages + 1)
679 | {
680 | _start = totalPages - maxDisplayedPages > 0 ? totalPages - maxDisplayedPages : 1;
681 | _end = totalPages - 1;
682 | }
683 | // << < 91 92 93 94 95 96 97 (98) 99 100 > >>
684 | else if (currentPageNo + maxDisplayedPages > totalPages + 1)
685 | {
686 | _start = totalPages - maxDisplayedPages > 0 ? totalPages - maxDisplayedPages + 1 : 1;
687 | _end = totalPages;
688 | }
689 |
690 | // << < 21 22 23 34 (25) 26 27 28 29 30 > >>
691 | else
692 | {
693 | _start = currentPageNo - _gap > 0 ? currentPageNo - _gap + 1 : 1;
694 | _end = _start + maxDisplayedPages - 1;
695 | }
696 |
697 | return new Boundaries { Start = _start, End = _end };
698 | }
699 |
700 | private TagBuilder CreatePagingLink(int targetPageNo, string text, string textSr, string pClass)
701 | {
702 | var liTag = new TagBuilder("li");
703 | liTag.AddCssClass("page-item");
704 |
705 | var pageUrl = CreatePagingUrl(targetPageNo, PageSize);
706 |
707 | var aTag = new TagBuilder("a");
708 | aTag.AddCssClass($"page-link {ClassPageLink}");
709 | aTag.Attributes.Add("href", pageUrl);
710 |
711 | // If no text provided for screen readers
712 | // use the actual page number
713 | if (string.IsNullOrWhiteSpace(textSr))
714 | {
715 | var pageNoText = targetPageNo.ToNumberFormat(NumberFormat);
716 |
717 | aTag.InnerHtml.Append($"{pageNoText}");
718 | }
719 | else
720 | {
721 | liTag.MergeAttribute("area-label", textSr);
722 | aTag.InnerHtml.AppendHtml($"{text}");
723 |
724 | if (RenderMode == RenderMode.Bootstrap5)
725 | aTag.InnerHtml.AppendHtml($"{textSr}");
726 | else
727 | aTag.InnerHtml.AppendHtml($"{textSr}");
728 | }
729 |
730 | if (PageNo == targetPageNo)
731 | {
732 | liTag.AddCssClass($"{pClass}");
733 | aTag.Attributes.Add("tabindex", "-1");
734 | aTag.Attributes.Remove("class");
735 | aTag.AddCssClass($"page-link {pClass}");
736 | aTag.Attributes.Remove("href");
737 | }
738 |
739 | if (Ajax)
740 | {
741 | var ajaxUrl = pageUrl.Replace("?", $"{AjaxUrl}&");
742 | aTag.Attributes.Add("data-ajax-url", ajaxUrl);
743 |
744 | foreach (var att in AjaxAttributes)
745 | {
746 | aTag.Attributes.Add(att.Key, att.Value);
747 | }
748 | }
749 |
750 | liTag.InnerHtml.AppendHtml(aTag);
751 | return liTag;
752 | }
753 |
754 | ///
755 | /// dropdown list for changing page size (items per page)
756 | ///
757 | ///
758 | private TagBuilder CreatePageSizeControl()
759 | {
760 | var dropDownDiv = new TagBuilder("div");
761 | dropDownDiv.AddCssClass("dropdown");
762 |
763 | var dropDownBtn = new TagBuilder("button");
764 | dropDownBtn.AddCssClass("btn btn-light dropdown-toggle");
765 | dropDownBtn.Attributes.Add("type", "button");
766 | dropDownBtn.Attributes.Add("id", "pagingDropDownMenuBtn");
767 |
768 | if (RenderMode == RenderMode.Bootstrap5)
769 | dropDownBtn.Attributes.Add("data-bs-toggle", "dropdown");
770 | else
771 | dropDownBtn.Attributes.Add("data-toggle", "dropdown");
772 | dropDownBtn.Attributes.Add("aria-haspopup", "true");
773 | dropDownBtn.Attributes.Add("aria-expanded", "false");
774 |
775 | var psText = string.IsNullOrWhiteSpace(TextPageSize)
776 | ? $"{PageSize.ToNumberFormat(NumberFormat)}"
777 | : string.Format(TextPageSize, $"{PageSize.ToNumberFormat(NumberFormat)}");
778 | dropDownBtn.InnerHtml.Append(psText);
779 |
780 | var dropDownMenu = new TagBuilder("div");
781 | dropDownMenu.AddCssClass("dropdown-menu dropdown-menu-right");
782 | dropDownMenu.Attributes.Add("aria-labelledby", "pagingDropDownMenuBtn");
783 |
784 | var pageSizeDropdownItems = PageSizeDropdownItems.Split("-", StringSplitOptions.RemoveEmptyEntries);
785 |
786 | for (int i = 0; i < pageSizeDropdownItems.Length; i++)
787 | {
788 | var n = int.Parse(pageSizeDropdownItems[i]);
789 |
790 | var pageUrl = $"{CreatePagingUrl(1, n)}";
791 |
792 | var option = new TagBuilder("a");
793 | option.AddCssClass("dropdown-item");
794 | option.Attributes.Add("href", pageUrl);
795 |
796 | option.InnerHtml.Append($"{n.ToNumberFormat(NumberFormat)}");
797 |
798 | if (n == PageSize)
799 | option.AddCssClass("active");
800 |
801 | if (Ajax)
802 | {
803 | var ajaxUrl = pageUrl.Replace("?", $"{AjaxUrl}&");
804 | option.Attributes.Add("data-ajax-url", ajaxUrl);
805 |
806 | foreach (var att in AjaxAttributes)
807 | {
808 | option.Attributes.Add(att.Key, att.Value);
809 | }
810 | }
811 |
812 | dropDownMenu.InnerHtml.AppendHtml(option);
813 | }
814 |
815 | dropDownDiv.InnerHtml.AppendHtml(dropDownBtn);
816 | dropDownDiv.InnerHtml.AppendHtml(dropDownMenu);
817 |
818 | return dropDownDiv;
819 | }
820 |
821 | ///
822 | /// edit the url for each page, so it navigates to its target page number
823 | ///
824 | ///
825 | ///
826 | ///
827 | private string CreatePagingUrl(int pageNo, int pageSize)
828 | {
829 | return string.Format(UrlTemplate, pageNo, pageSize);
830 | }
831 |
832 |
833 | ///
834 | /// edit the url for each page, so it navigates to its target page number
835 | ///
836 | /// a string with placeholders for page no and page size
837 | private string CreatePagingUrlTemplate()
838 | {
839 | var queryString = ViewContext.HttpContext.Request.QueryString.Value;
840 |
841 | if (!string.IsNullOrWhiteSpace(AjaxUrl))
842 | queryString = queryString.Replace($"{AjaxUrl}&", "");
843 |
844 | var urlTemplate = string.IsNullOrWhiteSpace(queryString)
845 | ? $"{QueryStringKeyPageNo}=1&{QueryStringKeyPageSize}={PageSize}".Split('&').ToList()
846 | : queryString.TrimStart('?').Split('&').ToList();
847 |
848 | var qDic = new List>
849 | {
850 | new Tuple(QueryStringKeyPageNo, "{0}"),
851 | new Tuple(QueryStringKeyPageSize, "{1}")
852 | };
853 |
854 | var excludedKeys = new List { "X-Requested-With", "_", QueryStringKeyPageNo, QueryStringKeyPageSize };
855 | foreach (var item in urlTemplate)
856 | {
857 | var key = item.Split('=')[0];
858 | var value = item.Split('=')[1];
859 |
860 | if (!excludedKeys.Contains(key))
861 | {
862 | qDic.Add(new Tuple(key, value));
863 | }
864 | }
865 |
866 | var path = ViewContext.HttpContext.Request.Path;
867 |
868 | return FixUrlPath ?? true
869 | ? path + "?" + string.Join("&", qDic.Select(q => q.Item1 + "=" + q.Item2))
870 | : "?" + string.Join("&", qDic.Select(q => q.Item1 + "=" + q.Item2));
871 | }
872 | }
873 | }
874 |
--------------------------------------------------------------------------------
/LazZiya.TagHelpers/LazZiya.TagHelpers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LazZiya.TagHelpers
5 |
6 |
7 |
8 |
9 | Create primary alert
10 | Alert contents must be replaced between alert tags e.g. job done!]]>
11 |
12 |
13 |
14 |
15 | Create primary alert
16 |
17 |
18 |
19 |
20 | Create secondary alert
21 | Alert contents must be replaced between alert tags e.g. job done!]]>
22 |
23 |
24 |
25 |
26 | Create secondary alert
27 |
28 |
29 |
30 |
31 | Create success alert
32 | Alert contents must be replaced between alert tags e.g. job done!]]>
33 |
34 |
35 |
36 |
37 | Create success alert
38 |
39 |
40 |
41 |
42 | Create danger alert
43 | Alert contents must be replaced between alert tags e.g. job done!]]>
44 |
45 |
46 |
47 |
48 | Create danger alert
49 |
50 |
51 |
52 |
53 | Create warning alert
54 | Alert contents must be replaced between alert tags e.g. job done!]]>
55 |
56 |
57 |
58 |
59 | Create danger alert
60 |
61 |
62 |
63 |
64 | Create info alert
65 | Alert contents must be replaced between alert tags e.g. job done!]]>
66 |
67 |
68 |
69 |
70 | Create info alert
71 |
72 |
73 |
74 |
75 | Create light alert
76 | Alert contents must be replaced between alert tags e.g. job done!]]>
77 |
78 |
79 |
80 |
81 | Create light alert
82 |
83 |
84 |
85 |
86 | Create dark alert
87 | Alert contents must be replaced between alert tags e.g. job done!]]>
88 |
89 |
90 |
91 |
92 | Create dark alert
93 |
94 |
95 |
96 |
97 | Define alert style depending on Bootstrap4.x alert classes
98 |
99 |
100 |
101 |
102 | alert-primary
103 |
104 |
105 |
106 |
107 | alert-secondary
108 |
109 |
110 |
111 |
112 | alert-success
113 |
114 |
115 |
116 |
117 | alert-danger
118 |
119 |
120 |
121 |
122 | alert-warning
123 |
124 |
125 |
126 |
127 | alert-info
128 |
129 |
130 |
131 |
132 | alert-light
133 |
134 |
135 |
136 |
137 | alert-dark
138 |
139 |
140 |
141 |
142 | Choose where to get alert icons from
143 |
144 |
145 |
146 |
147 | Bootstrap
148 |
149 |
150 |
151 |
152 | Bootstrap5
153 |
154 |
155 |
156 |
157 | FontAwesome
158 |
159 |
160 |
161 |
162 | Alert item that can be created in the backend manually for pushing alert to the temp data
163 |
164 |
165 |
166 |
167 | Key to find alerts in TempData dictionary
168 |
169 |
170 |
171 |
172 | Alert style depending on Bootstrap 4.x classes
173 |
174 |
175 |
176 |
177 | Header text for the alert message
178 |
179 |
180 |
181 |
182 | Alert message body
183 |
184 |
185 |
186 |
187 | true for dismissable alert
188 |
189 |
190 |
191 |
192 | Extensions for TempData for creating coder friendly alerts easily
193 |
194 |
195 |
196 |
197 | Create primary alert
198 |
199 | TempData
200 | message body
201 | message header
202 | Show closing button
203 |
204 |
205 |
206 | Create secondary alert
207 |
208 | TempData
209 | message body
210 | message header
211 | Show closing button
212 |
213 |
214 |
215 | Create success alert
216 |
217 | TempData
218 | message body
219 | message header
220 | Show closing button
221 |
222 |
223 |
224 | Create danger alert
225 |
226 | TempData
227 | message body
228 | message header
229 | Show closing button
230 |
231 |
232 |
233 | Create warning alert
234 |
235 | TempData
236 | message body
237 | message header
238 | Show closing button
239 |
240 |
241 |
242 | Create info alert
243 |
244 | TempData
245 | message body
246 | message header
247 | Show closing button
248 |
249 |
250 |
251 | Create light alert
252 |
253 | TempData
254 | message body
255 | message header
256 | Show closing button
257 |
258 |
259 |
260 | Create dark alert
261 |
262 | TempData
263 | message body
264 | message header
265 | Show closing button
266 |
267 |
268 |
269 | Create alert messages styled with bootstrap 4.x
270 | Alert contents must be replaced between alert tags e.g. job done!]]>
271 |
272 |
273 |
274 |
275 | Header text for the alert
276 |
277 |
278 |
279 |
280 | Show closing button, default is true
281 |
282 |
283 |
284 |
285 | Show multiple alerts as slides
286 |
287 |
288 |
289 |
290 | Show alert icons from fontawesome.
291 | Requires fontawesome css or bootstrap
292 |
293 |
294 |
295 |
296 | Choose where to get icons source from. "Bootstrap" or "FontAwesome".
297 |
298 |
299 |
300 |
301 | Choose render mode: Bootstrap5 if your project is using bootstrap5, otherwise default is Bootstrap for earlier versions.
302 |
303 |
304 |
305 |
306 | Parse localizer instance to localize alert message
307 |
308 |
309 |
310 |
311 | ViewContext property is not required to be passed as parameter, it will be assigned automatically by the tag helper.
312 | View context is required to access TempData dictionary that contains the alerts coming from backend
313 |
314 |
315 |
316 |
317 | Create alert messages styled with bootstrap 4.x
318 |
319 |
320 |
321 |
322 | creates email link with mark if email is confirmed
323 |
324 |
325 |
326 |
327 | boolean value to indicate if the email is confirmed or not
328 |
329 |
330 |
331 |
332 | process in creating email tag helper
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 | The label to display for language dropdown list on language names
341 |
342 |
343 |
344 |
345 | Culture name
346 |
347 |
348 |
349 |
350 | Culture display name
351 |
352 |
353 |
354 |
355 | Culture English name
356 |
357 |
358 |
359 |
360 | Culture native name
361 |
362 |
363 |
364 |
365 | Two letter ISO language name
366 |
367 |
368 |
369 |
370 | creates a language navigation menu, depends on supported cultures
371 |
372 |
373 |
374 |
375 | optional: manually specify list of supported cultures
376 |
377 | en-US,tr, ar
378 |
379 |
380 |
381 |
382 |
383 | optional: what to display as label for language dropdown
384 | default: LanguageLabel.EnglishName
385 |
386 |
387 |
388 |
389 | ViewContext property is not required to be passed as parameter, it will be auto assigned by the tag helpoer.
390 | current view context to access RouteData.Values and Request.Query collection
391 |
392 |
393 |
394 |
395 | Choose render mode: classis for regular dropdown list, Bootstrap4 for HTML5 div with Bootstrap4 style.
396 |
397 |
398 |
399 |
400 | Set the handler url for setting culture cookie on language change
401 |
402 |
403 |
404 |
405 | The url to redirect to on langugae change.
406 | The url must have at one place holder for culture value.
407 | e.g. /{0}/Home
408 |
409 |
410 |
411 |
412 | Show relevant country flag for specific culture.
413 | Flags will be shown only if the culture is country specific.
414 | e.g. "tr" will not render any flag, but "tr-sy" will render Turkish flag.
415 | Required reference to flag-icon-css
416 |
417 |
418 |
419 |
420 | true: Show flags in squared images,
421 | false: Show flags in rounded images,
422 |
423 |
424 |
425 |
426 | Whether show border or not
427 |
428 |
429 |
430 |
431 | required for listing supported cultures.
432 | The handler must contain two place holders for culture name and return url.
433 | e.g.:
434 |
435 |
436 |
437 |
438 | creates a language navigation menu, depends on supported cultures
439 |
440 |
441 |
442 |
443 |
444 | start creating the language navigation dropdown
445 |
446 |
447 |
448 |
449 |
450 |
451 | create classic list items list
452 | English]]>
453 |
454 | language name-URL dictionary
455 | reference to TagHelperOuput
456 |
457 |
458 |
459 |
460 | create a dropdown form control
461 | English]]>
462 |
463 | language name-URL dictionary
464 | reference to TagHelperOuput
465 |
466 |
467 |
468 |
469 | create classic list items list
470 | English]]>
471 |
472 | language name-URL dictionary
473 | reference to TagHelperOuput
474 |
475 |
476 |
477 |
478 | create classic list items list
479 | English]]>
480 |
481 | language name-URL dictionary
482 | reference to TagHelperOuput
483 |
484 |
485 |
486 |
487 | create dictonary for all supported cultures
488 | Key: Language display name for label
489 | Value: Navigation URL
490 |
491 |
492 |
493 |
494 |
495 | private list of supported CultureInfo,
496 |
497 |
498 |
499 |
500 | defines location to load localization valdiation scripts
501 |
502 |
503 |
504 |
505 | valdiation scripts are located under wwwroot/lib folder
506 |
507 |
508 |
509 |
510 | valdiation scripts will be loaded from jsdelivr
511 |
512 |
513 |
514 |
515 | Tag helper for client side localized validation scripts.
516 |
517 |
518 |
519 |
520 | (optional) define where to load scripts from, Local or JsDelivr.
521 | Default: JsDelivr
522 |
523 |
524 |
525 |
526 | (optional) set cldr version to load.
527 | Default: 35.1
528 |
529 |
530 |
531 |
532 | Tag helper for client side localized validation scripts.
533 |
534 |
535 |
536 |
537 | Tag helper component for client side localized validation scripts.
538 |
539 |
540 |
541 |
542 | inserts all localizaiton validation scripts into relevant tag
543 |
544 |
545 |
546 |
547 |
548 | default order is 0
549 |
550 |
551 |
552 |
553 | generate the taghelper
554 |
555 |
556 |
557 |
558 |
559 |
560 | find json files related to the current culture, if not found return parent culture, if not found return default culture.
561 | see ClientSideValidationScripts.html for how to configure paths
562 |
563 | culture name e.g. tr
564 |
565 |
566 |
567 | ajax update modes
568 |
569 |
570 |
571 |
572 | update before target content
573 |
574 |
575 |
576 |
577 | update after target content
578 |
579 |
580 |
581 |
582 | replace target content
583 |
584 |
585 |
586 |
587 | The http request method
588 |
589 |
590 |
591 |
592 | get request
593 |
594 |
595 |
596 |
597 | post request
598 |
599 |
600 |
601 |
602 | Creates a pagination control
603 |
604 |
605 |
606 |
607 | Dictonary object to hold all ajax attributes
608 |
609 |
610 |
611 |
612 | A URL template for paging buttons
613 | e.g.
614 |
615 |
616 |
617 |
618 |
619 | ViewContext property is not required to be passed as parameter, it will be assigned automatically by the tag helper.
620 | View context is required to access TempData dictionary that contains the alerts coming from backend
621 |
622 |
623 |
624 |
625 | Creates a pagination control
626 |
627 |
628 |
629 |
630 | current page number.
631 | default: 1
632 | example: p=1
633 |
634 |
635 |
636 |
637 | how many items to get from db per page per request
638 | default: 10
639 | example: pageSize=10
640 |
641 |
642 |
643 |
644 | Total count of records in the db
645 | default: 0
646 |
647 |
648 |
649 |
650 | if count of pages is too much, restrict shown pages count to specific number
651 | default: 10
652 |
653 |
654 |
655 |
656 | name of the settings section in appSettings.json
657 | default: "default"
658 |
659 |
660 |
661 |
662 | Force adding url path to the navigation url
663 | in some scenarios when the page is under some area/subFolder
664 | The navigation links are pointing to the home page.
665 | To force adding url path enable this property
666 |
667 |
668 |
669 |
670 | A list of dash delimitted numbers for page size dropdown.
671 | default: "10-25-50"
672 |
673 |
674 |
675 |
676 | Query string paramter name for current page.
677 | default: p
678 | exmaple: p=1
679 |
680 |
681 |
682 |
683 | Query string parameter name for page size
684 | default: s
685 | example: s=25
686 |
687 |
688 |
689 |
690 | Show drop down list for different page size options
691 | default: true
692 | options: true, false
693 |
694 |
695 |
696 |
697 | Show a three dots after first page or before last page
698 | when there is a gap in pages at the beginnig or end
699 |
700 |
701 |
702 |
703 | Show/hide First-Last buttons
704 | default: true, if set to false and total pages > max displayed pages it will be true
705 |
706 |
707 |
708 |
709 | Show/hide Previous-Next buttons
710 | default: true
711 |
712 |
713 |
714 |
715 | Show or hide total pages count
716 | default: true
717 |
718 |
719 |
720 |
721 | Show or hide total records count
722 | default: true
723 |
724 |
725 |
726 |
727 | The text to display at page size dropdown list label
728 | default: Page size
729 |
730 |
731 |
732 |
733 | Text to show on the "Go To First" Page button
734 |
735 |
736 |
737 |
738 |
739 |
740 | Text to show on "Go to last page" button
741 |
742 |
743 |
744 |
745 |
746 |
747 | Next button text
748 |
749 |
750 |
751 |
752 |
753 |
754 | previous button text
755 |
756 |
757 |
758 |
759 |
760 |
761 | Display text for total pages label
762 | default: page
763 |
764 |
765 |
766 |
767 | Display text for total records label
768 | default: records
769 |
770 |
771 |
772 |
773 | The number display format for page numbers. Use a list of numbers splitted by space e.g. "0 1 2 3 4 5 6 7 8 9" or use one from a pre-defined numbers formats in :
774 |
775 |
776 |
777 |
778 |
779 | Text for screen readers only
780 |
781 |
782 |
783 |
784 | text for screen readers only
785 |
786 |
787 |
788 |
789 | text for screenreaders only
790 |
791 |
792 |
793 |
794 | text for screen readers only
795 |
796 |
797 |
798 |
799 | Select bootstrap version
800 |
801 |
802 |
803 |
804 | add custom class to content div
805 |
806 |
807 |
808 |
809 | css class for pagination div
810 |
811 |
812 |
813 |
814 | css class for page count/record count div
815 |
816 |
817 |
818 |
819 | styling class for page size div
820 |
821 |
822 |
823 |
824 | pagination control class
825 | default: pagination
826 |
827 |
828 |
829 |
830 | class name for the active page
831 | default: active
832 | examples: disabled, active, ...
833 |
834 |
835 |
836 |
837 | name of the class when jumping button is disabled.
838 | jumping buttons are prev-next and first-last buttons
839 | default: disabled
840 | example: disabled, d-hidden
841 |
842 |
843 |
844 |
845 | css class for total records info
846 | default: badge badge-light
847 |
848 |
849 |
850 |
851 | css class for total pages info
852 | default: badge badge-light
853 |
854 |
855 |
856 |
857 | css class for page link, use for styling bg and text colors
858 |
859 |
860 |
861 |
862 | Set to true to use ajax pagination
863 |
864 |
865 |
866 |
867 | The message to display in a confirmation window before a request is submitted.
868 |
869 |
870 |
871 |
872 | The mode that specifies how to insert the response into the target DOM element. Valid values are before, after and replace. Default is replace
873 |
874 |
875 |
876 |
877 | A value, in milliseconds, that controls the duration of the animation when showing or hiding the loading element.
878 |
879 |
880 |
881 |
882 | The id attribute of an HTML element that is displayed while the Ajax function is loading. Default is #loading-spinner
883 |
884 |
885 |
886 |
887 | The name of the JavaScript function to call immediately before the page is updated.
888 |
889 |
890 |
891 |
892 | The JavaScript function to call when response data has been instantiated but before the page is updated.
893 |
894 |
895 |
896 |
897 | The JavaScript function to call if the page update fails.
898 |
899 |
900 |
901 |
902 | The JavaScript function to call after the page is successfully updated.
903 |
904 |
905 |
906 |
907 | The ID of the DOM element to update by using the response from the server.
908 |
909 |
910 |
911 |
912 | The URL to make the request to.
913 |
914 |
915 |
916 |
917 | process creating paging tag helper
918 |
919 |
920 |
921 |
922 |
923 |
924 | This method will assign the values by checking three places
925 | 1- Property value if set from HTML code
926 | 2- Default values in appSettings.json
927 | 3- Hard coded default value in code
928 |
929 |
930 |
931 |
932 | Calculate the boundaries of the currently rendered page numbers
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 | dropdown list for changing page size (items per page)
942 |
943 |
944 |
945 |
946 |
947 | edit the url for each page, so it navigates to its target page number
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 | edit the url for each page, so it navigates to its target page number
956 |
957 | a string with placeholders for page no and page size
958 |
959 |
960 |
961 | creates a display for phone number
962 |
963 |
964 |
965 |
966 | boolean value to indicate if the phone number has been confirmed
967 |
968 |
969 |
970 |
971 | process creating phone number tag helper
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 | A strongly-typed resource class, for looking up localized strings, etc.
980 |
981 |
982 |
983 |
984 | Returns the cached ResourceManager instance used by this class.
985 |
986 |
987 |
988 |
989 | Overrides the current thread's CurrentUICulture property for all
990 | resource lookups using this strongly typed resource class.
991 |
992 |
993 |
994 |
995 | Looks up a localized string similar to <!-- cldr scripts (needed for globalize) -->
996 | <script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr.js"></script>
997 | <script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr/event.js"></script>
998 | <script src="https://cdn.jsdelivr.net/gh/rxaviers/cldrjs@0.5.1/dist/cldr/supplemental.js"></script>
999 |
1000 | <!-- globalize scripts -->
1001 | <script src="https://cdn.jsdelivr.net/gh/globalizejs/globalize@1.4.2/dist/globalize.js"></script>
1002 | <script src="https://cdn.jsdelivr.net/gh/globalizejs/g [rest of string was truncated]";.
1003 |
1004 |
1005 |
1006 |
1007 | Looks up a localized string similar to <!-- cldr scripts (needed for globalize) -->
1008 | <script src="/lib/cldr/dist/cldr.min.js"></script>
1009 | <script src="/lib/cldr/dist/cldr/event.min.js"></script>
1010 | <script src="/lib/cldr/dist/cldr/supplemental.min.js"></script>
1011 |
1012 | <!-- globalize scripts -->
1013 | <script src="/lib/globalize/dist/globalize.min.js"></script>
1014 | <script src="/lib/globalize/dist/globalize/number.min.js"></script>
1015 | <script src="/lib/globalize/dist/globalize/date.min.js"></script>
1016 | <script src="/lib/globalize/dist/globalize/currency.min.js"></s [rest of string was truncated]";.
1017 |
1018 |
1019 |
1020 |
1021 | choose render mode style,
1022 | classic: regular dropdown select list
1023 | Bootstrap4: HTML5 div with Bootstrap4 support
1024 |
1025 |
1026 |
1027 |
1028 | regular dropdown list
1029 |
1030 |
1031 |
1032 |
1033 | HTML5 div with Bootstrap 4 support
1034 |
1035 |
1036 |
1037 |
1038 | Render as form control
1039 |
1040 |
1041 |
1042 |
1043 | HTML5 div with Bootstrap 5 support
1044 |
1045 |
1046 |
1047 |
1048 | creates a dropdown list from custom enum with supports for localization
1049 |
1050 |
1051 |
1052 |
1053 | (int)MyEnum.ValueName
1054 |
1055 |
1056 |
1057 |
1058 | typeof(MyEnum)
1059 |
1060 |
1061 |
1062 |
1063 | A delegate function for getting locaized value.
1064 |
1065 |
1066 |
1067 |
1068 | Initialize a new instance of SelectEnum taghelper
1069 |
1070 |
1071 |
1072 |
1073 |
1074 | start creating select-enum tag helper
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 | Generic extension to TempData for adding complex object and fix serialization problem
1082 |
1083 |
1084 |
1085 |
1086 |
1087 | Add object to temp data
1088 |
1089 |
1090 |
1091 |
1092 |
1093 |
1094 |
1095 |
1096 | Read object from temp data
1097 |
1098 |
1099 |
1100 |
1101 |
1102 |
1103 |
1104 |
1105 | Number formats for different cultures.
1106 | https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/numberingSystems.json
1107 |
1108 |
1109 |
1110 |
1111 | Receives a number in system format, and converts it to any other format.
1112 | See
1113 |
1114 |
1115 |
1116 |
1117 |
1118 |
1119 |
1120 | System default numbering format
1121 |
1122 |
1123 |
1124 |
1125 | 0123456789
1126 |
1127 |
1128 |
1129 |
1130 | Use hexadecimal numbering system
1131 |
1132 |
1133 |
1134 |
1135 | I II III IV V VI
1136 |
1137 |
1138 |
1139 |
1140 | ٠١٢٣٤٥٦٧٨٩
1141 |
1142 |
1143 |
1144 |
1145 | 𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯
1146 |
1147 |
1148 |
1149 |
1150 | ০১২৩৪৫৬৭৮৯
1151 |
1152 |
1153 |
1154 |
1155 | ०१२३४५६७८९
1156 |
1157 |
1158 |
1159 |
1160 | ۰۱۲۳۴۵۶۷۸۹
1161 |
1162 |
1163 |
1164 |
1165 | 0123456789
1166 |
1167 |
1168 |
1169 |
1170 | ೦೧೨೩೪೫೬೭೮೯
1171 |
1172 |
1173 |
1174 |
1175 | ૦૧૨૩૪૫૬૭૮૯
1176 |
1177 |
1178 |
1179 |
1180 | ੦੧੨੩੪੫੬੭੮੯
1181 |
1182 |
1183 |
1184 |
1185 | 〇一二三四五六七八九
1186 |
1187 |
1188 |
1189 |
1190 | ꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙
1191 |
1192 |
1193 |
1194 |
1195 | ០១២៣៤៥៦៧៨៩
1196 |
1197 |
1198 |
1199 |
1200 | ໐໑໒໓໔໕໖໗໘໙
1201 |
1202 |
1203 |
1204 |
1205 | 0123456789
1206 |
1207 |
1208 |
1209 |
1210 | 𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗
1211 |
1212 |
1213 |
1214 |
1215 | 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡
1216 |
1217 |
1218 |
1219 |
1220 | 𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿
1221 |
1222 |
1223 |
1224 |
1225 | 𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵
1226 |
1227 |
1228 |
1229 |
1230 | 𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫
1231 |
1232 |
1233 |
1234 |
1235 | ൦൧൨൩൪൫൬൭൮൯
1236 |
1237 |
1238 |
1239 |
1240 | ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙
1241 |
1242 |
1243 |
1244 |
1245 | ၀၁၂၃၄၅၆၇၈၉
1246 |
1247 |
1248 |
1249 |
1250 | ႐႑႒႓႔႕႖႗႘႙
1251 |
1252 |
1253 |
1254 |
1255 | ꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹
1256 |
1257 |
1258 |
1259 |
1260 | ߀߁߂߃߄߅߆߇߈߉
1261 |
1262 |
1263 |
1264 |
1265 | ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙
1266 |
1267 |
1268 |
1269 |
1270 | ୦୧୨୩୪୫୬୭୮୯
1271 |
1272 |
1273 |
1274 |
1275 | 𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩
1276 |
1277 |
1278 |
1279 |
1280 | ෦෧෨෩෪෫෬෭෮෯
1281 |
1282 |
1283 |
1284 |
1285 | ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙
1286 |
1287 |
1288 |
1289 |
1290 | ௦௧௨௩௪௫௬௭௮௯
1291 |
1292 |
1293 |
1294 |
1295 | ౦౧౨౩౪౫౬౭౮౯
1296 |
1297 |
1298 |
1299 |
1300 | ๐๑๒๓๔๕๖๗๘๙
1301 |
1302 |
1303 |
1304 |
1305 | ༠༡༢༣༤༥༦༧༨༩
1306 |
1307 |
1308 |
1309 |
1310 | ꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩
1311 |
1312 |
1313 |
1314 |
1315 | Convert decimals to roman numerals
1316 |
1317 |
1318 |
1319 |
1320 | Dictionary of roman numbers and their equavilant decimals
1321 |
1322 |
1323 |
1324 |
1325 |
1326 | Convert decimal number to roman number
1327 |
1328 | unsigned number
1329 | Roman number
1330 |
1331 |
1332 |
1333 |
--------------------------------------------------------------------------------