Commit 87473dc4 authored by Frank Nägler's avatar Frank Nägler Committed by Anja Leichsenring
Browse files

[TASK] Migrate TYPO3/CMS/Backend/Wizard to TypeScript

Resolves: #82612
Releases: master
Change-Id: I6dd7d2138afe98bd60889dd4f25b7a3b2dca287d
Reviewed-on: https://review.typo3.org/c/59669


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
parent 11b62b81
......@@ -21,6 +21,7 @@ declare namespace TYPO3 {
export let Storage: any;
export let Tooltip: any;
export let Utility: any;
export let Wizard: any;
export const lang: { [key: string]: string };
export const settings: any;
export const configuration: any;
......
......@@ -14,7 +14,7 @@
import {SeverityEnum} from './Enum/Severity';
import * as $ from 'jquery';
import Icons = require('./Icons');
import Wizard = require('TYPO3/CMS/Backend/Wizard');
import Wizard = require('./Wizard');
type LanguageRecord = {
uid: number;
......@@ -255,7 +255,7 @@ class Localization {
} else {
Wizard.lockNextStep();
}
}).on('change', '.t3js-localization-toggle-column', (toggleEvt): void => {
}).on('change', '.t3js-localization-toggle-column', (toggleEvt: JQueryEventObject): void => {
const $me = $(toggleEvt.currentTarget);
const $children = $me.closest('fieldset').find('.t3js-localization-toggle-record');
......
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import {SeverityEnum} from './Enum/Severity';
import * as $ from 'jquery';
import Modal = require('./Modal');
import Severity = require('./Severity');
import Icons = require('./Icons');
interface WizardSettings {
[key: string]: any;
}
interface WizardSetup {
slides: Array<any>;
settings: WizardSettings;
forceSelection: boolean;
$carousel: JQuery;
}
interface Slide {
identifier: string;
title: string;
content: string|JQuery;
severity: SeverityEnum;
callback?: Function;
}
/**
* Module: TYPO3/CMS/Backend/Wizard
* @exports TYPO3/CMS/Backend/Wizard
*/
class Wizard {
private setup: WizardSetup;
private readonly originalSetup: WizardSetup;
constructor() {
this.setup = {
slides: [],
settings: {},
forceSelection: true,
$carousel: null,
};
this.originalSetup = $.extend(true, {}, this.setup);
}
public set(key: string, value: any): Wizard {
this.setup.settings[key] = value;
return this;
}
public addSlide(
identifier: string,
title: string,
content: string = '',
severity: SeverityEnum = SeverityEnum.info,
callback?: Function,
): Wizard {
const slide: Slide = {
identifier: identifier,
title: title,
content: content,
severity: severity,
callback: callback,
};
this.setup.slides.push(slide);
return this;
}
public addFinalProcessingSlide(callback?: Function): JQueryPromise<any> {
if (!callback) {
callback = (): void => {
this.dismiss();
};
}
return Icons.getIcon('spinner-circle-dark', Icons.sizes.large, null, null).done((markup: string) => {
let $processingSlide = $('<div />', {class: 'text-center'}).append(markup);
this.addSlide(
'final-processing-slide', top.TYPO3.lang['wizard.processing.title'],
$processingSlide[0].outerHTML,
Severity.info,
callback,
);
});
}
public show(): void {
let $slides = this.generateSlides();
let firstSlide = this.setup.slides[0];
Modal.confirm(
firstSlide.title,
$slides,
firstSlide.severity,
[{
text: top.TYPO3.lang['wizard.button.cancel'],
active: true,
btnClass: 'btn-default',
name: 'cancel',
trigger: (): void => {
this.getComponent().trigger('wizard-dismiss');
},
}, {
text: top.TYPO3.lang['wizard.button.next'],
btnClass: 'btn-' + Severity.getCssClass(firstSlide.severity),
name: 'next',
}],
);
if (this.setup.forceSelection) {
this.lockNextStep();
}
this.addProgressBar();
this.initializeEvents();
this.getComponent().on('wizard-visible', (): void => {
this.runSlideCallback(firstSlide, this.setup.$carousel.find('.item').first());
}).on('wizard-dismissed', (): void => {
this.setup = $.extend(true, {}, this.originalSetup);
});
}
public getComponent(): JQuery {
if (this.setup.$carousel === null) {
this.generateSlides();
}
return this.setup.$carousel;
}
public dismiss(): void {
Modal.dismiss();
}
public lockNextStep(): JQuery {
let $button = this.setup.$carousel.closest('.modal').find('button[name="next"]');
$button.prop('disabled', true);
return $button;
}
public unlockNextStep(): JQuery {
let $button = this.setup.$carousel.closest('.modal').find('button[name="next"]');
$button.prop('disabled', false);
return $button;
}
private initializeEvents(): void {
let $modal = this.setup.$carousel.closest('.modal');
let $modalTitle = $modal.find('.modal-title');
let $modalFooter = $modal.find('.modal-footer');
let $nextButton = $modalFooter.find('button[name="next"]');
$nextButton.on('click', (): void => {
this.setup.$carousel.carousel('next');
});
this.setup.$carousel.on('slide.bs.carousel', (): void => {
let nextSlideNumber = this.setup.$carousel.data('currentSlide') + 1;
let currentIndex = this.setup.$carousel.data('currentIndex') + 1;
$modalTitle.text(this.setup.slides[currentIndex].title);
this.setup.$carousel.data('currentSlide', nextSlideNumber);
this.setup.$carousel.data('currentIndex', currentIndex);
if (nextSlideNumber >= this.setup.$carousel.data('realSlideCount')) {
// Point of no return - hide modal footer disable any closing ability
$modal.find('.modal-header .close').remove();
$modalFooter.slideUp();
} else {
$modalFooter.find('.progress-bar')
.width(this.setup.$carousel.data('initialStep') * nextSlideNumber + '%')
.text(top.TYPO3.lang['wizard.progress']
.replace('{0}', nextSlideNumber)
.replace('{1}', this.setup.$carousel.data('slideCount')));
}
$nextButton
.removeClass('btn-' + Severity.getCssClass(this.setup.slides[currentIndex - 1].severity))
.addClass('btn-' + Severity.getCssClass(this.setup.slides[currentIndex].severity));
$modal
.removeClass('modal-severity-' + Severity.getCssClass(this.setup.slides[currentIndex - 1].severity))
.addClass('modal-severity-' + Severity.getCssClass(this.setup.slides[currentIndex].severity));
}).on('slid.bs.carousel', (evt: JQueryEventObject): void => {
let currentIndex = this.setup.$carousel.data('currentIndex');
let slide = this.setup.slides[currentIndex];
this.runSlideCallback(slide, $(evt.relatedTarget));
if (this.setup.forceSelection) {
this.lockNextStep();
}
});
/**
* Custom event, closes the wizard
*/
let cmp = this.getComponent();
cmp.on('wizard-dismiss', this.dismiss);
Modal.currentModal.on('hidden.bs.modal', (): void => {
cmp.trigger('wizard-dismissed');
}).on('shown.bs.modal', (): void => {
cmp.trigger('wizard-visible');
});
}
private runSlideCallback(slide: Slide, $slide: JQuery): void {
if (typeof slide.callback === 'function') {
slide.callback($slide, this.setup.settings, slide.identifier);
}
}
private addProgressBar(): void {
let realSlideCount = this.setup.$carousel.find('.item').length;
let slideCount = Math.max(1, realSlideCount);
let initialStep;
let $modal = this.setup.$carousel.closest('.modal');
let $modalFooter = $modal.find('.modal-footer');
initialStep = Math.round(100 / slideCount);
this.setup.$carousel
.data('initialStep', initialStep)
.data('slideCount', slideCount)
.data('realSlideCount', realSlideCount)
.data('currentIndex', 0)
.data('currentSlide', 1);
// Append progress bar to modal footer
if (slideCount > 1) {
$modalFooter.prepend(
$('<div />', {class: 'progress'}).append(
$('<div />', {
role: 'progressbar',
class: 'progress-bar',
'aria-valuemin': 0,
'aria-valuenow': initialStep,
'aria-valuemax': 100,
}).width(initialStep + '%').text(
top.TYPO3.lang['wizard.progress']
.replace('{0}', '1')
.replace('{1}', slideCount),
),
),
);
}
}
private generateSlides(): JQuery {
// Check whether the slides were already generated
if (this.setup.$carousel !== null) {
return this.setup.$carousel;
}
let slides = '<div class="carousel slide" data-ride="carousel" data-interval="false">'
+ '<div class="carousel-inner" role="listbox">';
for (let i = 0; i < this.setup.slides.length; ++i) {
let currentSlide: Slide = this.setup.slides[i];
let slideContent = currentSlide.content;
if (typeof slideContent === 'object') {
slideContent = slideContent.html();
}
slides += '<div class="item" data-slide="' + currentSlide.identifier + '">' + slideContent + '</div>';
}
slides += '</div></div>';
this.setup.$carousel = $(slides);
this.setup.$carousel.find('.item').first().addClass('active');
return this.setup.$carousel;
}
}
let wizardObject;
try {
// fetch from opening window
if (window.opener && window.opener.TYPO3 && window.opener.TYPO3.Wizard) {
wizardObject = window.opener.TYPO3.Wizard;
}
// fetch from parent
if (parent && parent.window.TYPO3 && parent.window.TYPO3.Wizard) {
wizardObject = parent.window.TYPO3.Wizard;
}
// fetch object from outer frame
if (top && top.TYPO3 && top.TYPO3.Wizard) {
wizardObject = top.TYPO3.Wizard;
}
} catch (e) {
// This only happens if the opener, parent or top is some other url (eg a local file)
// which loaded the current window. Then the browser's cross domain policy jumps in
// and raises an exception.
// For this case we are safe and we can create our global object below.
}
if (!wizardObject) {
wizardObject = new Wizard();
// attach to global frame
if (typeof TYPO3 !== 'undefined') {
TYPO3.Wizard = wizardObject;
}
}
export = wizardObject;
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
var __values=this&&this.__values||function(e){var t="function"==typeof Symbol&&e[Symbol.iterator],a=0;return t?t.call(e):{next:function(){return e&&a>=e.length&&(e=void 0),{value:e&&e[a++],done:!e}}}};define(["require","exports","./Enum/Severity","jquery","./Icons","TYPO3/CMS/Backend/Wizard"],function(e,t,a,n,o,l){"use strict";return new(function(){function e(){var e=this;this.triggerButton=".t3js-localize",this.localizationMode=null,this.sourceLanguage=null,this.records=[],n(function(){e.initialize()})}return e.prototype.initialize=function(){var e=this,t=this;o.getIcon("actions-localize",o.sizes.large).done(function(i){o.getIcon("actions-edit-copy",o.sizes.large).done(function(c){n(t.triggerButton).removeClass("disabled"),n(document).on("click",t.triggerButton,function(t){t.preventDefault();var r=n(t.currentTarget),d=[],s="";r.data("allowTranslate")&&d.push('<div class="row"><div class="btn-group col-sm-3"><label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-translate">'+i+'<input type="radio" name="mode" id="mode_translate" value="localize" style="display: none"><br>Translate</label></div><div class="col-sm-9"><p class="t3js-helptext t3js-helptext-translate text-muted">'+TYPO3.lang["localize.educate.translate"]+"</p></div></div>"),r.data("allowCopy")&&d.push('<div class="row"><div class="col-sm-3 btn-group"><label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-copy">'+c+'<input type="radio" name="mode" id="mode_copy" value="copyFromLanguage" style="display: none"><br>Copy</label></div><div class="col-sm-9"><p class="t3js-helptext t3js-helptext-copy text-muted">'+TYPO3.lang["localize.educate.copy"]+"</p></div></div>"),s+='<div data-toggle="buttons">'+d.join("<hr>")+"</div>",l.addSlide("localize-choose-action",TYPO3.lang["localize.wizard.header_page"].replace("{0}",r.data("page")).replace("{1}",r.data("languageName")),s,a.SeverityEnum.info),l.addSlide("localize-choose-language",TYPO3.lang["localize.view.chooseLanguage"],"",a.SeverityEnum.info,function(t){o.getIcon("spinner-circle-dark",o.sizes.large).done(function(a){t.html('<div class="text-center">'+a+"</div>"),e.loadAvailableLanguages(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10)).done(function(a){if(1===a.length)return e.sourceLanguage=a[0].uid,void l.unlockNextStep().trigger("click");l.getComponent().on("click",".t3js-language-option",function(t){var a=n(t.currentTarget).find('input[type="radio"]');e.sourceLanguage=a.val(),console.log("Localization.ts@132",e.sourceLanguage),l.unlockNextStep()});var o,i,c=n("<div />",{class:"row","data-toggle":"buttons"});try{for(var r=__values(a),d=r.next();!d.done;d=r.next()){var s=d.value;c.append(n("<div />",{class:"col-sm-4"}).append(n("<label />",{class:"btn btn-default btn-block t3js-language-option option"}).text(" "+s.title).prepend(s.flagIcon).prepend(n("<input />",{type:"radio",name:"language",id:"language"+s.uid,value:s.uid,style:"display: none;"}))))}}catch(e){o={error:e}}finally{try{d&&!d.done&&(i=r.return)&&i.call(r)}finally{if(o)throw o.error}}t.empty().append(c)})})}),l.addSlide("localize-summary",TYPO3.lang["localize.view.summary"],"",a.SeverityEnum.info,function(t){o.getIcon("spinner-circle-dark",o.sizes.large).done(function(e){t.html('<div class="text-center">'+e+"</div>")}),e.getSummary(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10)).done(function(a){t.empty(),e.records=[];var o=a.columns.columns;a.columns.columnList.forEach(function(l){if(void 0!==a.records[l]){var i=o[l],c=n("<div />",{class:"row"});a.records[l].forEach(function(t){var a=" ("+t.uid+") "+t.title;e.records.push(t.uid),c.append(n("<div />",{class:"col-sm-6"}).append(n("<div />",{class:"input-group"}).append(n("<span />",{class:"input-group-addon"}).append(n("<input />",{type:"checkbox",class:"t3js-localization-toggle-record",id:"record-uid-"+t.uid,checked:"checked","data-uid":t.uid,"aria-label":a})),n("<label />",{class:"form-control",for:"record-uid-"+t.uid}).text(a).prepend(t.icon))))}),t.append(n("<fieldset />",{class:"localization-fieldset"}).append(n("<label />").text(i).prepend(n("<input />",{class:"t3js-localization-toggle-column",type:"checkbox",checked:"checked"})),c))}}),l.unlockNextStep(),l.getComponent().on("change",".t3js-localization-toggle-record",function(t){var a=n(t.currentTarget),o=a.data("uid"),i=a.closest("fieldset"),c=i.find(".t3js-localization-toggle-column");if(a.is(":checked"))e.records.push(o);else{var r=e.records.indexOf(o);r>-1&&e.records.splice(r,1)}var d=i.find(".t3js-localization-toggle-record"),s=i.find(".t3js-localization-toggle-record:checked");c.prop("checked",s.length>0),c.prop("indeterminate",s.length>0&&s.length<d.length),e.records.length>0?l.unlockNextStep():l.lockNextStep()}).on("change",".t3js-localization-toggle-column",function(e){var t=n(e.currentTarget),a=t.closest("fieldset").find(".t3js-localization-toggle-record");a.prop("checked",t.is(":checked")),a.trigger("change")})})}),l.addFinalProcessingSlide(function(){e.localizeRecords(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10),e.records).done(function(){l.dismiss(),document.location.reload()})}).done(function(){l.show(),l.getComponent().on("click",".t3js-localization-option",function(t){var a=n(t.currentTarget),o=a.find('input[type="radio"]');if(a.data("helptext")){var i=n(t.delegateTarget);i.find(".t3js-helptext").addClass("text-muted"),i.find(a.data("helptext")).removeClass("text-muted")}e.localizationMode=o.val(),l.unlockNextStep()})})})})})},e.prototype.loadAvailableLanguages=function(e,t){return n.ajax({url:TYPO3.settings.ajaxUrls.page_languages,data:{pageId:e,languageId:t}})},e.prototype.getSummary=function(e,t){return n.ajax({url:TYPO3.settings.ajaxUrls.records_localize_summary,data:{pageId:e,destLanguageId:t,languageId:this.sourceLanguage}})},e.prototype.localizeRecords=function(e,t,a){return n.ajax({url:TYPO3.settings.ajaxUrls.records_localize,data:{pageId:e,srcLanguageId:this.sourceLanguage,destLanguageId:t,action:this.localizationMode,uidList:a}})},e}())});
\ No newline at end of file
var __values=this&&this.__values||function(e){var t="function"==typeof Symbol&&e[Symbol.iterator],a=0;return t?t.call(e):{next:function(){return e&&a>=e.length&&(e=void 0),{value:e&&e[a++],done:!e}}}};define(["require","exports","./Enum/Severity","jquery","./Icons","./Wizard"],function(e,t,a,n,o,l){"use strict";return new(function(){function e(){var e=this;this.triggerButton=".t3js-localize",this.localizationMode=null,this.sourceLanguage=null,this.records=[],n(function(){e.initialize()})}return e.prototype.initialize=function(){var e=this,t=this;o.getIcon("actions-localize",o.sizes.large).done(function(i){o.getIcon("actions-edit-copy",o.sizes.large).done(function(c){n(t.triggerButton).removeClass("disabled"),n(document).on("click",t.triggerButton,function(t){t.preventDefault();var r=n(t.currentTarget),d=[],s="";r.data("allowTranslate")&&d.push('<div class="row"><div class="btn-group col-sm-3"><label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-translate">'+i+'<input type="radio" name="mode" id="mode_translate" value="localize" style="display: none"><br>Translate</label></div><div class="col-sm-9"><p class="t3js-helptext t3js-helptext-translate text-muted">'+TYPO3.lang["localize.educate.translate"]+"</p></div></div>"),r.data("allowCopy")&&d.push('<div class="row"><div class="col-sm-3 btn-group"><label class="btn btn-block btn-default t3js-localization-option" data-helptext=".t3js-helptext-copy">'+c+'<input type="radio" name="mode" id="mode_copy" value="copyFromLanguage" style="display: none"><br>Copy</label></div><div class="col-sm-9"><p class="t3js-helptext t3js-helptext-copy text-muted">'+TYPO3.lang["localize.educate.copy"]+"</p></div></div>"),s+='<div data-toggle="buttons">'+d.join("<hr>")+"</div>",l.addSlide("localize-choose-action",TYPO3.lang["localize.wizard.header_page"].replace("{0}",r.data("page")).replace("{1}",r.data("languageName")),s,a.SeverityEnum.info),l.addSlide("localize-choose-language",TYPO3.lang["localize.view.chooseLanguage"],"",a.SeverityEnum.info,function(t){o.getIcon("spinner-circle-dark",o.sizes.large).done(function(a){t.html('<div class="text-center">'+a+"</div>"),e.loadAvailableLanguages(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10)).done(function(a){if(1===a.length)return e.sourceLanguage=a[0].uid,void l.unlockNextStep().trigger("click");l.getComponent().on("click",".t3js-language-option",function(t){var a=n(t.currentTarget).find('input[type="radio"]');e.sourceLanguage=a.val(),console.log("Localization.ts@132",e.sourceLanguage),l.unlockNextStep()});var o,i,c=n("<div />",{class:"row","data-toggle":"buttons"});try{for(var r=__values(a),d=r.next();!d.done;d=r.next()){var s=d.value;c.append(n("<div />",{class:"col-sm-4"}).append(n("<label />",{class:"btn btn-default btn-block t3js-language-option option"}).text(" "+s.title).prepend(s.flagIcon).prepend(n("<input />",{type:"radio",name:"language",id:"language"+s.uid,value:s.uid,style:"display: none;"}))))}}catch(e){o={error:e}}finally{try{d&&!d.done&&(i=r.return)&&i.call(r)}finally{if(o)throw o.error}}t.empty().append(c)})})}),l.addSlide("localize-summary",TYPO3.lang["localize.view.summary"],"",a.SeverityEnum.info,function(t){o.getIcon("spinner-circle-dark",o.sizes.large).done(function(e){t.html('<div class="text-center">'+e+"</div>")}),e.getSummary(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10)).done(function(a){t.empty(),e.records=[];var o=a.columns.columns;a.columns.columnList.forEach(function(l){if(void 0!==a.records[l]){var i=o[l],c=n("<div />",{class:"row"});a.records[l].forEach(function(t){var a=" ("+t.uid+") "+t.title;e.records.push(t.uid),c.append(n("<div />",{class:"col-sm-6"}).append(n("<div />",{class:"input-group"}).append(n("<span />",{class:"input-group-addon"}).append(n("<input />",{type:"checkbox",class:"t3js-localization-toggle-record",id:"record-uid-"+t.uid,checked:"checked","data-uid":t.uid,"aria-label":a})),n("<label />",{class:"form-control",for:"record-uid-"+t.uid}).text(a).prepend(t.icon))))}),t.append(n("<fieldset />",{class:"localization-fieldset"}).append(n("<label />").text(i).prepend(n("<input />",{class:"t3js-localization-toggle-column",type:"checkbox",checked:"checked"})),c))}}),l.unlockNextStep(),l.getComponent().on("change",".t3js-localization-toggle-record",function(t){var a=n(t.currentTarget),o=a.data("uid"),i=a.closest("fieldset"),c=i.find(".t3js-localization-toggle-column");if(a.is(":checked"))e.records.push(o);else{var r=e.records.indexOf(o);r>-1&&e.records.splice(r,1)}var d=i.find(".t3js-localization-toggle-record"),s=i.find(".t3js-localization-toggle-record:checked");c.prop("checked",s.length>0),c.prop("indeterminate",s.length>0&&s.length<d.length),e.records.length>0?l.unlockNextStep():l.lockNextStep()}).on("change",".t3js-localization-toggle-column",function(e){var t=n(e.currentTarget),a=t.closest("fieldset").find(".t3js-localization-toggle-record");a.prop("checked",t.is(":checked")),a.trigger("change")})})}),l.addFinalProcessingSlide(function(){e.localizeRecords(parseInt(r.data("pageId"),10),parseInt(r.data("languageId"),10),e.records).done(function(){l.dismiss(),document.location.reload()})}).done(function(){l.show(),l.getComponent().on("click",".t3js-localization-option",function(t){var a=n(t.currentTarget),o=a.find('input[type="radio"]');if(a.data("helptext")){var i=n(t.delegateTarget);i.find(".t3js-helptext").addClass("text-muted"),i.find(a.data("helptext")).removeClass("text-muted")}e.localizationMode=o.val(),l.unlockNextStep()})})})})})},e.prototype.loadAvailableLanguages=function(e,t){return n.ajax({url:TYPO3.settings.ajaxUrls.page_languages,data:{pageId:e,languageId:t}})},e.prototype.getSummary=function(e,t){return n.ajax({url:TYPO3.settings.ajaxUrls.records_localize_summary,data:{pageId:e,destLanguageId:t,languageId:this.sourceLanguage}})},e.prototype.localizeRecords=function(e,t,a){return n.ajax({url:TYPO3.settings.ajaxUrls.records_localize,data:{pageId:e,srcLanguageId:this.sourceLanguage,destLanguageId:t,action:this.localizationMode,uidList:a}})},e}())});
\ No newline at end of file
......@@ -10,351 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
/**
* Module: TYPO3/CMS/Backend/Wizard
* API for wizard windows.
*/
define(['jquery',
'TYPO3/CMS/Backend/Modal',
'TYPO3/CMS/Backend/Severity',
'TYPO3/CMS/Backend/Icons',
'bootstrap'
], function($, Modal, Severity, Icons) {
'use strict';
try {
// fetch from parent
if (parent && parent.window.TYPO3 && parent.window.TYPO3.Wizard) {
return parent.window.TYPO3.Wizard;
}
// fetch object from outer frame
if (top && top.TYPO3 && top.TYPO3.Wizard) {
return top.TYPO3.Wizard;
}
} catch (e) {
// This only happens if the opener, parent or top is some other url (eg a local file)
// which loaded the current window. Then the browser's cross domain policy jumps in
// and raises an exception.
// For this case we are safe and we can create our global object below.
}
/**
* @type {{setup: {slides: Array, settings: {}, forceSelection: boolean, $carousel: null}, originalSetup: {}}}
* @exports TYPO3/CMS/Backend/Wizard
*/
var Wizard = {
setup: {
slides: [],
settings: {},
forceSelection: true,
$carousel: null
},
originalSetup: {}
};
/**
* Initializes the events after building the wizards
*
* @private
*/
Wizard.initializeEvents = function() {
var $modal = Wizard.setup.$carousel.closest('.modal'),
$modalTitle = $modal.find('.modal-title'),
$modalFooter = $modal.find('.modal-footer'),
$nextButton = $modalFooter.find('button[name="next"]');
$nextButton.on('click', function() {
Wizard.setup.$carousel.carousel('next');
});
Wizard.setup.$carousel.on('slide.bs.carousel', function() {
var nextSlideNumber = Wizard.setup.$carousel.data('currentSlide') + 1,
currentIndex = Wizard.setup.$carousel.data('currentIndex') + 1;
$modalTitle.text(Wizard.setup.slides[currentIndex].title);
Wizard.setup.$carousel.data('currentSlide', nextSlideNumber);
Wizard.setup.$carousel.data('currentIndex', currentIndex);
if (nextSlideNumber >= Wizard.setup.$carousel.data('realSlideCount')) {
// Point of no return - hide modal footer disable any closing ability
$modal.find('.modal-header .close').remove();
$modalFooter.slideUp();
} else {
$modalFooter.find('.progress-bar')
.width(Wizard.setup.$carousel.data('initialStep') * nextSlideNumber + '%')
.text(top.TYPO3.lang['wizard.progress']
.replace('{0}', nextSlideNumber)
.replace('{1}', Wizard.setup.$carousel.data('slideCount')));
}
$nextButton
.removeClass('btn-' + Severity.getCssClass(Wizard.setup.slides[currentIndex - 1].severity))
.addClass('btn-' + Severity.getCssClass(Wizard.setup.slides[currentIndex].severity));
$modal
.removeClass('modal-severity-' + Severity.getCssClass(Wizard.setup.slides[currentIndex - 1].severity))
.addClass('modal-severity-' + Severity.getCssClass(Wizard.setup.slides[currentIndex].severity));
}).on('slid.bs.carousel', function(e) {
var currentIndex = Wizard.setup.$carousel.data('currentIndex'),
slide = Wizard.setup.slides[currentIndex];
Wizard.runSlideCallback(slide, $(e.relatedTarget));
if (Wizard.setup.forceSelection) {
Wizard.lockNextStep();
}
});
/**
* Custom event, closes the wizard
*/
var cmp = Wizard.getComponent();
cmp.on('wizard-dismiss', Wizard.dismiss);
Modal.currentModal.on('hidden.bs.modal', function() {
cmp.trigger('wizard-dismissed');
}).on('shown.bs.modal', function() {
cmp.trigger('wizard-visible');
});
};
/**
* @param {String} key
* @param {*} value
* @returns {Object}
*/
Wizard.set = function(key, value) {
Wizard.setup.settings[key] = value;
return Wizard;
};
/**
* Adds a new slide to the wizard
*
* @param {String} identifier
* @param {String} title
* @param {String} content
* @param {String} severity
* @param {Function} callback
* @returns {Object}
*/
Wizard.addSlide = function(identifier, title, content, severity, callback) {
Wizard.setup.slides.push({
identifier: identifier,
title: title,
content: content || '',
severity: (typeof severity !== 'undefined' ? severity : Severity.info),
callback: callback
});
return Wizard;
};
/**
* Adds a final processing slide
*
* @param {Function} callback
* @returns {Object}
*/
Wizard.addFinalProcessingSlide = function(callback) {
if (typeof callback !== 'function') {
callback = function() {
Wizard.dismiss();
}
}