From 2d77d8eccf4029ea76f8d0f61ba2c4aef93f5b31 Mon Sep 17 00:00:00 2001 From: Martin Renvoize <martin.renvoize@ptfs-europe.com> Date: Mon, 9 Sep 2024 17:00:51 +0100 Subject: [PATCH] Bug 10190: Add custom input for delay This custom input allows for dynamic min/max rules and it updates the input styling to match other inputs on the page including a 'clear' button. Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk> Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk> --- .../CirculationTriggersFormAdd.vue | 224 ++++++++++++++++-- .../CirculationTriggers/TriggersTable.vue | 60 +++-- 2 files changed, 247 insertions(+), 37 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue index ff46803dc4a..5edae92fbdf 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue @@ -106,13 +106,54 @@ <label for="overdue_delay" >{{ $__("Delay") }}: </label> - <input - id="overdue_delay" - v-model="newRule.delay" - type="number" - :placeholder="fallbackRule.delay" - :min="minDelay" - /> + <div class="numeric-input-wrapper"> + <div class="input-with-clear"> + <input + id="overdue_delay" + v-model="newRule.delay" + type="number" + :placeholder="fallbackRule.delay" + :min="minDelay" + :max="maxDelay" + class="numeric-input" + /> + <button + v-if=" + newRule.delay !== null && + newRule.delay !== undefined + " + type="button" + class="clear-btn" + @click="newRule.delay = null" + > + <svg + xmlns="http://www.w3.org/2000/svg" + width="10" + height="10" + > + <path + d="M6.895455 5l2.842897-2.842898c.348864-.348863.348864-.914488 0-1.263636L9.106534.261648c-.348864-.348864-.914489-.348864-1.263636 0L5 3.104545 2.157102.261648c-.348863-.348864-.914488-.348864-1.263636 0L.261648.893466c-.348864.348864-.348864.914489 0 1.263636L3.104545 5 .261648 7.842898c-.348864.348863-.348864.914488 0 1.263636l.631818.631818c.348864.348864.914773.348864 1.263636 0L5 6.895455l2.842898 2.842897c.348863.348864.914772.348864 1.263636 0l.631818-.631818c.348864-.348864.348864-.914489 0-1.263636L6.895455 5z" + ></path> + </svg> + </button> + <div class="chevron-buttons"> + <button + type="button" + class="increment-btn" + @click="incrementDelay" + > + ▴ + </button> + <button + type="button" + class="decrement-btn" + @click="decrementDelay" + > + ▾ + </button> + </div> + </div> + </div> </li> <li> <label for="letter_code" @@ -131,11 +172,14 @@ v-bind="attributes" v-on="events" :placeholder=" - letters.find( - letter => - letter.code === - fallbackRule.notice - )?.name || fallbackRule.notice + newRule.notice === null || + newRule.notice === undefined + ? letters.find( + letter => + letter.code === + fallbackRule.notice + )?.name || fallbackRule.notice + : '' " /> </template> @@ -293,6 +337,8 @@ export default { editMode: false, ruleBeingEdited: null, triggerBeingEdited: null, + minDelay: 0, + maxDelay: Infinity, }; }, beforeRouteEnter(to, from, next) { @@ -311,16 +357,6 @@ export default { ); }); }, - computed: { - minDelay() { - const lastRule = this.circRules[this.newTriggerNumber - 2]; - return lastRule - ? parseInt( - lastRule[`overdue_${this.newTriggerNumber - 1}_delay`] - ) + 1 - : 0; - }, - }, methods: { async addCircRule(e) { e.preventDefault(); @@ -468,6 +504,9 @@ export default { lengthunit: rules[0].lengthunit, numberOfTriggers: numberOfTriggers, }; + + this.setMinDelay(); + this.setMaxDelay(); }, error => {} ); @@ -627,6 +666,55 @@ export default { ), }; }, + setMinDelay() { + const priorTriggerNumber = parseInt(this.newTriggerNumber) - 1; + this.minDelay = this.ruleBeingEdited[ + `overdue_${priorTriggerNumber}_delay` + ] + ? parseInt( + this.ruleBeingEdited[ + `overdue_${priorTriggerNumber}_delay` + ] + ) + 1 + : 0; + }, + setMaxDelay() { + const nextTriggerNumber = parseInt(this.newTriggerNumber) + 1; + this.maxDelay = this.ruleBeingEdited[ + `overdue_${nextTriggerNumber}_delay` + ] + ? parseInt( + this.ruleBeingEdited[`overdue_${nextTriggerNumber}_delay`] + ) - 1 + : Infinity; + }, + incrementDelay() { + // Check for minDelay and maxDelay + const min = this.minDelay !== undefined ? this.minDelay : 1; + const max = this.maxDelay !== undefined ? this.maxDelay : Infinity; + + // Set to minDelay if it's null or undefined + if ( + this.newRule.delay === undefined || + this.newRule.delay === null + ) { + this.newRule.delay = min; + } + + // Increment within the valid range + else { + this.newRule["delay"] = Math.min(this.newRule.delay + 1, max); + } + }, + decrementDelay() { + // Check for minDelay + const min = this.minDelay !== undefined ? this.minDelay : 1; + + // Decrement only if greater than minDelay + if (this.newRule.delay > min) { + this.newRule.delay--; + } + }, }, watch: { $route: { @@ -659,6 +747,98 @@ form li { align-items: center; } +.numeric-input-wrapper { + position: relative; + display: inline-block; + width: 30%; +} + +.input-with-clear { + position: relative; + display: flex; + align-items: center; + width: 100%; +} + +.numeric-input { + padding-right: 40px; /* Adjust to leave space for clear button */ + padding-left: 0.25em; + padding-top: 2px; + padding-bottom: 2px; + width: 100%; + border-radius: 4px; + border: 1px solid #ccc; + font-size: 16px; + box-sizing: border-box; + transition: border-color 0.2s ease; +} + +.clear-btn { + position: absolute; + right: 22px; /* Adjust positioning */ + fill: var(--vs-controls-color); + background-color: transparent; + border: 0; + font-size: 1.2em; + color: #333; + cursor: pointer; + z-index: 2; /* Ensure it is above the input */ +} + +.button:active:hover, +.clear-btn:active:hover { + background-color: #d4d4d4; + border-color: #8c8c8c; +} + +/* Chevron buttons container */ +.chevron-buttons { + display: flex; + flex-direction: column; + position: absolute; + right: 0px; + top: 0; + bottom: 0; + width: 16px; + padding: 0px 5px 0px 2px; + justify-content: center; + z-index: 2; +} + +/* Chevron button styles */ +.increment-btn, +.decrement-btn { + background-color: transparent; + border: 0px solid #ccc; + font-size: 10px; + padding: 0px; + cursor: pointer; + color: rgba(60, 60, 60, 0.5); + border-radius: 2px; +} + +.increment-btn:hover, +.decrement-btn:hover { + background-color: #ddd; +} + +/* Hide the native increment/decrement buttons */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type="number"] { + -moz-appearance: textfield; /* For Firefox */ +} + +.numeric-input:focus, +.numeric-input:hover { + border-color: #007bff; /* Match focus color of v-select */ + outline: none; +} + .dialog.alert fieldset:not(.bg-danger):not(.bg-warning):not(.bg-info):not( .bg-success diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue index 02b8a16cc55..a788136544c 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/TriggersTable.vue @@ -78,14 +78,18 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_delay` + `overdue_${ + modal ? i + 1 : triggerNumber + }_delay` ).isFallback, }" > {{ findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_delay` + `overdue_${ + modal ? i + 1 : triggerNumber + }_delay` ).value + " " + $__("days") @@ -99,7 +103,9 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_notice` + `overdue_${ + modal ? i + 1 : triggerNumber + }_notice` ).isFallback, }" > @@ -107,7 +113,9 @@ handleNotice( findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_notice` + `overdue_${ + modal ? i + 1 : triggerNumber + }_notice` ).value ) }} @@ -120,19 +128,25 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).isFallback, }" > {{ findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_notice` + `overdue_${ + modal ? i + 1 : triggerNumber + }_notice` ).value !== "" ? handleTransport( findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).value, "email" ) @@ -147,19 +161,25 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).isFallback, }" > {{ findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_notice` + `overdue_${ + modal ? i + 1 : triggerNumber + }_notice` ).value !== "" ? handleTransport( findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).value, "print" ) @@ -174,19 +194,25 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).isFallback, }" > {{ findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_notice` + `overdue_${ + modal ? i + 1 : triggerNumber + }_notice` ).value !== "" ? handleTransport( findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_mtt` + `overdue_${ + modal ? i + 1 : triggerNumber + }_mtt` ).value, "sms" ) @@ -201,7 +227,9 @@ :class="{ fallback: findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_restrict` + `overdue_${ + modal ? i + 1 : triggerNumber + }_restrict` ).isFallback, }" > @@ -209,7 +237,9 @@ handleRestrictions( findEffectiveRule( rule, - `overdue_${modal ? i + 1 : triggerNumber}_restrict` + `overdue_${ + modal ? i + 1 : triggerNumber + }_restrict` ).value ) }} -- 2.48.1