22using Microsoft . AspNetCore . Mvc . Rendering ;
33using Microsoft . AspNetCore . Mvc . TagHelpers ;
44using Microsoft . AspNetCore . Razor . TagHelpers ;
5+ using System . Diagnostics . CodeAnalysis ;
56using System . Text . Encodings . Web ;
67using System . Threading . Tasks ;
78
89namespace ICG . AspNetCore . Utilities . Bootstrap5TagHelpers . Modal ;
910
11+ /// <summary>
12+ /// A collection of options for modal dialog sizing
13+ /// </summary>
14+ public enum ModalSize
15+ {
16+ /// <summary>
17+ /// Will render with .modal-sm
18+ /// </summary>
19+ Small = 0 ,
20+
21+ /// <summary>
22+ /// Will render without any additional class
23+ /// </summary>
24+ Default = 1 ,
25+
26+ /// <summary>
27+ /// Will render with .modal-lg
28+ /// </summary>
29+ Large = 2 ,
30+
31+ /// <summary>
32+ /// Will render with .modal-xl
33+ /// </summary>
34+ ExtraLarge = 3
35+ }
36+
37+ /// <summary>
38+ /// A collection of options for setting the full-screen mode of a modal
39+ /// </summary>
40+ public enum ModalFullscreenMode
41+ {
42+ /// <summary>
43+ /// The default behavior, it will NEVER be full screen
44+ /// </summary>
45+ Never = 0 ,
46+ /// <summary>
47+ /// The dialog will ALWAYS be full scree
48+ /// </summary>
49+ Always = 1 ,
50+ /// <summary>
51+ /// The dialog will only be full screen below the small breakpoint
52+ /// </summary>
53+ BelowSmall = 2 ,
54+ /// <summary>
55+ /// The dialog will only be full screen below the medium breakpoint
56+ /// </summary>
57+ BelowMedium = 3 ,
58+ /// <summary>
59+ /// The dialog will only be full screen below the large breakpoint
60+ /// </summary>
61+ BelowLarge = 4 ,
62+ /// <summary>
63+ /// The dialog will only be full screen below the extra large breakpoint
64+ /// </summary>
65+ BelowXLarge = 5 ,
66+ /// <summary>
67+ /// The dialog will only be full screen below the extra extra large breakpoint
68+ /// </summary>
69+ BelowXXLarge = 6
70+ }
71+
72+ /// <summary>
73+ /// Extension methods for helping with conversion of enum to class
74+ /// </summary>
75+ public static class ModalEnumExtensions
76+ {
77+ /// <summary>
78+ /// Converts to the proper CSS class
79+ /// </summary>
80+ /// <param name="modalSize">The targeted size of the modal</param>
81+ /// <returns></returns>
82+ public static string ToClass ( this ModalSize modalSize )
83+ {
84+ switch ( modalSize )
85+ {
86+ case ModalSize . Small :
87+ return "modal-sm" ;
88+ case ModalSize . Large :
89+ return "modal-lg" ;
90+ case ModalSize . ExtraLarge :
91+ return "modal-xl" ;
92+ default :
93+ return string . Empty ;
94+ }
95+ }
96+
97+ /// <summary>
98+ /// Converts to proper css class
99+ /// </summary>
100+ /// <param name="mode">The targeted mode for full screen dispay</param>
101+ /// <returns></returns>
102+ public static string ToClass ( this ModalFullscreenMode mode )
103+ {
104+ switch ( mode )
105+ {
106+ case ModalFullscreenMode . Always :
107+ return "modal-fullscreen" ;
108+ case ModalFullscreenMode . BelowSmall :
109+ return "modal-fullscreen-sm-down" ;
110+ case ModalFullscreenMode . BelowMedium :
111+ return "modal-fullscreen-md-down" ;
112+ case ModalFullscreenMode . BelowLarge :
113+ return "modal-fullscreen-lg-down" ;
114+ case ModalFullscreenMode . BelowXLarge :
115+ return "modal-fullscreen-xl-down" ;
116+ case ModalFullscreenMode . BelowXXLarge :
117+ return "modal-fullscreen-xxl-down" ;
118+ default :
119+ return string . Empty ;
120+ }
121+ }
122+ }
123+
124+
10125/// <summary>
11126/// A high-level wrapper Tag Helper for rendering a bootstrap Modal
12127/// </summary>
13128[ RestrictChildren ( "modal-body" , "modal-header" , "modal-footer" ) ]
14129public class ModalTagHelper : TagHelper
15130{
131+ /// <summary>
132+ /// Determines the optional size of the modal dialog
133+ /// </summary>
134+ public ModalSize Size { get ; set ; } = ModalSize . Default ;
135+
136+ /// <summary>
137+ /// Determines the optional full screen mode of the dialog.
138+ /// </summary>
139+ public ModalFullscreenMode FullscreenMode { get ; set ; } = ModalFullscreenMode . Never ;
140+
16141 /// <summary>
17142 /// If set to true the background will not be clickable to dismiss the dialog
18143 /// </summary>
19144 public bool StaticBackdrop { get ; set ; } = false ;
20145
21146 /// <summary>
22- /// If set to true the modal will have the added class of modal-dialog-centered
147+ /// If set to true the modal will have the added class of modal-dialog-centered
23148 /// </summary>
24149 public bool VerticallyCentered { get ; set ; } = false ;
25150
26151 /// <summary>
27- /// If set to true the modal will have the added class of modal-dialog-scrollable
152+ /// If set to true the modal will have the added class of modal-dialog-scrollable
28153 /// </summary>
29154 public bool Scrollable { get ; set ; } = false ;
30155
156+ /// <summary>
157+ /// Ensure that if we have a context item that we reset. This is needed when you have multiple tag helpers on the same
158+ /// page if the information is not shared
159+ /// </summary>
160+ /// <param name="context"></param>
161+ [ ExcludeFromCodeCoverage ]
31162 public override void Init ( TagHelperContext context )
32163 {
33164 //Reset
34- if ( context . Items . ContainsKey ( typeof ( ModalContext ) ) )
165+ if ( context . Items . ContainsKey ( typeof ( ModalContext ) ) )
166+ {
35167 context . Items . Remove ( typeof ( ModalContext ) ) ;
168+ }
36169 }
37170
38171 /// <summary>
@@ -46,7 +179,9 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu
46179 //Obtain the id value to add to the context
47180 var id = "" ;
48181 if ( output . Attributes . ContainsName ( "id" ) )
182+ {
49183 id = output . Attributes [ "id" ] . Value . ToString ( ) ;
184+ }
50185
51186 //Add the id to the context
52187 var modalContext = new ModalContext { Id = id } ;
@@ -61,19 +196,42 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu
61196 //Add classes to the existing tag, merging with custom ones added
62197 output . AddClass ( "modal" , HtmlEncoder . Default ) ;
63198 output . AddClass ( "fade" , HtmlEncoder . Default ) ;
64-
65- if ( ! string . IsNullOrEmpty ( id ) )
199+
200+ if ( ! string . IsNullOrEmpty ( id ) )
201+ {
66202 output . Attributes . Add ( "aria-labelledby" , $ "{ id } Label") ;
203+ }
204+
67205 output . Attributes . Add ( "aria-hidden" , "true" ) ;
68206 if ( StaticBackdrop )
207+ {
69208 output . Attributes . Add ( "data-bs-backdrop" , "static" ) ;
209+ }
210+
70211 output . Attributes . Add ( "tabindex" , "-1" ) ;
71212 var dialogWrapper = new TagBuilder ( "div" ) ;
72213 dialogWrapper . AddCssClass ( "modal-dialog" ) ;
73214 if ( VerticallyCentered )
215+ {
74216 dialogWrapper . AddCssClass ( "modal-dialog-centered" ) ;
217+ }
218+
75219 if ( Scrollable )
220+ {
76221 dialogWrapper . AddCssClass ( "modal-dialog-scrollable" ) ;
222+ }
223+
224+ var sizeClass = Size . ToClass ( ) ;
225+ if ( ! string . IsNullOrEmpty ( sizeClass ) )
226+ {
227+ dialogWrapper . AddCssClass ( sizeClass ) ;
228+ }
229+
230+ var fullscreenClass = FullscreenMode . ToClass ( ) ;
231+ if ( ! string . IsNullOrEmpty ( fullscreenClass ) )
232+ {
233+ dialogWrapper . AddCssClass ( fullscreenClass ) ;
234+ }
77235 var dialogContent = new TagBuilder ( "div" ) ;
78236 dialogContent . AddCssClass ( "modal-content" ) ;
79237 dialogContent . InnerHtml . AppendHtml ( body ) ;
0 commit comments