From 4b681fd3228b768da138ddc002dd5d4700febea2 Mon Sep 17 00:00:00 2001 From: Andreas Fernandez <a.fernandez@scripting-base.de> Date: Fri, 17 Apr 2020 16:42:34 +0200 Subject: [PATCH] [BUGFIX] Reset click events in buttons of MultiStepWizard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the MultiStepWizard is used with additional click events bound to the next or prev button, those event got stacked as the buttons don't change per step. To fix this issue, all click events are removed after switching a step and the original click event to switch the step is bound again. Furthermore the 'savePath' for duplication of a form is now correctly set if there is only one folder available and therefore no select element present in the modal. Resolves: #91094 Releases: master Change-Id: Ic95d2222441c8e1e8cf9fb46e5e7437d4e4ed85e Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64214 Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Christian Eßl <indy.essl@gmail.com> Reviewed-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Christian Eßl <indy.essl@gmail.com> --- .../Public/TypeScript/MultiStepWizard.ts | 33 ++++++++++++------- .../Public/JavaScript/MultiStepWizard.js | 2 +- .../Backend/FormManager/ViewModel.js | 3 +- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/MultiStepWizard.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/MultiStepWizard.ts index 474975afa1d7..7b337868ca24 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/MultiStepWizard.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/MultiStepWizard.ts @@ -258,17 +258,8 @@ class MultiStepWizard { */ private initializeEvents(): void { let $modal = this.setup.$carousel.closest('.modal'); - let $modalFooter = $modal.find('.modal-footer'); - let $nextButton = $modalFooter.find('button[name="next"]'); - let $prevButton = $modalFooter.find('button[name="prev"]'); - - $nextButton.on('click', (): void => { - this.setup.$carousel.carousel('next'); - }); - - $prevButton.on('click', (): void => { - this.setup.$carousel.carousel('prev'); - }); + this.initializeSlideNextEvent($modal); + this.initializeSlidePrevEvent($modal); // Event fires when the slide transition is invoked this.setup.$carousel.on('slide.bs.carousel', (evt: any): void => { @@ -301,6 +292,22 @@ class MultiStepWizard { }); } + private initializeSlideNextEvent($modal: JQuery) { + let $modalFooter = $modal.find('.modal-footer'); + let $nextButton = $modalFooter.find('button[name="next"]'); + $nextButton.off().on('click', (): void => { + this.setup.$carousel.carousel('next'); + }); + } + + private initializeSlidePrevEvent($modal: JQuery) { + let $modalFooter = $modal.find('.modal-footer'); + let $prevButton = $modalFooter.find('button[name="prev"]'); + $prevButton.off().on('click', (): void => { + this.setup.$carousel.carousel('prev'); + }); + } + /** * All changes after applying the next-button * @@ -308,6 +315,8 @@ class MultiStepWizard { * @private */ private nextSlideChanges($modal: JQuery): void { + this.initializeSlideNextEvent($modal); + let $modalTitle = $modal.find('.modal-title'); let $modalFooter = $modal.find('.modal-footer'); let $modalButtonGroup = $modal.find('.modal-btn-group'); @@ -361,6 +370,8 @@ class MultiStepWizard { * @private */ private prevSlideChanges($modal: JQuery): void { + this.initializeSlidePrevEvent($modal); + let $modalTitle = $modal.find('.modal-title'); let $modalFooter = $modal.find('.modal-footer'); let $modalButtonGroup = $modal.find('.modal-btn-group'); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/MultiStepWizard.js b/typo3/sysext/backend/Resources/Public/JavaScript/MultiStepWizard.js index 79bf63ba89f4..91365918d750 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/MultiStepWizard.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/MultiStepWizard.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -define(["require","exports","./Enum/Severity","jquery","./Modal","./Severity","./Icons"],(function(t,e,s,i,r,a,l){"use strict";class n{constructor(){this.setup={slides:[],settings:{},forceSelection:!0,$carousel:null},this.originalSetup=i.extend(!0,{},this.setup)}set(t,e){return this.setup.settings[t]=e,this}addSlide(t,e,i="",r=s.SeverityEnum.info,a,l){const n={identifier:t,title:e,content:i,severity:r,progressBarTitle:a,callback:l};return this.setup.slides.push(n),this}addFinalProcessingSlide(t){return t||(t=()=>{this.dismiss()}),l.getIcon("spinner-circle",l.sizes.default,null,null).then(e=>{let s=i("<div />",{class:"text-center"}).append(e);this.addSlide("final-processing-slide",top.TYPO3.lang["wizard.processing.title"],s[0].outerHTML,a.info,null,t)})}show(){let t=this.generateSlides(),e=this.setup.slides[0];r.confirm(e.title,t,e.severity,[{text:top.TYPO3.lang["wizard.button.cancel"],active:!0,btnClass:"btn-default pull-left",name:"cancel",trigger:()=>{this.getComponent().trigger("wizard-dismiss")}},{text:top.TYPO3.lang["wizard.button.prev"],btnClass:"btn-"+a.getCssClass(e.severity),name:"prev"},{text:top.TYPO3.lang["wizard.button.next"],btnClass:"btn-"+a.getCssClass(e.severity),name:"next"}],["modal-multi-step-wizard"]),this.addButtonContainer(),this.addProgressBar(),this.initializeEvents(),this.getComponent().on("wizard-visible",()=>{this.runSlideCallback(e,this.setup.$carousel.find(".item").first())}).on("wizard-dismissed",()=>{this.setup=i.extend(!0,{},this.originalSetup)})}getComponent(){return null===this.setup.$carousel&&this.generateSlides(),this.setup.$carousel}dismiss(){r.dismiss()}lockNextStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="next"]');return t.prop("disabled",!0),t}unlockNextStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="next"]');return t.prop("disabled",!1),t}lockPrevStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="prev"]');return t.prop("disabled",!0),t}unlockPrevStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="prev"]');return t.prop("disabled",!1),t}triggerStepButton(t){let e=this.setup.$carousel.closest(".modal").find('button[name="'+t+'"]');return e.length>0&&!0!==e.prop("disabled")&&e.trigger("click"),e}blurCancelStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="cancel"]');return t.blur(),t}initializeEvents(){let t=this.setup.$carousel.closest(".modal"),e=t.find(".modal-footer"),s=e.find('button[name="next"]'),a=e.find('button[name="prev"]');s.on("click",()=>{this.setup.$carousel.carousel("next")}),a.on("click",()=>{this.setup.$carousel.carousel("prev")}),this.setup.$carousel.on("slide.bs.carousel",e=>{"left"===e.direction?this.nextSlideChanges(t):this.prevSlideChanges(t)}).on("slid.bs.carousel",t=>{let e=this.setup.$carousel.data("currentIndex"),s=this.setup.slides[e];this.runSlideCallback(s,i(t.relatedTarget)),this.setup.forceSelection&&this.lockNextStep()});let l=this.getComponent();l.on("wizard-dismiss",this.dismiss),r.currentModal.on("hidden.bs.modal",()=>{l.trigger("wizard-dismissed")}).on("shown.bs.modal",()=>{l.trigger("wizard-visible")})}nextSlideChanges(t){let e=t.find(".modal-title"),s=t.find(".modal-footer"),i=t.find(".modal-btn-group"),r=s.find('button[name="next"]'),l=this.setup.$carousel.data("currentSlide")+1,n=this.setup.$carousel.data("currentIndex")+1;e.text(this.setup.slides[n].title),this.setup.$carousel.data("currentSlide",l),this.setup.$carousel.data("currentIndex",n),l>=this.setup.$carousel.data("realSlideCount")?(r.text(this.getProgressBarTitle(this.setup.$carousel.data("currentIndex"))),s.find(".progress-bar.first-step").width("100%").text(this.getProgressBarTitle(this.setup.$carousel.data("currentIndex"))),s.find(".progress-bar.last-step").width("0%").text(""),this.setup.forceSelection=!1):(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*l+"%").text(this.getProgressBarTitle(n)),s.find(".progress-bar.step").width("0%").text(""),i.slideDown()),r.removeClass("btn-"+a.getCssClass(this.setup.slides[n-1].severity)).addClass("btn-"+a.getCssClass(this.setup.slides[n].severity)),t.removeClass("modal-severity-"+a.getCssClass(this.setup.slides[n-1].severity)).addClass("modal-severity-"+a.getCssClass(this.setup.slides[n].severity))}prevSlideChanges(t){let e=t.find(".modal-title"),s=t.find(".modal-footer"),i=t.find(".modal-btn-group"),r=s.find('button[name="next"]'),a=this.setup.$carousel.data("currentSlide")-1,l=this.setup.$carousel.data("currentIndex")-1;this.setup.$carousel.data("currentSlide",a),this.setup.$carousel.data("currentIndex",l),e.text(this.setup.slides[l].title),s.find(".progress-bar.last-step").width(this.setup.$carousel.data("initialStep")+"%").text(this.getProgressBarTitle(this.setup.$carousel.data("slideCount")-1)),r.text(top.TYPO3.lang["wizard.button.next"]),1===a?(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*a+"%").text(this.getProgressBarTitle(0)),s.find(".progress-bar.step").width(this.setup.$carousel.data("initialStep")+"%").text(this.getProgressBarTitle(l+1)),i.slideUp()):(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*a+"%").text(this.getProgressBarTitle(l)),this.setup.forceSelection=!0)}getProgressBarTitle(t){let e;return e=null===this.setup.slides[t].progressBarTitle?0===t?top.TYPO3.lang["wizard.progressStep.start"]:t>=this.setup.$carousel.data("slideCount")-1?top.TYPO3.lang["wizard.progressStep.finish"]:top.TYPO3.lang["wizard.progressStep"]+String(t+1):this.setup.slides[t].progressBarTitle,e}runSlideCallback(t,e){"function"==typeof t.callback&&t.callback(e,this.setup.settings,t.identifier)}addProgressBar(){let t,e=this.setup.$carousel.find(".item").length-1,s=Math.max(1,e),r=this.setup.$carousel.closest(".modal").find(".modal-footer");if(t=Math.round(100/s),this.setup.$carousel.data("initialStep",t).data("slideCount",s).data("realSlideCount",e).data("currentIndex",0).data("currentSlide",1),s>1){r.prepend(i("<div />",{class:"progress"}));for(let e=0;e<this.setup.slides.length;++e){let s;s=0===e?"progress-bar first-step":e===this.setup.$carousel.data("slideCount")-1?"progress-bar last-step inactive":"progress-bar step inactive",r.find(".progress").append(i("<div />",{role:"progressbar",class:s,"aria-valuemin":0,"aria-valuenow":t,"aria-valuemax":100}).width(t+"%").text(this.getProgressBarTitle(e)))}}}addButtonContainer(){this.setup.$carousel.closest(".modal").find(".modal-footer .btn").wrapAll('<div class="modal-btn-group" />')}generateSlides(){if(null!==this.setup.$carousel)return this.setup.$carousel;let t='<div class="carousel slide" data-ride="carousel" data-interval="false"><div class="carousel-inner" role="listbox">';for(let e=0;e<this.setup.slides.length;++e){let s=this.setup.slides[e],i=s.content;"object"==typeof i&&(i=i.html()),t+='<div class="item" data-slide="'+s.identifier+'" data-step="'+e+'">'+i+"</div>"}return t+="</div></div>",this.setup.$carousel=i(t),this.setup.$carousel.find(".item").first().addClass("active"),this.setup.$carousel}}let o;try{window.opener&&window.opener.TYPO3&&window.opener.TYPO3.MultiStepWizard&&(o=window.opener.TYPO3.MultiStepWizard),parent&&parent.window.TYPO3&&parent.window.TYPO3.MultiStepWizard&&(o=parent.window.TYPO3.MultiStepWizard),top&&top.TYPO3&&top.TYPO3.MultiStepWizard&&(o=top.TYPO3.MultiStepWizard)}catch(t){}return o||(o=new n,"undefined"!=typeof TYPO3&&(TYPO3.MultiStepWizard=o)),o})); \ No newline at end of file +define(["require","exports","./Enum/Severity","jquery","./Modal","./Severity","./Icons"],(function(t,e,s,i,r,a,l){"use strict";class n{constructor(){this.setup={slides:[],settings:{},forceSelection:!0,$carousel:null},this.originalSetup=i.extend(!0,{},this.setup)}set(t,e){return this.setup.settings[t]=e,this}addSlide(t,e,i="",r=s.SeverityEnum.info,a,l){const n={identifier:t,title:e,content:i,severity:r,progressBarTitle:a,callback:l};return this.setup.slides.push(n),this}addFinalProcessingSlide(t){return t||(t=()=>{this.dismiss()}),l.getIcon("spinner-circle",l.sizes.default,null,null).then(e=>{let s=i("<div />",{class:"text-center"}).append(e);this.addSlide("final-processing-slide",top.TYPO3.lang["wizard.processing.title"],s[0].outerHTML,a.info,null,t)})}show(){let t=this.generateSlides(),e=this.setup.slides[0];r.confirm(e.title,t,e.severity,[{text:top.TYPO3.lang["wizard.button.cancel"],active:!0,btnClass:"btn-default pull-left",name:"cancel",trigger:()=>{this.getComponent().trigger("wizard-dismiss")}},{text:top.TYPO3.lang["wizard.button.prev"],btnClass:"btn-"+a.getCssClass(e.severity),name:"prev"},{text:top.TYPO3.lang["wizard.button.next"],btnClass:"btn-"+a.getCssClass(e.severity),name:"next"}],["modal-multi-step-wizard"]),this.addButtonContainer(),this.addProgressBar(),this.initializeEvents(),this.getComponent().on("wizard-visible",()=>{this.runSlideCallback(e,this.setup.$carousel.find(".item").first())}).on("wizard-dismissed",()=>{this.setup=i.extend(!0,{},this.originalSetup)})}getComponent(){return null===this.setup.$carousel&&this.generateSlides(),this.setup.$carousel}dismiss(){r.dismiss()}lockNextStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="next"]');return t.prop("disabled",!0),t}unlockNextStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="next"]');return t.prop("disabled",!1),t}lockPrevStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="prev"]');return t.prop("disabled",!0),t}unlockPrevStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="prev"]');return t.prop("disabled",!1),t}triggerStepButton(t){let e=this.setup.$carousel.closest(".modal").find('button[name="'+t+'"]');return e.length>0&&!0!==e.prop("disabled")&&e.trigger("click"),e}blurCancelStep(){let t=this.setup.$carousel.closest(".modal").find('button[name="cancel"]');return t.blur(),t}initializeEvents(){let t=this.setup.$carousel.closest(".modal");this.initializeSlideNextEvent(t),this.initializeSlidePrevEvent(t),this.setup.$carousel.on("slide.bs.carousel",e=>{"left"===e.direction?this.nextSlideChanges(t):this.prevSlideChanges(t)}).on("slid.bs.carousel",t=>{let e=this.setup.$carousel.data("currentIndex"),s=this.setup.slides[e];this.runSlideCallback(s,i(t.relatedTarget)),this.setup.forceSelection&&this.lockNextStep()});let e=this.getComponent();e.on("wizard-dismiss",this.dismiss),r.currentModal.on("hidden.bs.modal",()=>{e.trigger("wizard-dismissed")}).on("shown.bs.modal",()=>{e.trigger("wizard-visible")})}initializeSlideNextEvent(t){t.find(".modal-footer").find('button[name="next"]').off().on("click",()=>{this.setup.$carousel.carousel("next")})}initializeSlidePrevEvent(t){t.find(".modal-footer").find('button[name="prev"]').off().on("click",()=>{this.setup.$carousel.carousel("prev")})}nextSlideChanges(t){this.initializeSlideNextEvent(t);let e=t.find(".modal-title"),s=t.find(".modal-footer"),i=t.find(".modal-btn-group"),r=s.find('button[name="next"]'),l=this.setup.$carousel.data("currentSlide")+1,n=this.setup.$carousel.data("currentIndex")+1;e.text(this.setup.slides[n].title),this.setup.$carousel.data("currentSlide",l),this.setup.$carousel.data("currentIndex",n),l>=this.setup.$carousel.data("realSlideCount")?(r.text(this.getProgressBarTitle(this.setup.$carousel.data("currentIndex"))),s.find(".progress-bar.first-step").width("100%").text(this.getProgressBarTitle(this.setup.$carousel.data("currentIndex"))),s.find(".progress-bar.last-step").width("0%").text(""),this.setup.forceSelection=!1):(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*l+"%").text(this.getProgressBarTitle(n)),s.find(".progress-bar.step").width("0%").text(""),i.slideDown()),r.removeClass("btn-"+a.getCssClass(this.setup.slides[n-1].severity)).addClass("btn-"+a.getCssClass(this.setup.slides[n].severity)),t.removeClass("modal-severity-"+a.getCssClass(this.setup.slides[n-1].severity)).addClass("modal-severity-"+a.getCssClass(this.setup.slides[n].severity))}prevSlideChanges(t){this.initializeSlidePrevEvent(t);let e=t.find(".modal-title"),s=t.find(".modal-footer"),i=t.find(".modal-btn-group"),r=s.find('button[name="next"]'),a=this.setup.$carousel.data("currentSlide")-1,l=this.setup.$carousel.data("currentIndex")-1;this.setup.$carousel.data("currentSlide",a),this.setup.$carousel.data("currentIndex",l),e.text(this.setup.slides[l].title),s.find(".progress-bar.last-step").width(this.setup.$carousel.data("initialStep")+"%").text(this.getProgressBarTitle(this.setup.$carousel.data("slideCount")-1)),r.text(top.TYPO3.lang["wizard.button.next"]),1===a?(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*a+"%").text(this.getProgressBarTitle(0)),s.find(".progress-bar.step").width(this.setup.$carousel.data("initialStep")+"%").text(this.getProgressBarTitle(l+1)),i.slideUp()):(s.find(".progress-bar.first-step").width(this.setup.$carousel.data("initialStep")*a+"%").text(this.getProgressBarTitle(l)),this.setup.forceSelection=!0)}getProgressBarTitle(t){let e;return e=null===this.setup.slides[t].progressBarTitle?0===t?top.TYPO3.lang["wizard.progressStep.start"]:t>=this.setup.$carousel.data("slideCount")-1?top.TYPO3.lang["wizard.progressStep.finish"]:top.TYPO3.lang["wizard.progressStep"]+String(t+1):this.setup.slides[t].progressBarTitle,e}runSlideCallback(t,e){"function"==typeof t.callback&&t.callback(e,this.setup.settings,t.identifier)}addProgressBar(){let t,e=this.setup.$carousel.find(".item").length-1,s=Math.max(1,e),r=this.setup.$carousel.closest(".modal").find(".modal-footer");if(t=Math.round(100/s),this.setup.$carousel.data("initialStep",t).data("slideCount",s).data("realSlideCount",e).data("currentIndex",0).data("currentSlide",1),s>1){r.prepend(i("<div />",{class:"progress"}));for(let e=0;e<this.setup.slides.length;++e){let s;s=0===e?"progress-bar first-step":e===this.setup.$carousel.data("slideCount")-1?"progress-bar last-step inactive":"progress-bar step inactive",r.find(".progress").append(i("<div />",{role:"progressbar",class:s,"aria-valuemin":0,"aria-valuenow":t,"aria-valuemax":100}).width(t+"%").text(this.getProgressBarTitle(e)))}}}addButtonContainer(){this.setup.$carousel.closest(".modal").find(".modal-footer .btn").wrapAll('<div class="modal-btn-group" />')}generateSlides(){if(null!==this.setup.$carousel)return this.setup.$carousel;let t='<div class="carousel slide" data-ride="carousel" data-interval="false"><div class="carousel-inner" role="listbox">';for(let e=0;e<this.setup.slides.length;++e){let s=this.setup.slides[e],i=s.content;"object"==typeof i&&(i=i.html()),t+='<div class="item" data-slide="'+s.identifier+'" data-step="'+e+'">'+i+"</div>"}return t+="</div></div>",this.setup.$carousel=i(t),this.setup.$carousel.find(".item").first().addClass("active"),this.setup.$carousel}}let d;try{window.opener&&window.opener.TYPO3&&window.opener.TYPO3.MultiStepWizard&&(d=window.opener.TYPO3.MultiStepWizard),parent&&parent.window.TYPO3&&parent.window.TYPO3.MultiStepWizard&&(d=parent.window.TYPO3.MultiStepWizard),top&&top.TYPO3&&top.TYPO3.MultiStepWizard&&(d=top.TYPO3.MultiStepWizard)}catch(t){}return d||(d=new n,"undefined"!=typeof TYPO3&&(TYPO3.MultiStepWizard=d)),d})); \ No newline at end of file diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js index f22f55d01b65..c55ef06644b4 100644 --- a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js +++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js @@ -612,11 +612,12 @@ define(['jquery', nextButton.on('click', function(e) { Icons.getIcon('spinner-circle', Icons.sizes.default, null, null).then(function(markup) { MultiStepWizard.set('confirmationDuplicateFormName', that.data('formName')); - MultiStepWizard.set('savePath', $(getDomElementIdentifier('duplicateFormSavePath') + ' option:selected', modal).val()); if (folders.length > 1) { + MultiStepWizard.set('savePath', $(getDomElementIdentifier('duplicateFormSavePath') + ' option:selected', modal).val()); MultiStepWizard.set('confirmationDuplicateFormSavePath', $(getDomElementIdentifier('duplicateFormSavePath') + ' option:selected', modal).text()); } else { + MultiStepWizard.set('savePath', folders[0]['value']); MultiStepWizard.set('confirmationDuplicateFormSavePath', folders[0]['label']); } -- GitLab