22let selectedFiles = [ ]
33let currentSourceType = 'upload'
44let currentExportTab = 'presets'
5+ let presetsConfig = null
56
67// Initialize app
7- document . addEventListener ( 'DOMContentLoaded' , ( ) => {
8+ document . addEventListener ( 'DOMContentLoaded' , async ( ) => {
9+ await loadPresets ( )
810 initializeTabs ( )
911 initializeExportTabs ( )
1012 initializeUpload ( )
1113 initializeAdvancedSettings ( )
1214 initializeForm ( )
1315 initializeExportSelection ( )
1416 initializeFormatDescription ( )
17+ initializePresetDescription ( )
1518} )
1619
20+ // Load presets from server
21+ async function loadPresets ( ) {
22+ try {
23+ const response = await fetch ( '/api/presets' )
24+ const data = await response . json ( )
25+ presetsConfig = data . presets
26+
27+ const presetsGrid = document . getElementById ( 'presets-grid' )
28+ presetsGrid . innerHTML = ''
29+
30+ presetsConfig . forEach ( ( preset , index ) => {
31+ const label = document . createElement ( 'label' )
32+ label . className = 'preset-tile'
33+
34+ const input = document . createElement ( 'input' )
35+ input . type = 'radio'
36+ input . name = 'preset'
37+ input . value = preset . id
38+ input . dataset . description = preset . description
39+ input . dataset . presetOptions = JSON . stringify ( preset . options )
40+ if ( index === 0 ) input . checked = true
41+
42+ const content = document . createElement ( 'div' )
43+ content . className = 'preset-content'
44+
45+ const logo = document . createElement ( 'div' )
46+ logo . style . fontSize = '2rem'
47+ logo . style . marginBottom = '0.5rem'
48+ logo . textContent = preset . logo
49+
50+ const title = document . createElement ( 'h3' )
51+ title . textContent = preset . name
52+
53+ const subtitle = document . createElement ( 'p' )
54+ subtitle . textContent = preset . subtitle
55+
56+ content . appendChild ( logo )
57+ content . appendChild ( title )
58+ content . appendChild ( subtitle )
59+
60+ label . appendChild ( input )
61+ label . appendChild ( content )
62+
63+ presetsGrid . appendChild ( label )
64+ } )
65+ } catch ( error ) {
66+ console . error ( 'Failed to load presets:' , error )
67+ }
68+ }
69+
1770// Tab switching
1871function initializeTabs ( ) {
1972 const tabs = document . querySelectorAll ( '.tab-button' )
@@ -168,25 +221,33 @@ function escapeHtml(text) {
168221
169222// Export selection handling
170223function initializeExportSelection ( ) {
171- const presetRadios = document . querySelectorAll ( 'input[name="preset"]' )
172- const formatRadios = document . querySelectorAll ( 'input[name="format"]' )
224+ // Use event delegation for dynamically loaded presets
225+ document . getElementById ( 'presets-grid' ) . addEventListener ( 'change' , ( e ) => {
226+ if ( e . target . name === 'preset' && e . target . checked ) {
227+ // Deselect all formats
228+ const formatRadios = document . querySelectorAll ( 'input[name="format"]' )
229+ formatRadios . forEach ( ( radio ) => {
230+ radio . checked = false
231+ } )
173232
174- // When preset is selected, deselect formats and update settings
175- presetRadios . forEach ( ( radio ) => {
176- radio . addEventListener ( 'change' , ( ) => {
177- if ( radio . checked ) {
178- formatRadios . forEach ( ( formatRadio ) => {
179- formatRadio . checked = false
180- } )
181- updateAdvancedSettings ( radio . value )
182- }
183- } )
233+ // Apply preset options to the form
234+ applyPresetOptions ( e . target )
235+
236+ // Get the preset configuration to determine the format
237+ const presetOptions = JSON . parse ( e . target . dataset . presetOptions || '{}' )
238+ const format = presetOptions . format || e . target . value
239+
240+ updateAdvancedSettings ( format )
241+ }
184242 } )
185243
244+ const formatRadios = document . querySelectorAll ( 'input[name="format"]' )
245+
186246 // When format is selected, deselect presets and update settings
187247 formatRadios . forEach ( ( radio ) => {
188248 radio . addEventListener ( 'change' , ( ) => {
189249 if ( radio . checked ) {
250+ const presetRadios = document . querySelectorAll ( 'input[name="preset"]' )
190251 presetRadios . forEach ( ( presetRadio ) => {
191252 presetRadio . checked = false
192253 } )
@@ -195,13 +256,51 @@ function initializeExportSelection() {
195256 } )
196257 } )
197258
198- // Initialize with default selection (Moodle)
199- updateAdvancedSettings ( 'moodle' )
259+ // Initialize with default selection
260+ setTimeout ( ( ) => {
261+ const checkedPreset = document . querySelector ( 'input[name="preset"]:checked' )
262+ if ( checkedPreset ) {
263+ const presetOptions = JSON . parse (
264+ checkedPreset . dataset . presetOptions || '{}'
265+ )
266+ const format = presetOptions . format || checkedPreset . value
267+ applyPresetOptions ( checkedPreset )
268+ updateAdvancedSettings ( format )
269+ }
270+ } , 100 )
200271
201272 // PDF-specific: Toggle header/footer template fields
202273 initializePdfHeaderFooter ( )
203274}
204275
276+ // Apply preset options to form fields
277+ function applyPresetOptions ( presetInput ) {
278+ try {
279+ const options = JSON . parse ( presetInput . dataset . presetOptions || '{}' )
280+
281+ // Apply each option to the corresponding form field
282+ Object . keys ( options ) . forEach ( ( key ) => {
283+ const value = options [ key ]
284+ const fieldName = `option_${ key } `
285+
286+ // Try to find the field by name
287+ const field = document . querySelector ( `[name="${ fieldName } "]` )
288+
289+ if ( field ) {
290+ if ( field . type === 'checkbox' ) {
291+ field . checked = Boolean ( value )
292+ } else if ( field . type === 'number' ) {
293+ field . value = value
294+ } else {
295+ field . value = value || ''
296+ }
297+ }
298+ } )
299+ } catch ( error ) {
300+ console . error ( 'Failed to apply preset options:' , error )
301+ }
302+ }
303+
205304// Initialize PDF header/footer toggle
206305function initializePdfHeaderFooter ( ) {
207306 const displayHeaderFooter = document . getElementById ( 'pdfDisplayHeaderFooter' )
@@ -412,3 +511,32 @@ function initializeFormatDescription() {
412511 } )
413512 } )
414513}
514+ // Preset description display
515+ function initializePresetDescription ( ) {
516+ // Use event delegation since presets are loaded dynamically
517+ document . getElementById ( 'presets-grid' ) . addEventListener ( 'change' , ( e ) => {
518+ if ( e . target . name === 'preset' ) {
519+ const descriptionBox = document . getElementById ( 'preset-description' )
520+ const descriptionText = descriptionBox . querySelector ( 'p' )
521+ const description = e . target . dataset . description
522+
523+ if ( description ) {
524+ descriptionText . innerHTML = description
525+ descriptionBox . style . display = 'block'
526+ } else {
527+ descriptionBox . style . display = 'none'
528+ }
529+ }
530+ } )
531+
532+ // Show description for initially checked preset
533+ setTimeout ( ( ) => {
534+ const checkedPreset = document . querySelector ( 'input[name="preset"]:checked' )
535+ if ( checkedPreset && checkedPreset . dataset . description ) {
536+ const descriptionBox = document . getElementById ( 'preset-description' )
537+ const descriptionText = descriptionBox . querySelector ( 'p' )
538+ descriptionText . innerHTML = checkedPreset . dataset . description
539+ descriptionBox . style . display = 'block'
540+ }
541+ } , 100 )
542+ }
0 commit comments