Skip to content

Commit

Permalink
Merge pull request #162 from Liturgical-Calendar/JohnRDOrazio/issue161
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnRDOrazio authored Jan 22, 2025
2 parents 85e2d50 + bf3f2cb commit 96b685e
Show file tree
Hide file tree
Showing 6 changed files with 2,102 additions and 1,089 deletions.
73 changes: 27 additions & 46 deletions assets/js/DiocesanCalendarPayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,53 @@
* @prop {string} metadata.region
*/


class DiocesanCalendarPayload {
/**
* Constructs a DiocesanCalendarPayload instance.
*
* @param {Array<RowData>} litcal - The liturgical calendar data.
* @param {Object} settings - The settings for the calendar, containing properties such as epiphany, ascension, and corpus_christi.
* @param {Object} metadata - Additional metadata about the calendar, such as the diocese name, diocese id, nation, supported locales, etc.
*
* @returns {Proxy} - A proxy to control access to properties and prevent adding new ones.
*
* The constructor initializes the payload with the provided liturgical calendar, settings, and metadata.
* It also returns a Proxy that restricts access to only allowed properties and supports JSON serialization.
*/
constructor( litcal, settings, metadata ) {
const allowedProps = new Set(['litcal', 'settings', 'metadata']);
this.litcal = litcal;
this.settings = settings;
this.metadata = metadata;
return new Proxy( this, {
return new Proxy(this, {
get: (target, prop) => {
if ( allowedProps.has( prop ) ) {
return Reflect.get(target, prop);
} else {
throw new Error( `Cannot access invalid property "${prop}".` );
// Allow JSON.stringify
if (prop === 'toJSON') {
return () => ({
litcal: this.litcal,
settings: this.settings,
metadata: this.metadata
});
}
},

set( target, prop, value ) {
if ( allowedProps.has( prop ) ) {
//TODO: Add validations
return Reflect.set(target, prop, value);
} else {
throw new Error( `Cannot add new property "${prop}".` );
}
}
} );
}
}

/**
* @typedef DiocesanCalendarDELETEPayload
* @prop {string} diocese
* @prop {string} nation
*/

class DiocesanCalendarDELETEPayload {
/**
* Create a new DiocesanCalendarDELETEPaylod.
* @param {string} diocese - Diocese code.
* @param {string} nation - Nation code.
* @returns {DiocesanCalendarDELETEPayload} A new instance of DiocesanCalendarDELETEPayload.
*/
constructor( diocese, nation ) {
const allowedProps = new Set(['diocese', 'nation']);
this.diocese = diocese;
this.nation = nation;
return new Proxy( this, {
get: (target, prop) => {
if ( allowedProps.has( prop ) || (prop === 'toJSON' && typeof target[prop] === 'function') ) {
return Reflect.get(target, prop);
} else {
throw new Error( `Cannot access invalid property "${prop}".` );
}
throw new Error( `Cannot access invalid property "${prop}".` );
},

set( target, prop, value ) {
if ( allowedProps.has( prop ) ) {
//TODO: Add validation for diocese and nation
// Theoretically we could add validations here against calendars metadata
// But that would probably be more feasible with a dedicated metadata class...
return Reflect.set(target, prop, value);
} else {
throw new Error( `Cannot add new property "${prop}".` );
}
throw new Error( `Cannot add new property "${prop}".` );
}
} );
});
}
}

export {
DiocesanCalendarPayload,
DiocesanCalendarDELETEPayload
DiocesanCalendarPayload
}
76 changes: 48 additions & 28 deletions assets/js/FormControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ class FormControls {

if (FormControls.settings.monthField) {
formRow += `<div class="form-group col-sm-2">
<label for="onTheFly${FormControls.uniqid}Month"><span class="month-label">${Messages[ "Month" ]}</span><div class="form-check form-check-inline form-switch ms-2 ps-5 border border-secondary bg-light" title="switch on for mobile celebration as opposed to fixed date">
<label class="form-check-label me-1" for="onTheFly${FormControls.uniqid}StrtotimeSwitch">Mobile</label>
<label for="onTheFly${FormControls.uniqid}Month" class="d-flex justify-content-between align-items-end"><span class="month-label">${Messages[ "Month" ]}</span><div class="form-check form-check-inline form-switch me-0 ps-5 pe-2 border border-2 border-secondary rounded bg-light" title="switch on for mobile celebration as opposed to fixed date">
<label class="form-check-label" for="onTheFly${FormControls.uniqid}StrtotimeSwitch">Mobile</label>
<input class="form-check-input litEvent litEventStrtotimeSwitch" type="checkbox" data-bs-toggle="toggle" data-bs-size="xs" data-bs-onstyle="info" data-bs-offstyle="dark" role="switch" id="onTheFly${FormControls.uniqid}StrtotimeSwitch">
</div></label>
<select class="form-select litEvent litEventMonth" id="onTheFly${FormControls.uniqid}Month">`;
Expand All @@ -293,8 +293,8 @@ class FormControls {

if(FormControls.settings.strtotimeField) {
formRow += `<div class="form-group col-sm-3">
<label for="onTheFly${FormControls.uniqid}Strtotime"><span class="month-label">Relative date</span><div class="form-check form-check-inline form-switch ms-2 ps-5 border border-secondary bg-light" title="switch on for mobile celebration as opposed to fixed date">
<label class="form-check-label me-1" for="onTheFly${FormControls.uniqid}StrtotimeSwitch">Mobile</label>
<label for="onTheFly${FormControls.uniqid}Strtotime" class="d-flex justify-content-between align-items-end"><span class="month-label">Relative date</span><div class="form-check form-check-inline form-switch me-0 ps-5 pe-2 border border-2 border-secondary rounded bg-light" title="switch on for mobile celebration as opposed to fixed date">
<label class="form-check-label" for="onTheFly${FormControls.uniqid}StrtotimeSwitch">Mobile</label>
<input class="form-check-input litEvent litEventStrtotimeSwitch" type="checkbox" data-bs-toggle="toggle" data-bs-size="xs" data-bs-onstyle="info" data-bs-offstyle="dark" role="switch" id="onTheFly${FormControls.uniqid}StrtotimeSwitch">
</div></label>
<input type="text" class="form-control litEvent litEventStrtotime" id="onTheFly${FormControls.uniqid}Strtotime" placeholder="e.g. fourth thursday of november" title="e.g. fourth thursday of november | php strtotime syntax supported here!" />
Expand Down Expand Up @@ -403,8 +403,8 @@ class FormControls {
formRow += `<div class="row gx-2 align-items-baseline">`;

formRow += `<div class="form-group col-sm-6">`;
if(FormControls.settings.tagField === false){
formRow += `<input type="hidden" class="litEventEvent_key" id="onTheFly${FormControls.uniqid}Tag" value="${festivity !== null ? festivity.event_key : ''}" />`;
if(FormControls.settings.tagField === false) {
formRow += `<input type="hidden" class="litEventEventKey" id="onTheFly${FormControls.uniqid}Tag" value="${festivity !== null ? festivity.event_key : ''}" />`;
}
formRow += `<label for="onTheFly${FormControls.uniqid}Name">${Messages[ "Name" ]}</label>
<input type="text" class="form-control litEvent litEventName${festivity !== null && typeof festivity.name==='undefined' ? ` is-invalid` : ``}" id="onTheFly${FormControls.uniqid}Name" value="${festivity !== null ? festivity.name : ''}"${FormControls.settings.nameField === false ? ' readonly' : ''} />
Expand Down Expand Up @@ -464,7 +464,7 @@ class FormControls {
if (FormControls.settings.tagField) {
formRow += `<div class="form-group col-sm-2">
<label for="onTheFly${FormControls.uniqid}Tag">${Messages[ "Tag" ]}</label>
<input type="text" value="${festivity !== null ? festivity.event_key : ''}" class="form-control litEvent litEventTag" id="onTheFly${FormControls.uniqid}Tag" />
<input type="text" value="${festivity !== null ? festivity.event_key : ''}" class="form-control litEvent litEventEventKey" id="onTheFly${FormControls.uniqid}Tag" />
</div>`;
}

Expand Down Expand Up @@ -591,7 +591,7 @@ class FormControls {

formRow += `<div class="form-group col-sm-6">`;
if(FormControls.settings.tagField === false){
formRow += `<input type="hidden" class="litEventEvent_key" id="onTheFly${FormControls.uniqid}Tag" value="${festivity !== null ? festivity.event_key : ''}" />`;
formRow += `<input type="hidden" class="litEventEventKey" id="onTheFly${FormControls.uniqid}Tag" value="${festivity !== null ? festivity.event_key : ''}" />`;
}
formRow += `<label for="onTheFly${FormControls.uniqid}Name">${Messages[ "Name" ]}</label>
<input type="text" class="form-control litEvent litEventName${festivity !== null && typeof festivity.name==='undefined' ? ` is-invalid` : ``}" id="onTheFly${FormControls.uniqid}Name" value="${festivity !== null ? festivity.name : ''}"${FormControls.settings.nameField === false ? ' readonly' : ''} />
Expand Down Expand Up @@ -661,7 +661,7 @@ class FormControls {
if (FormControls.settings.tagField) {
formRow += `<div class="form-group col-sm-2">
<label for="onTheFly${FormControls.uniqid}Tag">${Messages[ "Tag" ]}</label>
<input type="text" value="${festivity !== null ? festivity.event_key : ''}" class="form-control litEvent litEventTag" id="onTheFly${FormControls.uniqid}Tag" />
<input type="text" value="${festivity !== null ? festivity.event_key : ''}" class="form-control litEvent litEventEventKey" id="onTheFly${FormControls.uniqid}Tag" />
</div>`;
}

Expand Down Expand Up @@ -877,42 +877,62 @@ class LitEvent {

/**
* Configures the multiselect for the liturgical common field of a festivity / liturgical event row.
* @param {jQuery} $row - The jQuery object of the row to configure the multiselect for. If null, the function will configure all rows.
* @param {Array<string>} common - The values to select in the multiselect. If null, the function will select all values.
* @param {?HTMLElement} row - The HTMLElement representing the row to configure the multiselect for. If null, the function will configure all rows.
* @param {?Array<string>} common - The values to select in the multiselect. If null, the function will select all values.
*/
const setCommonMultiselect = ($row=null,common=null) => {
let $litEventCommon;
if( $row !== null ) {
$litEventCommon = $row.find('.litEventCommon');
const setCommonMultiselect = (row=null, common=null) => {
let litEventCommon;
if( row !== null ) {
litEventCommon = row.querySelector('.litEventCommon');
} else {
$litEventCommon = $('.litEventCommon');
litEventCommon = document.querySelectorAll('.litEventCommon');
}
$litEventCommon.multiselect({
$(litEventCommon).multiselect({
buttonWidth: '100%',
buttonClass: 'form-select',
templates: {
button: '<button type="button" class="multiselect dropdown-toggle" data-bs-toggle="dropdown"><span class="multiselect-selected-text"></span></button>'
},
maxHeight: 200,
enableCaseInsensitiveFiltering: true,
/**
* Triggered when the selected values of the multiselect for the liturgical common field change.
* @param {HTMLOptionElement} option - The option that was selected or deselected.
* @param {boolean} checked - Whether the option was selected or deselected.
* @fires CustomEvent#change
*/
onChange: (option, checked) => {
if (($(option).val() !== 'Proper' && checked === true && $(option).parent().val().includes('Proper')) || checked === false ) {
$(option).parent().multiselect('deselect', 'Proper');
$row = $(option).closest('.row');
if( $row.find('.litEventReadings').length ) {
$row.find('.litEventReadings').prop('disabled',true);
const selectEl = option[0].parentElement;
const selectedOptions = Array.from(selectEl.selectedOptions).map(({value}) => value);
console.log('setCommonMultiselect: litEventCommon has changed, new value is: ', selectedOptions);
if (option[0].value !== 'Proper' && checked === true && selectedOptions.includes('Proper')) {
console.log('setCommonMultiselect: option[0].value:', option[0].value, 'checked:', checked, 'selectedOptions.includes(\'Proper\'):', selectedOptions.includes('Proper'));
console.log('setCommonMultiselect: deselecting Proper');
$(selectEl).multiselect('deselect', 'Proper');
row = option[0].closest('.row');
const litEventReadingsEl = row.querySelector('.litEventReadings');
if( litEventReadingsEl ) {
litEventReadingsEl.disabled = true;
}
} else if ($(option).val() === 'Proper' && checked === true) {
$(option).parent().multiselect('deselectAll', false).multiselect('select', 'Proper');
$row = $(option).closest('.row');
if( $row.find('.litEventReadings').length ) {
$row.find('.litEventReadings').prop('disabled',false);
} else if (option[0].value === 'Proper' && checked === true) {
console.log('setCommonMultiselect: option[0].value:', option[0].value, 'checked:', checked);
console.log('setCommonMultiselect: selecting Proper');
$(selectEl).multiselect('deselectAll', false).multiselect('select', 'Proper');
row = option[0].closest('.row');
const litEventReadingsEl = row.querySelector('.litEventReadings');
if( litEventReadingsEl ) {
litEventReadingsEl.disabled = false;
}
}
selectEl.dispatchEvent(new CustomEvent('change', {
bubbles: true,
cancelable: true
}));
}
}).multiselect('deselectAll', false);

if( common !== null ) {
$litEventCommon.multiselect('select', common);
$(litEventCommon).multiselect('select', common);
}
}

Expand Down
5 changes: 2 additions & 3 deletions assets/js/Payload.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { NationalCalendarPayload } from "./NationalCalendarPayload.js";
import { DiocesanCalendarPayload, DiocesanCalendarDELETEPayload } from "./DiocesanCalendarPayload.js";
import { DiocesanCalendarPayload } from "./DiocesanCalendarPayload.js";
import { WiderRegionPayload } from "./WiderRegionPayload.js";

export {
WiderRegionPayload,
NationalCalendarPayload,
DiocesanCalendarPayload,
DiocesanCalendarDELETEPayload
DiocesanCalendarPayload
}
Loading

0 comments on commit 96b685e

Please sign in to comment.