Einfügen Icons + Anpassung Styling Radio-Buttons und Foto-Buttons bei Eventerstellung
This commit is contained in:
parent
ee1c78f5de
commit
4bd4f8046d
@ -229,6 +229,24 @@ textarea:focus {
|
|||||||
transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
|
transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.option-card--with-icon {
|
||||||
|
justify-items: center;
|
||||||
|
align-content: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
color: var(--brown);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-card__icon {
|
||||||
|
color: var(--brown);
|
||||||
|
font-size: 1.35rem;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-card--with-icon span {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.option-card:hover {
|
.option-card:hover {
|
||||||
background: var(--olive-light);
|
background: var(--olive-light);
|
||||||
@ -236,6 +254,41 @@ textarea:focus {
|
|||||||
transform: translateY(-3px);
|
transform: translateY(-3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.option-grid--tomato-choices .option-card:hover,
|
||||||
|
.option-grid--tomato-choices .option-card:has(input:focus-visible) {
|
||||||
|
border-color: var(--tomato);
|
||||||
|
background: var(--tomato);
|
||||||
|
color: var(--butter-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-grid--tomato-choices .option-card:has(input:checked) {
|
||||||
|
border-color: var(--tomato);
|
||||||
|
background: var(--tomato);
|
||||||
|
color: var(--butter-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:hover .option-card__icon,
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:has(input:focus-visible) .option-card__icon,
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:has(input:checked) .option-card__icon {
|
||||||
|
color: var(--butter-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:has(input:disabled) {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:has(input:disabled):hover {
|
||||||
|
border-color: var(--olive-light);
|
||||||
|
background: var(--butter-light);
|
||||||
|
color: var(--brown);
|
||||||
|
box-shadow: none;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-grid--icon-choices .option-card--with-icon:has(input:disabled):hover .option-card__icon {
|
||||||
|
color: var(--brown);
|
||||||
|
}
|
||||||
|
|
||||||
.option-card input {
|
.option-card input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@ -253,14 +306,37 @@ textarea:focus {
|
|||||||
box-shadow: 0 0 0 2px rgba(212, 75, 36, 0.14);
|
box-shadow: 0 0 0 2px rgba(212, 75, 36, 0.14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.guest-count-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
color: var(--brown);
|
||||||
|
font-size: 3rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-count-icon::before {
|
||||||
|
display: block;
|
||||||
|
transform: translateX(1.1rem);
|
||||||
|
}
|
||||||
|
|
||||||
.counter {
|
.counter {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-16);
|
gap: var(--space-16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.counter input {
|
.counter-value-group {
|
||||||
|
display: grid;
|
||||||
|
justify-items: stretch;
|
||||||
|
row-gap: var(--space-1);
|
||||||
width: 6rem;
|
width: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter input {
|
||||||
|
width: 100%;
|
||||||
|
height: 3rem;
|
||||||
|
padding-block: 0.75rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +403,20 @@ textarea:focus {
|
|||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.review-gallery {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-gallery__thumb {
|
||||||
|
width: 4.5rem;
|
||||||
|
height: 4.5rem;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
object-fit: cover;
|
||||||
|
box-shadow: var(--shadow-interaction);
|
||||||
|
}
|
||||||
|
|
||||||
.submission-success-actions {
|
.submission-success-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@ -417,22 +507,58 @@ textarea:focus {
|
|||||||
margin-top: var(--space-2);
|
margin-top: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gallery Upload */
|
|
||||||
.gallery-upload {
|
.gallery-upload {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: var(--space-16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gallery-preview {
|
.gallery-preview {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gallery-add-button {
|
||||||
|
width: 7rem;
|
||||||
|
height: 7rem;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
align-content: center;
|
||||||
|
gap: var(--space-1);
|
||||||
|
padding: var(--space-1);
|
||||||
|
border: 1.5px solid var(--olive-light);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
background: var(--butter-light);
|
||||||
|
color: var(--olive);
|
||||||
|
font-family: var(--font-main);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-add-button__icon {
|
||||||
|
color: var(--brown);
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-add-button__text {
|
||||||
|
color: var(--black);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.15;
|
||||||
|
text-align: center;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-add-button:hover {
|
||||||
|
background: var(--olive-light);
|
||||||
|
box-shadow: var(--shadow-interaction);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
.gallery-thumb {
|
.gallery-thumb {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 5.5rem;
|
width: 7rem;
|
||||||
height: 5.5rem;
|
height: 7rem;
|
||||||
border-radius: var(--radius-sm, 0.5rem);
|
border-radius: var(--radius-sm, 0.5rem);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|||||||
@ -80,24 +80,28 @@
|
|||||||
<fieldset class="form-field">
|
<fieldset class="form-field">
|
||||||
<label>Art des Essens / Eventtyp</label>
|
<label>Art des Essens / Eventtyp</label>
|
||||||
|
|
||||||
<div class="option-grid option-grid--4">
|
<div class="option-grid option-grid--4 option-grid--event-type option-grid--icon-choices option-grid--tomato-choices">
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="radio" name="eventType" value="Brunch" required />
|
<input type="radio" name="eventType" value="Brunch" required />
|
||||||
|
<i class="fa-solid fa-bread-slice option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Brunch</span>
|
<span>Brunch</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="radio" name="eventType" value="Lunch" />
|
<input type="radio" name="eventType" value="Lunch" />
|
||||||
|
<i class="fa-solid fa-pizza-slice option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Lunch</span>
|
<span>Lunch</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="radio" name="eventType" value="Kaffee + Kuchen" />
|
<input type="radio" name="eventType" value="Kaffee + Kuchen" />
|
||||||
|
<i class="fa-solid fa-mug-hot option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Kaffee + Kuchen</span>
|
<span>Kaffee + Kuchen</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="radio" name="eventType" value="Dinner" />
|
<input type="radio" name="eventType" value="Dinner" />
|
||||||
|
<i class="fa-solid fa-martini-glass option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Dinner</span>
|
<span>Dinner</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -115,15 +119,18 @@
|
|||||||
>
|
>
|
||||||
−
|
−
|
||||||
</button>
|
</button>
|
||||||
|
<div class="counter-value-group">
|
||||||
|
<i class="fa-solid fa-user-group guest-count-icon" aria-hidden="true"></i>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
id="maxGuests"
|
id="maxGuests"
|
||||||
name="maxGuests"
|
name="maxGuests"
|
||||||
min="1"
|
min="1"
|
||||||
step="1"
|
step="1"
|
||||||
value="4"
|
value="0"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="counter-button"
|
class="counter-button"
|
||||||
@ -152,24 +159,28 @@
|
|||||||
<fieldset class="form-field">
|
<fieldset class="form-field">
|
||||||
<label>Ernährungsform</label>
|
<label>Ernährungsform</label>
|
||||||
|
|
||||||
<div class="option-grid option-grid--4">
|
<div class="option-grid option-grid--4 option-grid--icon-choices option-grid--tomato-choices">
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="checkbox" name="dietType" value="Fleisch" />
|
<input type="checkbox" name="dietType" value="Fleisch" />
|
||||||
|
<i class="fa-solid fa-drumstick-bite option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Fleisch</span>
|
<span>Fleisch</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="checkbox" name="dietType" value="Fisch" />
|
<input type="checkbox" name="dietType" value="Fisch" />
|
||||||
|
<i class="fa-solid fa-fish option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Fisch</span>
|
<span>Fisch</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="checkbox" name="dietType" value="Vegetarisch" />
|
<input type="checkbox" name="dietType" value="Vegetarisch" />
|
||||||
|
<i class="fa-solid fa-seedling option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Vegetarisch</span>
|
<span>Vegetarisch</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="option-card option">
|
<label class="option-card option option-card--with-icon">
|
||||||
<input type="checkbox" name="dietType" value="Vegan" />
|
<input type="checkbox" name="dietType" value="Vegan" />
|
||||||
|
<i class="fa-solid fa-leaf option-card__icon" aria-hidden="true"></i>
|
||||||
<span>Vegan</span>
|
<span>Vegan</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -198,7 +209,7 @@
|
|||||||
<label>Allergene / Unverträglichkeiten</label>
|
<label>Allergene / Unverträglichkeiten</label>
|
||||||
<p class="field-hint">Optional – nur auswählen, wenn es für dein Event relevant ist.</p>
|
<p class="field-hint">Optional – nur auswählen, wenn es für dein Event relevant ist.</p>
|
||||||
|
|
||||||
<div class="option-grid option-grid--3">
|
<div class="option-grid option-grid--3 option-grid--tomato-choices">
|
||||||
<label class="option-card option">
|
<label class="option-card option">
|
||||||
<input type="checkbox" name="allergies" value="glutenfrei" />
|
<input type="checkbox" name="allergies" value="glutenfrei" />
|
||||||
<span>Glutenfrei</span>
|
<span>Glutenfrei</span>
|
||||||
@ -243,7 +254,7 @@
|
|||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label for="eventTime">Uhrzeit</label>
|
<label for="eventTime">Uhrzeit</label>
|
||||||
<input type="time" id="eventTime" name="eventTime" value="00:00" required />
|
<input type="time" id="eventTime" name="eventTime" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -297,10 +308,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>Fotos hinzufügen <span class="field-hint-inline">(optional)</span></label>
|
<label>Wie wird dein Event aussehen? <span class="field-hint-inline">(optional)</span></label>
|
||||||
<div class="gallery-upload">
|
<div class="gallery-upload">
|
||||||
<div class="gallery-preview" id="galleryPreview"></div>
|
<div class="gallery-preview" id="galleryPreview"></div>
|
||||||
<button type="button" class="button-primary" id="galleryAddBtn" aria-label="Foto hinzufügen">Foto hinzufügen</button>
|
<button type="button" class="gallery-add-button" id="galleryAddBtn" aria-label="Foto hinzufügen">
|
||||||
|
<i class="fa-solid fa-plus gallery-add-button__icon" aria-hidden="true"></i>
|
||||||
|
<span class="gallery-add-button__text">Foto<br>hinzufügen</span>
|
||||||
|
</button>
|
||||||
<input type="file" id="galleryFileInput" accept="image/*" multiple hidden />
|
<input type="file" id="galleryFileInput" accept="image/*" multiple hidden />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -375,6 +389,15 @@
|
|||||||
<dt>Event-Abend</dt>
|
<dt>Event-Abend</dt>
|
||||||
<dd data-review="eventDescription">–</dd>
|
<dd data-review="eventDescription">–</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="review-item" data-edit-step="6" data-edit-field="galleryAddBtn" role="button" tabindex="0" aria-label="Fotos bearbeiten">
|
||||||
|
<dt>Fotos</dt>
|
||||||
|
<dd>
|
||||||
|
<div class="review-gallery" data-review-gallery>
|
||||||
|
<span>Keine Fotos hinzugefügt</span>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -270,6 +270,29 @@ function updateReviewField(fieldName, value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeigt hochgeladene Fotos als kleine Vorschaubilder in der Review.
|
||||||
|
*/
|
||||||
|
function updateReviewGallery() {
|
||||||
|
const target = document.querySelector("[data-review-gallery]");
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
target.innerHTML = "";
|
||||||
|
|
||||||
|
if (galleryImages.length === 0) {
|
||||||
|
target.textContent = "Keine Fotos hinzugefügt";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryImages.forEach((src, index) => {
|
||||||
|
const image = document.createElement("img");
|
||||||
|
image.className = "review-gallery__thumb";
|
||||||
|
image.src = src;
|
||||||
|
image.alt = `Foto ${index + 1}`;
|
||||||
|
target.appendChild(image);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Baut den Text für Allergien / Hinweise zusammen.
|
* Baut den Text für Allergien / Hinweise zusammen.
|
||||||
* Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert.
|
* Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert.
|
||||||
@ -297,6 +320,8 @@ function updateReview() {
|
|||||||
Object.entries(reviewValues).forEach(([key, value]) => {
|
Object.entries(reviewValues).forEach(([key, value]) => {
|
||||||
updateReviewField(key, value);
|
updateReviewField(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateReviewGallery();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -539,6 +564,52 @@ function validateDietType() {
|
|||||||
return { isValid: true };
|
return { isValid: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verhindert widersprüchliche Ernährungsformen:
|
||||||
|
* Fleisch/Fisch dürfen zusammen, schliessen aber vegetarisch/vegan aus.
|
||||||
|
*/
|
||||||
|
function registerDietConflictHandlers() {
|
||||||
|
const dietOptions = Array.from(form.querySelectorAll('input[name="dietType"]'));
|
||||||
|
const meatFishOptions = dietOptions.filter(input => ["Fleisch", "Fisch"].includes(input.value));
|
||||||
|
const plantOptions = dietOptions.filter(input => ["Vegetarisch", "Vegan"].includes(input.value));
|
||||||
|
|
||||||
|
const updateDietAvailability = changedInput => {
|
||||||
|
if (changedInput?.checked && changedInput.value === "Vegetarisch") {
|
||||||
|
dietOptions.forEach(input => {
|
||||||
|
if (input.value === "Vegan") input.checked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedInput?.checked && changedInput.value === "Vegan") {
|
||||||
|
dietOptions.forEach(input => {
|
||||||
|
if (input.value === "Vegetarisch") input.checked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasMeatOrFish = meatFishOptions.some(input => input.checked);
|
||||||
|
const selectedPlantDiet = plantOptions.find(input => input.checked);
|
||||||
|
|
||||||
|
meatFishOptions.forEach(input => {
|
||||||
|
input.disabled = Boolean(selectedPlantDiet);
|
||||||
|
});
|
||||||
|
|
||||||
|
plantOptions.forEach(input => {
|
||||||
|
input.disabled = hasMeatOrFish || Boolean(selectedPlantDiet && input !== selectedPlantDiet);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
dietOptions.forEach(input => {
|
||||||
|
input.addEventListener("change", () => {
|
||||||
|
dietOptions.forEach(option => {
|
||||||
|
option.closest(".option-card")?.classList.remove("option-card--invalid");
|
||||||
|
});
|
||||||
|
updateDietAvailability(input);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
updateDietAvailability();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prüft alle Pflichtfelder ausser Radios und Checkboxen.
|
* Prüft alle Pflichtfelder ausser Radios und Checkboxen.
|
||||||
* Rückgabe:
|
* Rückgabe:
|
||||||
@ -648,11 +719,17 @@ function registerCounterHandlers() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Erhöht oder verringert den Wert eines Zahlenfelds.
|
* Erhöht oder verringert den Wert eines Zahlenfelds.
|
||||||
* Der Wert darf dabei nie kleiner als das definierte Minimum werden.
|
* 0 bleibt als bewusster Startwert erlaubt; gültig ist erst eine Auswahl ab min.
|
||||||
*/
|
*/
|
||||||
function updateCounterValue(input, change) {
|
function updateCounterValue(input, change) {
|
||||||
const min = Number(input.min || 1);
|
const min = Number(input.min || 1);
|
||||||
const currentValue = Number(input.value || min);
|
const currentValue = Number(input.value || 0);
|
||||||
|
|
||||||
|
if (currentValue < min && change < 0) {
|
||||||
|
input.value = currentValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
input.value = Math.max(min, currentValue + change);
|
input.value = Math.max(min, currentValue + change);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +842,7 @@ function registerValidationFeedbackHandlers() {
|
|||||||
* Setzt den Fokus auf ein bestimmtes Feld oder die erste Option einer Radio-Gruppe.
|
* Setzt den Fokus auf ein bestimmtes Feld oder die erste Option einer Radio-Gruppe.
|
||||||
*/
|
*/
|
||||||
function focusFieldByName(fieldName) {
|
function focusFieldByName(fieldName) {
|
||||||
const field = form.elements[fieldName];
|
const field = form.elements[fieldName] || document.getElementById(fieldName);
|
||||||
|
|
||||||
if (!field) return;
|
if (!field) return;
|
||||||
|
|
||||||
@ -862,6 +939,7 @@ function initEventCreationFlow() {
|
|||||||
|
|
||||||
// Counter aktivieren
|
// Counter aktivieren
|
||||||
registerCounterHandlers();
|
registerCounterHandlers();
|
||||||
|
registerDietConflictHandlers();
|
||||||
registerMenuBulletHandler();
|
registerMenuBulletHandler();
|
||||||
registerValidationFeedbackHandlers();
|
registerValidationFeedbackHandlers();
|
||||||
registerReviewEditHandlers();
|
registerReviewEditHandlers();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user