1515 */
1616
1717const ModelProperty = {
18- TABLE_HTML : "table_html" ,
19- ROW_COUNT : "row_count" ,
20- PAGE_SIZE : "page_size" ,
2118 PAGE : "page" ,
19+ PAGE_SIZE : "page_size" ,
20+ ROW_COUNT : "row_count" ,
21+ TABLE_HTML : "table_html" ,
2222} ;
2323
2424const Event = {
@@ -28,39 +28,48 @@ const Event = {
2828} ;
2929
3030/**
31- * Renders a paginated table and its controls into a given element .
31+ * Renders the interactive table widget .
3232 * @param {{
33- * model: !Backbone.Model ,
34- * el: ! HTMLElement
33+ * model: any ,
34+ * el: HTMLElement
3535 * }} options
3636 */
3737function render ( { model, el } ) {
38- // Structure
38+ // Main container with a unique class for CSS scoping
3939 const container = document . createElement ( "div" ) ;
40+ container . classList . add ( "bigframes-widget" ) ;
41+
42+ // Structure
4043 const tableContainer = document . createElement ( "div" ) ;
4144 const footer = document . createElement ( "div" ) ;
42- // Total rows label
45+
46+ // Footer: Total rows label
4347 const rowCountLabel = document . createElement ( "div" ) ;
44- // Pagination controls
48+
49+ // Footer: Pagination controls
4550 const paginationContainer = document . createElement ( "div" ) ;
4651 const prevPage = document . createElement ( "button" ) ;
4752 const paginationLabel = document . createElement ( "span" ) ;
4853 const nextPage = document . createElement ( "button" ) ;
49- // Page size controls
54+
55+ // Footer: Page size controls
5056 const pageSizeContainer = document . createElement ( "div" ) ;
5157 const pageSizeLabel = document . createElement ( "label" ) ;
5258 const pageSizeSelect = document . createElement ( "select" ) ;
5359
60+ // Add CSS classes
5461 tableContainer . classList . add ( "table-container" ) ;
5562 footer . classList . add ( "footer" ) ;
5663 paginationContainer . classList . add ( "pagination" ) ;
5764 pageSizeContainer . classList . add ( "page-size" ) ;
5865
66+ // Configure pagination buttons
5967 prevPage . type = "button" ;
6068 nextPage . type = "button" ;
6169 prevPage . textContent = "Prev" ;
6270 nextPage . textContent = "Next" ;
6371
72+ // Configure page size selector
6473 pageSizeLabel . textContent = "Page Size" ;
6574 for ( const size of [ 10 , 25 , 50 , 100 ] ) {
6675 const option = document . createElement ( "option" ) ;
@@ -72,39 +81,34 @@ function render({ model, el }) {
7281 pageSizeSelect . appendChild ( option ) ;
7382 }
7483
75- /** Updates the button states and page label based on the model. */
84+ /** Updates the footer states and page label based on the model. */
7685 function updateButtonStates ( ) {
7786 const rowCount = model . get ( ModelProperty . ROW_COUNT ) ;
78- rowCountLabel . textContent = `${ rowCount . toLocaleString ( ) } total rows` ;
79-
80- const totalPages = Math . ceil (
81- model . get ( ModelProperty . ROW_COUNT ) / model . get ( ModelProperty . PAGE_SIZE ) ,
82- ) ;
87+ const pageSize = model . get ( ModelProperty . PAGE_SIZE ) ;
8388 const currentPage = model . get ( ModelProperty . PAGE ) ;
89+ const totalPages = Math . ceil ( rowCount / pageSize ) ;
8490
85- paginationLabel . textContent = `Page ${ currentPage + 1 } of ${ totalPages } ` ;
91+ rowCountLabel . textContent = `${ rowCount . toLocaleString ( ) } total rows` ;
92+ paginationLabel . textContent = `Page ${ currentPage + 1 } of ${ totalPages || 1 } ` ;
8693 prevPage . disabled = currentPage === 0 ;
8794 nextPage . disabled = currentPage >= totalPages - 1 ;
88-
89- // Update page size selector
90- pageSizeSelect . value = model . get ( ModelProperty . PAGE_SIZE ) ;
95+ pageSizeSelect . value = pageSize ;
9196 }
9297
9398 /**
94- * Updates the page in the model.
95- * @param {number } direction -1 for previous, 1 for next .
99+ * Increments or decrements the page in the model.
100+ * @param {number } direction - `1` for next, `-1` for previous .
96101 */
97102 function handlePageChange ( direction ) {
98- const currentPage = model . get ( ModelProperty . PAGE ) ;
99- const newPage = Math . max ( 0 , currentPage + direction ) ;
100- if ( newPage !== currentPage ) {
101- model . set ( ModelProperty . PAGE , newPage ) ;
102- model . save_changes ( ) ;
103- }
103+ const current = model . get ( ModelProperty . PAGE ) ;
104+ const next = current + direction ;
105+ model . set ( ModelProperty . PAGE , next ) ;
106+ model . save_changes ( ) ;
104107 }
105108
106- /** Handles the page_size in the model.
107- * @param {number } size - new size to set
109+ /**
110+ * Handles changes to the page size from the dropdown.
111+ * @param {number } size - The new page size.
108112 */
109113 function handlePageSizeChange ( size ) {
110114 const currentSize = model . get ( ModelProperty . PAGE_SIZE ) ;
@@ -114,14 +118,15 @@ function render({ model, el }) {
114118 }
115119 }
116120
117- /** Updates the HTML in the table container * */
121+ /** Updates the HTML in the table container and refreshes button states. */
118122 function handleTableHTMLChange ( ) {
119- // Note: Using innerHTML can be a security risk if the content is
120- // user-generated. Ensure 'table_html' is properly sanitized .
123+ // Note: Using innerHTML is safe here because the content is generated
124+ // by a trusted backend (DataFrame.to_html) .
121125 tableContainer . innerHTML = model . get ( ModelProperty . TABLE_HTML ) ;
122126 updateButtonStates ( ) ;
123127 }
124128
129+ // Add event listeners
125130 prevPage . addEventListener ( Event . CLICK , ( ) => handlePageChange ( - 1 ) ) ;
126131 nextPage . addEventListener ( Event . CLICK , ( ) => handlePageChange ( 1 ) ) ;
127132 pageSizeSelect . addEventListener ( Event . CHANGE , ( e ) => {
@@ -132,18 +137,24 @@ function render({ model, el }) {
132137 } ) ;
133138 model . on ( Event . CHANGE_TABLE_HTML , handleTableHTMLChange ) ;
134139
135- // Initial setup
140+ // Assemble the DOM
136141 paginationContainer . appendChild ( prevPage ) ;
137142 paginationContainer . appendChild ( paginationLabel ) ;
138143 paginationContainer . appendChild ( nextPage ) ;
144+
139145 pageSizeContainer . appendChild ( pageSizeLabel ) ;
140146 pageSizeContainer . appendChild ( pageSizeSelect ) ;
147+
141148 footer . appendChild ( rowCountLabel ) ;
142149 footer . appendChild ( paginationContainer ) ;
143150 footer . appendChild ( pageSizeContainer ) ;
151+
144152 container . appendChild ( tableContainer ) ;
145153 container . appendChild ( footer ) ;
154+
146155 el . appendChild ( container ) ;
156+
157+ // Initial render
147158 handleTableHTMLChange ( ) ;
148159}
149160
0 commit comments