55 * - webexpress.webui.Event.MODAL_HIDE_EVENT
66 */
77webexpress . webui . ModalCtrl = class extends webexpress . webui . Ctrl {
8- _close = null ;
8+ _closeLabel = null ;
99 _size = null ;
1010 _autoShow = null ;
11- _contentDiv = null ;
12- _dialogDiv = $ ( "<div class='modal-dialog modal-dialog-scrollable'>" ) ;
13- _headerDiv = null ;
14- _footerDiv = null ;
15- _bodyDiv = null ;
11+ _dialogDiv = document . createElement ( "div" ) ;
12+ _contentDiv = document . createElement ( "div" ) ;
13+ _headerDiv = document . createElement ( "div" ) ;
14+ _titleH1 = document . createElement ( "h1" ) ;
15+ _bodyDiv = document . createElement ( "div" ) ;
16+ _footerDiv = document . createElement ( "div" ) ;
17+ _cancelButton = document . createElement ( "button" ) ;
1618
1719 /**
1820 * Constructor
@@ -22,87 +24,110 @@ webexpress.webui.ModalCtrl = class extends webexpress.webui.Ctrl {
2224 super ( element ) ;
2325
2426 // Retrieve custom attributes or use default values
25- this . _close = $ ( element ) . data ( "close-label" ) || this . _close ;
26- this . _size = $ ( element ) . data ( "size" ) || null ;
27- this . _autoShow = $ ( element ) . data ( "auto-show" ) || null ;
28-
29- // Extract header, content, and footer from the provided HTML structure
30- this . _headerDiv = $ ( "<div>" ) . append ( $ ( ".wx-modal-header" , this . _element ) . detach ( ) ) ;
31- this . _contentDiv = $ ( "<div>" ) . append ( $ ( ".wx-modal-content" , this . _element ) . children ( ) . detach ( ) ) ;
32- this . _footerDiv = $ ( "<div>" ) . append ( $ ( ".wx-modal-footer" , this . _element ) . children ( ) . detach ( ) ) ;
27+ this . _closeLabel = element . getAttribute ( "data-close-label" ) || "Close" ;
28+ this . _size = element . getAttribute ( "data-size" ) || "" ;
29+ this . _autoShow = element . getAttribute ( "data-auto-show" ) === "true" ;
3330
3431 // Cleanup the DOM element
35- $ ( this . _element )
36- . removeAttr ( "data-close-label data-size data-auto-show" ) // Remove unnecessary attributes
37- . empty ( ) // Clear existing content
38- . addClass ( "modal fade" ) // Add modal-specific classes
39- . attr ( "tabindex" , "-1" )
40- . attr ( "aria-hidden" , "true" ) ;
41-
42- // Create modal header
43- const header = $ ( "<div class='modal-header'>" )
44- . append ( $ ( "<h1 class='modal-title fs-5'>" ) . append ( this . _headerDiv ) )
45- . append (
46- $ ( "<button type='button' class='btn-close' data-wx-dismiss='modal'>" )
47- . attr ( "aria-label" , this . _close )
48- ) ;
49-
50- // Create modal footer
51- const footer = $ ( "<div class='modal-footer'>" )
52- . append ( this . _footerDiv )
53- . append (
54- $ ( "<button type='button' class='btn btn-secondary' data-wx-dismiss='modal'>" )
55- . text ( this . _close ) . prepend ( $ ( "<i class='fas fa-times me-2'>" ) )
56-
57- ) ;
58-
59- // Create modal body
60- this . _bodyDiv = $ ( "<div class='modal-body'>" ) ;
61-
62- // Combine header, body, and footer into modal content
63- const modalContent = $ ( "<div class='modal-content'>" ) . append ( header , this . _bodyDiv , footer ) ;
64-
65- // Add size class to dialog and append modal content
66- this . _dialogDiv . addClass ( this . _size ) . append ( modalContent ) ;
67-
68- if ( this . _autoShow === true ) {
69- this . show ( ) ; // Automatically show the modal if specified
32+ element . removeAttribute ( "data-close-label" ) ;
33+ element . removeAttribute ( "data-size" ) ;
34+ element . removeAttribute ( "data-auto-show" ) ;
35+ element . classList . add ( "modal" , "fade" ) ;
36+
37+ // Create modal elements
38+ this . _bodyDiv . className = "modal-body" ;
39+ this . _headerDiv . className = "modal-header" ;
40+ this . _titleH1 . className = "modal-title fs-5" ;
41+ this . _footerDiv . className = "modal-footer" ;
42+
43+ // Extract and append children from .wx-modal-header
44+ const headers = this . _element . querySelectorAll ( ".wx-modal-header" ) ;
45+ headers . forEach ( header => {
46+ this . _titleH1 . appendChild ( this . _detachElement ( header ) ) ;
47+ } ) ;
48+
49+ // Extract and append all .wx-modal-content elements
50+ const contents = this . _element . querySelectorAll ( ".wx-modal-content" ) ;
51+ contents . forEach ( content => {
52+ this . _contentDiv . appendChild ( this . _detachElement ( content ) ) ;
53+ } ) ;
54+
55+ // Extract and append all .wx-modal-footer elements
56+ const footers = this . _element . querySelectorAll ( ".wx-modal-footer" ) ;
57+ footers . forEach ( footer => {
58+ this . _footerDiv . appendChild ( this . _detachElement ( footer ) ) ;
59+ } ) ;
60+
61+ // Create header content
62+ this . _headerDiv . appendChild ( this . _titleH1 ) ;
63+ this . _bodyDiv . appendChild ( this . _contentDiv ) ;
64+
65+ const closeButton = document . createElement ( "button" ) ;
66+ closeButton . type = "button" ;
67+ closeButton . className = "btn-close" ;
68+ closeButton . setAttribute ( "data-wx-dismiss" , "modal" ) ;
69+ closeButton . setAttribute ( "aria-label" , this . _closeLabel ) ;
70+ closeButton . addEventListener ( "click" , ( ) => this . hide ( ) ) ;
71+ this . _headerDiv . appendChild ( closeButton ) ;
72+
73+ // Create footer content
74+ this . _cancelButton . type = "button" ;
75+ this . _cancelButton . className = "btn btn-secondary" ;
76+ this . _cancelButton . setAttribute ( "data-wx-dismiss" , "modal" ) ;
77+ this . _cancelButton . innerHTML = `<i class='fas fa-times me-2'></i>${ this . _closeLabel } ` ;
78+ this . _cancelButton . addEventListener ( "click" , ( ) => this . hide ( ) ) ;
79+ this . _footerDiv . appendChild ( this . _cancelButton ) ;
80+
81+ // Create modal content structure
82+ this . _dialogDiv . className = `modal-dialog modal-dialog-scrollable ${ this . _size } ` ;
83+
84+ const modalContentDiv = document . createElement ( "div" ) ;
85+ modalContentDiv . className = "modal-content" ;
86+ modalContentDiv . appendChild ( this . _headerDiv ) ;
87+ modalContentDiv . appendChild ( this . _bodyDiv ) ;
88+ modalContentDiv . appendChild ( this . _footerDiv ) ;
89+
90+ this . _dialogDiv . appendChild ( modalContentDiv ) ;
91+ this . _element . appendChild ( this . _dialogDiv ) ;
92+
93+ // Auto-show if specified
94+ if ( this . _autoShow ) {
95+ this . show ( ) ;
7096 }
7197 }
7298
7399 /**
74100 * Updates the modal content with fetched data from the URI.
75101 */
76102 update ( ) {
77- // Clear existing content in body and append the new content
78- this . _bodyDiv . empty ( ) . append ( this . _contentDiv ) ;
79-
80- // Clear the DOM element and append the dialog structure
81- $ ( this . _element ) . empty ( ) . append ( this . _dialogDiv ) ;
103+ if ( ! this . _element . hasChildNodes ( ) ) {
104+ this . _element . appendChild ( this . _dialogDiv ) ;
105+ }
82106
83107 // Bind click event to close the modal when dismiss button is clicked
84- this . _dialogDiv . find ( "[data-wx-dismiss='modal']" ) . click ( ( ) => {
85- this . hide ( ) ; // Hide only this modal dialog
86- } ) ;
108+ const closeButton = this . _dialogDiv . querySelector ( "[data-wx-dismiss='modal']" ) ;
109+ if ( closeButton ) {
110+ closeButton . removeEventListener ( "click" , this . hide ) ;
111+ closeButton . addEventListener ( "click" , ( ) => this . hide ( ) ) ; // Bind click event
112+ }
87113 }
88114
89115 /**
90116 * Displays the modal by retrieving or creating its Bootstrap instance.
91117 * Ensures the modal is properly initialized before showing it.
92118 */
93119 show ( ) {
94- this . update ( ) ; // Ensure modal content is up to date
95- const modalInstance = bootstrap . Modal . getOrCreateInstance ( this . _element , {
96- backdrop : ' static' ,
97- keyboard : true
120+ this . update ( ) ; // Ensure modal content is refreshed
121+ const modalInstance = new bootstrap . Modal ( this . _element , {
122+ backdrop : " static" ,
123+ keyboard : true ,
98124 } ) ;
99- modalInstance . show ( ) ; // Open the modal
125+ modalInstance . show ( ) ;
100126
101- // Trigger custom event for showing the modal
102- $ ( document ) . trigger ( webexpress . webui . Event . MODAL_SHOW_EVENT , {
103- sender : this . _element ,
104- id : $ ( this . _element ) . attr ( "id" ) ,
105- } ) ;
127+ // Trigger event for showing the modal
128+ document . dispatchEvent ( new CustomEvent ( webexpress . webui . Event . MODAL_SHOW_EVENT , {
129+ detail : { sender : this . _element , id : this . _element . id }
130+ } ) ) ;
106131 }
107132
108133 /**
@@ -111,22 +136,23 @@ webexpress.webui.ModalCtrl = class extends webexpress.webui.Ctrl {
111136 */
112137 hide ( ) {
113138 const modalInstance = bootstrap . Modal . getInstance ( this . _element ) ;
114- modalInstance ?. hide ( ) ; // Close the modal
115139
140+ this . _element . addEventListener ( "hidden.bs.modal" , ( ) => {
141+ this . _element . removeAttribute ( "style" ) ;
142+ this . _element . removeAttribute ( "aria-hidden" ) ;
116143
117- // Cleanup content after the modal is fully hidden
118- $ ( this . _element ) . on ( "hidden.bs.modal" , ( ) => {
119- $ ( this . _element ) . empty ( ) ; // Clear modal content
120- $ ( document ) . trigger ( webexpress . webui . Event . MODAL_HIDE_EVENT , {
144+ document . dispatchEvent ( new CustomEvent ( webexpress . webui . Event . MODAL_HIDE_EVENT , {
121145 sender : this . _element ,
122- id : $ ( this . _element ) . attr ( "id" ) ,
123- } ) ;
124-
125- modalInstance ?. dispose ( ) ; // Free memory
146+ id : this . _element . id
147+ } ) ) ;
126148 } ) ;
127-
128- // Ensure event listeners are properly removed
129- $ ( this . _element ) . off ( "hidden.bs.modal" ) ;
149+
150+ this . _element . innerHTML = "" ;
151+ this . _element . removeAttribute ( "style" ) ;
152+ this . _element . removeAttribute ( "aria-hidden" ) ;
153+ document . body . focus ( ) ;
154+
155+ modalInstance ?. hide ( ) ;
130156 }
131157} ;
132158
0 commit comments