From 3cf86c37dac28c4a440fc2b15b12c1ea132e0934 Mon Sep 17 00:00:00 2001 From: Andreas Kienast <a.fernandez@scripting-base.de> Date: Thu, 29 Feb 2024 11:51:39 +0100 Subject: [PATCH] [TASK] Deprecate `@typo3/backend/wizard.js` The TYPO3 backend module `@typo3/backend/wizard.js` that offers simple wizards has been marked as deprecated in favor of the richer `@typo3/backend/multi-step-wizard.js` module. Resolves: #103230 Releases: main Change-Id: I653f8c746f8f7f2b48899a0a78ea759fd5eb95da Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83161 Tested-by: Benni Mack <benni@typo3.org> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Garvin Hicking <gh@faktor-e.de> Tested-by: Garvin Hicking <gh@faktor-e.de> Reviewed-by: Benni Mack <benni@typo3.org> --- Build/Sources/TypeScript/backend/wizard.ts | 6 ++ .../Resources/Public/JavaScript/wizard.js | 2 +- ...n-103230-DeprecateTypo3backendwizardjs.rst | 62 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/13.1/Deprecation-103230-DeprecateTypo3backendwizardjs.rst diff --git a/Build/Sources/TypeScript/backend/wizard.ts b/Build/Sources/TypeScript/backend/wizard.ts index 0dcda3678e06..011782eb88a0 100644 --- a/Build/Sources/TypeScript/backend/wizard.ts +++ b/Build/Sources/TypeScript/backend/wizard.ts @@ -43,12 +43,18 @@ interface Slide { /** * Module: @typo3/backend/wizard * @exports @typo3/backend/wizard + * @deprecated will be removed in TYPO3 14.0 */ class Wizard { private setup: WizardSetup; private readonly originalSetup: WizardSetup; constructor() { + console.warn( + 'The module `@typo3/backend/wizard.js` has been marked as deprecated and will be removed in TYPO3 v14.0. ' + + 'Consider migrating to `@typo3/backend/multi-step-wizard.js`.' + ); + this.setup = { slides: [], settings: {}, diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/wizard.js b/typo3/sysext/backend/Resources/Public/JavaScript/wizard.js index f9a9a3062886..e061172ad98b 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/wizard.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/wizard.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import{SeverityEnum}from"@typo3/backend/enum/severity.js";import $ from"jquery";import{Carousel}from"bootstrap";import{default as Modal}from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";import Icons from"@typo3/backend/icons.js";class Wizard{constructor(){this.setup={slides:[],settings:{},forceSelection:!0,$carousel:null,carousel:null},this.originalSetup=$.extend(!0,{},this.setup)}set(e,t){return this.setup.settings[e]=t,this}addSlide(e,t,s="",i=SeverityEnum.notice,r){const a={identifier:e,title:t,content:s,severity:i,callback:r};return this.setup.slides.push(a),this}addFinalProcessingSlide(e){return e||(e=()=>{this.dismiss()}),Icons.getIcon("spinner-circle",Icons.sizes.large,null,null).then((t=>{const s=$("<div />",{class:"text-center"}).append(t);this.addSlide("final-processing-slide",top.TYPO3.lang["wizard.processing.title"],s[0].outerHTML,Severity.notice,e)}))}show(){const e=this.generateSlides(),t=this.setup.slides[0];Modal.advanced({title:t.title,content:e,severity:t.severity,staticBackdrop:!0,buttons:[{text:top.TYPO3.lang["wizard.button.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:()=>{this.getComponent().trigger("wizard-dismiss")}},{text:top.TYPO3.lang["wizard.button.next"],btnClass:"btn-primary",name:"next"}],callback:e=>{this.setup.carousel=new Carousel(e.querySelector(".carousel")),this.addProgressBar(),this.initializeEvents(e)}}),this.setup.forceSelection&&this.lockNextStep(),this.getComponent().on("wizard-visible",(()=>{this.runSlideCallback(t,this.setup.$carousel.find(".carousel-item").first())})).on("wizard-dismissed",(()=>{this.setup=$.extend(!0,{},this.originalSetup)}))}getComponent(){return null===this.setup.$carousel&&this.generateSlides(),this.setup.$carousel}dismiss(){Modal.dismiss()}lockNextStep(){const e=this.setup.$carousel.closest(".modal").find('button[name="next"]');return e.prop("disabled",!0),e}unlockNextStep(){const e=this.setup.$carousel.closest(".modal").find('button[name="next"]');return e.prop("disabled",!1),e}setForceSelection(e){this.setup.forceSelection=e}initializeEvents(e){const t=this.setup.$carousel.closest(".modal"),s=t.find(".modal-title"),i=t.find(".modal-footer");i.find('button[name="next"]').on("click",(()=>{this.setup.carousel.next()})),this.setup.$carousel.get(0).addEventListener("slide.bs.carousel",(()=>{const e=this.setup.$carousel.data("currentSlide")+1,r=this.setup.$carousel.data("currentIndex")+1;s.text(this.setup.slides[r].title),this.setup.$carousel.data("currentSlide",e),this.setup.$carousel.data("currentIndex",r),e>=this.setup.$carousel.data("realSlideCount")?(t.find(".modal-header .close").remove(),i.slideUp()):i.find(".progress-bar").width(this.setup.$carousel.data("initialStep")*e+"%").text(top.TYPO3.lang["wizard.progress"].replace("{0}",e).replace("{1}",this.setup.$carousel.data("slideCount"))),t.removeClass("modal-severity-"+Severity.getCssClass(this.setup.slides[r-1].severity)).addClass("modal-severity-"+Severity.getCssClass(this.setup.slides[r].severity))})),this.setup.$carousel.get(0).addEventListener("slid.bs.carousel",(e=>{const t=this.setup.$carousel.data("currentIndex"),s=this.setup.slides[t];this.runSlideCallback(s,$(e.relatedTarget)),this.setup.forceSelection&&this.lockNextStep()}));const r=this.getComponent();r.on("wizard-dismiss",this.dismiss),e.addEventListener("typo3-modal-hidden",(()=>{r.trigger("wizard-dismissed")})),e.addEventListener("typo3-modal-shown",(()=>{r.trigger("wizard-visible")}))}runSlideCallback(e,t){"function"==typeof e.callback&&e.callback(t,this.setup.settings,e.identifier)}addProgressBar(){const e=this.setup.$carousel.find(".carousel-item").length,t=Math.max(1,e),s=Math.round(100/t),i=this.setup.$carousel.closest(".modal").find(".modal-footer");this.setup.$carousel.data("initialStep",s).data("slideCount",t).data("realSlideCount",e).data("currentIndex",0).data("currentSlide",1),t>1&&i.prepend($("<div />",{class:"progress"}).append($("<div />",{role:"progressbar",class:"progress-bar","aria-valuemin":0,"aria-valuenow":s,"aria-valuemax":100}).width(s+"%").text(top.TYPO3.lang["wizard.progress"].replace("{0}","1").replace("{1}",t.toString()))))}generateSlides(){if(null!==this.setup.$carousel)return this.setup.$carousel;let e='<div class="carousel slide" data-bs-ride="false"><div class="carousel-inner" role="listbox">';for(const t of Object.values(this.setup.slides)){let s=t.content;"object"==typeof s&&(s=s.html()),e+='<div class="carousel-item" data-bs-slide="'+t.identifier+'">'+s+"</div>"}return e+="</div></div>",this.setup.$carousel=$(e),this.setup.$carousel.find(".carousel-item").first().addClass("active"),this.setup.$carousel}}let wizardObject;try{window.opener&&window.opener.TYPO3&&window.opener.TYPO3.Wizard&&(wizardObject=window.opener.TYPO3.Wizard),parent&&parent.window.TYPO3&&parent.window.TYPO3.Wizard&&(wizardObject=parent.window.TYPO3.Wizard),top&&top.TYPO3&&top.TYPO3.Wizard&&(wizardObject=top.TYPO3.Wizard)}catch{}wizardObject||(wizardObject=new Wizard,"undefined"!=typeof TYPO3&&(TYPO3.Wizard=wizardObject));export default wizardObject; \ No newline at end of file +import{SeverityEnum}from"@typo3/backend/enum/severity.js";import $ from"jquery";import{Carousel}from"bootstrap";import{default as Modal}from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";import Icons from"@typo3/backend/icons.js";class Wizard{constructor(){console.warn("The module `@typo3/backend/wizard.js` has been marked as deprecated and will be removed in TYPO3 v14.0. Consider migrating to `@typo3/backend/multi-step-wizard.js`."),this.setup={slides:[],settings:{},forceSelection:!0,$carousel:null,carousel:null},this.originalSetup=$.extend(!0,{},this.setup)}set(e,t){return this.setup.settings[e]=t,this}addSlide(e,t,s="",i=SeverityEnum.notice,a){const r={identifier:e,title:t,content:s,severity:i,callback:a};return this.setup.slides.push(r),this}addFinalProcessingSlide(e){return e||(e=()=>{this.dismiss()}),Icons.getIcon("spinner-circle",Icons.sizes.large,null,null).then((t=>{const s=$("<div />",{class:"text-center"}).append(t);this.addSlide("final-processing-slide",top.TYPO3.lang["wizard.processing.title"],s[0].outerHTML,Severity.notice,e)}))}show(){const e=this.generateSlides(),t=this.setup.slides[0];Modal.advanced({title:t.title,content:e,severity:t.severity,staticBackdrop:!0,buttons:[{text:top.TYPO3.lang["wizard.button.cancel"],active:!0,btnClass:"btn-default",name:"cancel",trigger:()=>{this.getComponent().trigger("wizard-dismiss")}},{text:top.TYPO3.lang["wizard.button.next"],btnClass:"btn-primary",name:"next"}],callback:e=>{this.setup.carousel=new Carousel(e.querySelector(".carousel")),this.addProgressBar(),this.initializeEvents(e)}}),this.setup.forceSelection&&this.lockNextStep(),this.getComponent().on("wizard-visible",(()=>{this.runSlideCallback(t,this.setup.$carousel.find(".carousel-item").first())})).on("wizard-dismissed",(()=>{this.setup=$.extend(!0,{},this.originalSetup)}))}getComponent(){return null===this.setup.$carousel&&this.generateSlides(),this.setup.$carousel}dismiss(){Modal.dismiss()}lockNextStep(){const e=this.setup.$carousel.closest(".modal").find('button[name="next"]');return e.prop("disabled",!0),e}unlockNextStep(){const e=this.setup.$carousel.closest(".modal").find('button[name="next"]');return e.prop("disabled",!1),e}setForceSelection(e){this.setup.forceSelection=e}initializeEvents(e){const t=this.setup.$carousel.closest(".modal"),s=t.find(".modal-title"),i=t.find(".modal-footer");i.find('button[name="next"]').on("click",(()=>{this.setup.carousel.next()})),this.setup.$carousel.get(0).addEventListener("slide.bs.carousel",(()=>{const e=this.setup.$carousel.data("currentSlide")+1,a=this.setup.$carousel.data("currentIndex")+1;s.text(this.setup.slides[a].title),this.setup.$carousel.data("currentSlide",e),this.setup.$carousel.data("currentIndex",a),e>=this.setup.$carousel.data("realSlideCount")?(t.find(".modal-header .close").remove(),i.slideUp()):i.find(".progress-bar").width(this.setup.$carousel.data("initialStep")*e+"%").text(top.TYPO3.lang["wizard.progress"].replace("{0}",e).replace("{1}",this.setup.$carousel.data("slideCount"))),t.removeClass("modal-severity-"+Severity.getCssClass(this.setup.slides[a-1].severity)).addClass("modal-severity-"+Severity.getCssClass(this.setup.slides[a].severity))})),this.setup.$carousel.get(0).addEventListener("slid.bs.carousel",(e=>{const t=this.setup.$carousel.data("currentIndex"),s=this.setup.slides[t];this.runSlideCallback(s,$(e.relatedTarget)),this.setup.forceSelection&&this.lockNextStep()}));const a=this.getComponent();a.on("wizard-dismiss",this.dismiss),e.addEventListener("typo3-modal-hidden",(()=>{a.trigger("wizard-dismissed")})),e.addEventListener("typo3-modal-shown",(()=>{a.trigger("wizard-visible")}))}runSlideCallback(e,t){"function"==typeof e.callback&&e.callback(t,this.setup.settings,e.identifier)}addProgressBar(){const e=this.setup.$carousel.find(".carousel-item").length,t=Math.max(1,e),s=Math.round(100/t),i=this.setup.$carousel.closest(".modal").find(".modal-footer");this.setup.$carousel.data("initialStep",s).data("slideCount",t).data("realSlideCount",e).data("currentIndex",0).data("currentSlide",1),t>1&&i.prepend($("<div />",{class:"progress"}).append($("<div />",{role:"progressbar",class:"progress-bar","aria-valuemin":0,"aria-valuenow":s,"aria-valuemax":100}).width(s+"%").text(top.TYPO3.lang["wizard.progress"].replace("{0}","1").replace("{1}",t.toString()))))}generateSlides(){if(null!==this.setup.$carousel)return this.setup.$carousel;let e='<div class="carousel slide" data-bs-ride="false"><div class="carousel-inner" role="listbox">';for(const t of Object.values(this.setup.slides)){let s=t.content;"object"==typeof s&&(s=s.html()),e+='<div class="carousel-item" data-bs-slide="'+t.identifier+'">'+s+"</div>"}return e+="</div></div>",this.setup.$carousel=$(e),this.setup.$carousel.find(".carousel-item").first().addClass("active"),this.setup.$carousel}}let wizardObject;try{window.opener&&window.opener.TYPO3&&window.opener.TYPO3.Wizard&&(wizardObject=window.opener.TYPO3.Wizard),parent&&parent.window.TYPO3&&parent.window.TYPO3.Wizard&&(wizardObject=parent.window.TYPO3.Wizard),top&&top.TYPO3&&top.TYPO3.Wizard&&(wizardObject=top.TYPO3.Wizard)}catch{}wizardObject||(wizardObject=new Wizard,"undefined"!=typeof TYPO3&&(TYPO3.Wizard=wizardObject));export default wizardObject; \ No newline at end of file diff --git a/typo3/sysext/core/Documentation/Changelog/13.1/Deprecation-103230-DeprecateTypo3backendwizardjs.rst b/typo3/sysext/core/Documentation/Changelog/13.1/Deprecation-103230-DeprecateTypo3backendwizardjs.rst new file mode 100644 index 000000000000..6e7f6c70d044 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/13.1/Deprecation-103230-DeprecateTypo3backendwizardjs.rst @@ -0,0 +1,62 @@ +.. include:: /Includes.rst.txt + +.. _deprecation-103230-1709202638: + +=========================================================== +Deprecation: #103230 - Deprecate `@typo3/backend/wizard.js` +=========================================================== + +See :issue:`103230` + +Description +=========== + +The TYPO3 backend module :js:`@typo3/backend/wizard.js` that offers simple +wizards has been marked as deprecated in favor of the richer +:js:`@typo3/backend/multi-step-wizard.js` module. + + +Impact +====== + +Using the deprecated module will trigger a browser console warning. + + +Affected installations +====================== + +All installations using :js:`@typo3/backend/wizard.js` are affected. + + +Migration +========= + +Migrate to the module :js:`@typo3/backend/multi-step-wizard.js`. There are two +major differences: + +* The class name changes to :js:`MultiStepWizard` +* The method :js:`addSlide()` receives an additional argument for the step title + in the progress bar + + +Example +------- + +.. code-block:: diff + + -import Wizard from '@typo3/backend/wizard.js'; + +import MultiStepWizard from '@typo3/backend/multi-step-wizard.js'; + + -Wizard.addSlide( + +MultiStepWizard.addSlide( + 'my-slide-identifier', + 'Slide title', + 'Content of my slide', + SeverityEnum.notice, + + 'My step', + function () { + // callback executed after displaying the slide + } + ); + +.. index:: Backend, JavaScript, NotScanned, ext:backend -- GitLab