From fdd3689e5aed2ddae0646834427f8c700883be56 Mon Sep 17 00:00:00 2001 From: Dmitry Kurmanov Date: Fri, 29 Sep 2023 11:17:24 +0400 Subject: [PATCH] PR: Implement a proprietary confirmation dialog (#7015) * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * Update descriptions * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/private-tasks/issues/300 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * work for the https://github.com/surveyjs/survey-library/issues/6362 * Fix popup container is not removed in Vue --------- Co-authored-by: Roman Tsukanov Co-authored-by: Dmitry Kuzin --- src/common-styles/sv-popup.scss | 34 +++++++++++++ src/default-styles.scss | 5 ++ src/defaultV2-theme/blocks/sd-button.scss | 20 ++++++++ src/localization/english.ts | 2 + src/plugins/themes/common-theme-settings.ts | 1 + src/popup-utils.ts | 1 + src/popup.ts | 1 + src/settings.ts | 20 ++++++-- src/utils/utils.ts | 37 ++++++++++++++ src/vue/components/popup/popup-container.vue | 3 +- testCafe/questions/file.js | 48 ++++++++++-------- .../etalons/paneldynamic-confirm-dialog.png | Bin 0 -> 8596 bytes .../tests/defaultV2/paneldynamic.ts | 34 +++++++++++++ 13 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 visualRegressionTests/tests/defaultV2/etalons/paneldynamic-confirm-dialog.png diff --git a/src/common-styles/sv-popup.scss b/src/common-styles/sv-popup.scss index 2d67bcf712..c54210126b 100644 --- a/src/common-styles/sv-popup.scss +++ b/src/common-styles/sv-popup.scss @@ -63,6 +63,40 @@ sv-popup { } } +.sv-popup--confirm-delete { + .sv-popup__container { + border-radius: calcSize(1); + } + + .sv-popup__body-content { + border-radius: calcSize(1); + } + + .sv-popup__body-header { + color: $font-editorfont-color; + margin-bottom: 0; + + /* UI/Default */ + font-family: $font-family; + font-size: calcFontSize(1); + font-style: normal; + font-weight: 400; + line-height: calcLineHeight(1.5);/* 150% */ + } + + .sv-popup__scrolling-content { + display: none; + } + + .sv-popup__body-footer { + padding-bottom: 0; + + .sv-action-bar { + gap: calcSize(2); + } + } +} + .sv-popup.sv-popup--modal>.sv-popup__container { position: static; } diff --git a/src/default-styles.scss b/src/default-styles.scss index 6edce77a6d..af3b8fc7b7 100644 --- a/src/default-styles.scss +++ b/src/default-styles.scss @@ -1350,6 +1350,11 @@ sv-popup { background-color: var(--background-dim, #f3f3f3); } +.sv-popup__button.sv-popup__button--danger { + background-color: var(--sjs-special-red, #E50A3E); + color: var(--primary-foreground, #fff); +} + //eo popup //list .sv-list { diff --git a/src/defaultV2-theme/blocks/sd-button.scss b/src/defaultV2-theme/blocks/sd-button.scss index cf8c3d6934..a22a0eaa76 100644 --- a/src/defaultV2-theme/blocks/sd-button.scss +++ b/src/defaultV2-theme/blocks/sd-button.scss @@ -21,6 +21,11 @@ outline: none; } +.sd-btn--small { + flex-grow: 1; + padding: calcSize(1.5) calcSize(4); +} + .sd-btn:hover { background-color: $background-dark; } @@ -48,4 +53,19 @@ .sd-btn--action:disabled { color: $primary-foreground-disabled; pointer-events: none; +} + +.sd-btn--danger { + background-color: $red; + color: $primary-foreground; +} + +.sd-btn--danger:hover { + background-color: $red; + color: $primary-foreground; +} + +.sd-btn--danger:disabled { + color: $red-forecolor; + pointer-events: none; } \ No newline at end of file diff --git a/src/localization/english.ts b/src/localization/english.ts index 86dbe25431..1f93a552cc 100644 --- a/src/localization/english.ts +++ b/src/localization/english.ts @@ -101,6 +101,8 @@ export var englishStrings = { tagboxDoneButtonCaption: "OK", selectToRankEmptyRankedAreaText: "All choices are ranked", selectToRankEmptyUnrankedAreaText: "Drag and drop choices here to rank them", + ok: "OK", + cancel: "Cancel", }; // Uncomment the lines below if you create a custom dictionary. diff --git a/src/plugins/themes/common-theme-settings.ts b/src/plugins/themes/common-theme-settings.ts index 7cdd8583c0..d080787580 100644 --- a/src/plugins/themes/common-theme-settings.ts +++ b/src/plugins/themes/common-theme-settings.ts @@ -424,6 +424,7 @@ export function setStyles(): void { ".sv-popup__button:disabled:hover": "box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);", ".sv-popup__button.sv-popup__button--apply": "background-color: var(--primary, #19b394); color: var(--primary-foreground, #fff);", ".sv-popup__button.sv-popup__button--apply:disabled": "background-color: var(--background-dim, #f3f3f3);", + ".sv-popup__button.sv-popup__button--danger": "background-color: var(--sjs-special-red, #E50A3E); color: var(--primary-foreground, #fff);", //eo popup //list ".sv-list": "padding: 0; margin: 0; background: var(--background, #fff); list-style-type: none; overflow-y: auto;", diff --git a/src/popup-utils.ts b/src/popup-utils.ts index d18761594b..4e08f9dfc9 100644 --- a/src/popup-utils.ts +++ b/src/popup-utils.ts @@ -26,6 +26,7 @@ export function createPopupModalViewModel(options: IDialogOptions, rootElement?: options.title ); popupModel.displayMode = options.displayMode || "popup"; + popupModel.isFocusedContent = options.isFocusedContent ?? true; const popupViewModel: PopupBaseViewModel = new PopupModalViewModel(popupModel); if(!!rootElement && !!rootElement.appendChild) { var container: HTMLElement = document.createElement("div"); diff --git a/src/popup.ts b/src/popup.ts index 42b33bfcee..68fccb74c5 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -20,6 +20,7 @@ export interface IDialogOptions extends IPopupOptionsBase { componentName: string; data: any; onApply: () => boolean; + isFocusedContent?: boolean; } export interface IPopupModel extends IDialogOptions { contentComponentName: string; diff --git a/src/settings.ts b/src/settings.ts index b67ca77223..f0a497f94b 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,4 +1,5 @@ import { IDialogOptions } from "./popup"; +import { showConfirmDialog } from "./utils/utils"; export type ISurveyEnvironment = { root: Document | ShadowRoot, @@ -483,7 +484,7 @@ export var settings = { */ tagboxCloseOnSelect: false, /** - * A property that allows you to display a custom confirm dialog instead of the standard browser dialog. + * A property that allows you to display a custom confirm dialog. * * Set this property to a function that renders your custom dialog window. This function should return `true` if a user confirms an action or `false` otherwise. * @param message A message to be displayed in the confirm dialog window. @@ -492,14 +493,25 @@ export var settings = { return confirm(message); }, /** - * A property that allows you to display a custom confirm dialog instead of the standard browser dialog in async mode. + * A property that allows you to display a custom confirm dialog in async mode or activate the standard browser dialog. * - * Set this property to a function that renders your custom dialog window. This function should return `true` to be enabled; otherwise, a survey executes the [`confirmActionFunc`](#confirmActionFunc) function. Pass the dialog result as the `callback` parameter: `true` if a user confirms an action, `false` otherwise. + * To display a custom confirm dialog, set this property to a function that renders it. This function should return `true` to be enabled; otherwise, a survey executes the [`confirmActionFunc`](#confirmActionFunc) function. Pass the dialog result as the `callback` parameter: `true` if a user confirms an action, `false` otherwise. + * + * To activate the standard browser dialog, set the `confirmActionAsync` property to a function that returns `false`. With this configuration, a survey falls back to the [`confirmActionFunc`](#confirmActionFunc) function, which renders the standard browser dialog by default. + * + * ```js + * import { settings } from "survey-core"; + * + * // Display the standard browser dialog + * settings.confirmActionAsync = () => { + * return false; + * } + * ``` * @param message A message to be displayed in the confirm dialog window. * @param callback A callback function that should be called with `true` if a user confirms an action or `false` otherwise. */ confirmActionAsync: function (message: string, callback: (res: boolean) => void): boolean { - return false; + return showConfirmDialog(message, callback); }, /** * A minimum width value for all survey elements. diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 585b7c2c90..5a35f53807 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,8 @@ +import { LocalizableString } from "../localizablestring"; import { settings, ISurveyEnvironment } from "./../settings"; +import { IDialogOptions } from "../popup"; +import { surveyLocalization } from "../surveyStrings"; +import { PopupBaseViewModel } from "../popup-view-model"; function compareVersions(a: any, b: any) { const regExStrip0: RegExp = /(\.0+)+$/; @@ -14,19 +18,23 @@ function compareVersions(a: any, b: any) { } return segmentsA.length - segmentsB.length; } + function confirmAction(message: string): boolean { if (!!settings && !!settings.confirmActionFunc) return settings.confirmActionFunc(message); return confirm(message); } + function confirmActionAsync(message: string, funcOnYes: () => void, funcOnNo?: () => void): void { const callbackFunc = (res: boolean): void => { if(res) funcOnYes(); else if(!!funcOnNo) funcOnNo(); }; + if(!!settings && !!settings.confirmActionAsync) { if(settings.confirmActionAsync(message, callbackFunc)) return; } + callbackFunc(confirmAction(message)); } function detectIEBrowser(): boolean { @@ -399,6 +407,35 @@ export class Logger { } } +export function showConfirmDialog(message: string, callback: (res: boolean) => void): boolean { + const locStr = new LocalizableString(undefined); + const popupViewModel:PopupBaseViewModel = settings.showDialog({ + componentName: "sv-string-viewer", + data: { locStr: locStr, locString: locStr, model: locStr }, //TODO fix in library + onApply: () => { + callback(true); + return true; + }, + onCancel: () => { + callback(false); + return false; + }, + title: message, + displayMode: "popup", + isFocusedContent: false, + cssClass: "sv-popup--confirm-delete" + }, /*settings.rootElement*/document.body); //TODO survey root + const toolbar = popupViewModel.footerToolbar; + const applyBtn = toolbar.getActionById("apply"); + const cancelBtn = toolbar.getActionById("cancel"); + cancelBtn.title = surveyLocalization.getString("cancel"); + cancelBtn.innerCss = "sv-popup__body-footer-item sv-popup__button sd-btn sd-btn--small"; + applyBtn.title = surveyLocalization.getString("ok"); + applyBtn.innerCss = "sv-popup__body-footer-item sv-popup__button sv-popup__button--danger sd-btn sd-btn--small sd-btn--danger"; + popupViewModel.width = "452px"; + return true; +} + export { mergeValues, getElementWidth, diff --git a/src/vue/components/popup/popup-container.vue b/src/vue/components/popup/popup-container.vue index ffbe8ea160..3127b8cb99 100644 --- a/src/vue/components/popup/popup-container.vue +++ b/src/vue/components/popup/popup-container.vue @@ -105,11 +105,12 @@ export function showModal( export function showDialog(dialogOptions: IDialogOptions, rootElement?: HTMLElement): PopupBaseViewModel { dialogOptions.onHide = () => { popup.$destroy(); + popupViewModel.container.remove(); popupViewModel.dispose(); }; const popupViewModel: PopupBaseViewModel = createPopupModalViewModel(dialogOptions, rootElement); const popup = new PopupContainer({ - el: popupViewModel.container.appendChild(document.createElement("div")), + el: (popupViewModel.container).appendChild(document.createElement("div")), propsData: { model: popupViewModel }, }); popupViewModel.model.isVisible = true; diff --git a/testCafe/questions/file.js b/testCafe/questions/file.js index ceba77b6a0..be931c3481 100644 --- a/testCafe/questions/file.js +++ b/testCafe/questions/file.js @@ -162,26 +162,34 @@ frameworks.forEach(framework => { "input[type=file]", "../resources/small_Dashka.jpg" ); - await t - .setNativeDialogHandler(() => { - return false; - }) - .click(".sv_q_file_remove"); - await t - .setNativeDialogHandler(() => { - return false; - }) - .click(".sv_q_file_remove_button"); - const history = await t.getNativeDialogHistory(); - await t - .expect(history[1].type) - .eql("confirm") - .expect(history[1].text) - .eql("Are you sure that you want to remove this file: small_Dashka.jpg?") - .expect(history[0].type) - .eql("confirm") - .expect(history[0].text) - .eql("Are you sure that you want to remove all files?"); + + const getFileName = ClientFunction(() => window["survey"].getAllQuestions()[0].value[0].name); + const checkValue = ClientFunction(() => window["survey"].getAllQuestions()[0].value.length === 0); + await t.click(".sv_q_file_remove_button").click(".sv-popup--confirm-delete .sd-btn"); + assert.equal(await getFileName(), "small_Dashka.jpg"); + await t.click(".sv_q_file_remove_button").click(".sv-popup--confirm-delete .sd-btn--danger"); + assert.equal(await checkValue(), true); + + // await t + // .setNativeDialogHandler(() => { + // return false; + // }) + // .click(".sv_q_file_remove"); + // await t + // .setNativeDialogHandler(() => { + // return false; + // }) + // .click(".sv_q_file_remove_button"); + // const history = await t.getNativeDialogHistory(); + // await t + // .expect(history[1].type) + // .eql("confirm") + // .expect(history[1].text) + // .eql("Are you sure that you want to remove this file: small_Dashka.jpg?") + // .expect(history[0].type) + // .eql("confirm") + // .expect(history[0].text) + // .eql("Are you sure that you want to remove all files?"); }); // TODO testcafe waiting forever... // test(`change file max size`, async t => { diff --git a/visualRegressionTests/tests/defaultV2/etalons/paneldynamic-confirm-dialog.png b/visualRegressionTests/tests/defaultV2/etalons/paneldynamic-confirm-dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..a74ab2faa5b855d86bdea5547afe46d22e7ac83e GIT binary patch literal 8596 zcmc(lXH-;Kx2`dOfh3{?K~SPd2_?|v&>}f1h*E;&Ad-U!k|bvkK{6teTFD?8L?}X$ zC1(&QlH?3p!kN4K`|h}7oO8#x=lnVSL(8gNYp*@mobUV0Ssi>&O`iPxmGeYIMC6JJ zG8#lgCmP{({#g?E^DlXiIQZ+NqRgEKE+3{9epg5NBr@zz8mkYvM)u-R7DN4GQFcdK9pA8&$Um z)6(VsaAWJ<=?*O0pJz`g;Mhzqn(?)EREn)-C1rkpD9eC9_GtdOyPW4Gf2Mp)HIhlf zPBcY0MeWU-Hy5a=L`F(WOR0io&IV%phlcvb$5qZ?(S`^f>el4@tSy_G6B@g}ny!NL!Q%f;wg&-E!-t_*CFRY7P*+(DXJ+;nx>sEM* z*o%u4fwyn9e{kDhgImhT$f&V%adA1VPhM>=Mo-uXjf{-ISCT`DOG*?K73)`e($BE4 zuw)l^bf|R1#9TtYV5*i)-M8cfZ#&#{6itbDuD(h|6{VSgo&E|R%b=;?KNWa!ni^iz z|1Z3SxBP6;$B|#XChAjv%_~PWNzi`c`4ANu$rIQZ}^g8=LYA#vz|8-y2p_QGm5hw*ACZ-Z`bw8L6%+)UP*I$<9vcSORv_*5(`fq!NGGgRR48yvWm2p)@5~x-Ak5(xrS@wm1J~iqC=x+mX?@G z2ln#Gm)tyYp|cit6f| z5)vsNKCpQH8k^G4*2ZBer8=TmJt~l;mZD^6cwIh%(Ga45ME1vzXI+xNtZXXhXyhW9!VT%zP>(+c`F+&P?!C@P z!T(}SHzXt^Uf7-`1rytJmr_EeA+LNg1i9=JuVjvwX1t> zQRjd8`OHd?p*@b*y!8#cfS{m;hK6**C#{?tC{)H>fh(qmTXQH(v0rnuoRX4~f_CY% z%l`iUjkETH1^V6Tk&tlcM|7=U-LfM!ND<@~5 z@wq^3M~Yb7IckmzWF)TNz0YjCtVQY7(A7<;dw577L2C-RTrpw8p_Yt`;nLhVba(oz zpkRU0>)@0ZVV3!0e!dwLSVyu*^fWfm7(*lGykY=h&V5o%1MzPRrcU59JujIW>G$c= zO(yq^J7yj6^(Ebs?bPbx^?wZMVtG9`NmcsrDK93cz0WWi%r=K7d+d#jJN2o;3CO6K zIadkSO?AIIaq6#6pNxhJ4WY~-1%u_%#drHPU265(+S@DlC*3NSvXbZ^ALJPXo?eh} z+cRm2xVp18kwkI%@@0t8>!c)QVaBYAiuk7jZJO#5{zJ=|H8sg@>$P!7HdVp)v(1~b zbOCqt^q6?-2zXnYI(I*d5ey z-KalfVQp;+&y1wF>-K!qn>W%8mIbxVX?FvW0*{ySlJx%b74k`9Vq2u=4y#SgrX0aj zib2T6WN&2z6eD6D7TauQ*!=a|YP=$9q{MvIp>lDfSDClS{m{XzGqI^RQ`y4G3ZE9p zWK{1%tdc63g2$Ug(46;=7kj}28~Q%*NWW=$cWY3`_O{oNJIMXgx8Y%2E~W(6*=Y)C z#)eddKPjyPr17*vrSM~8W7ZP0P8K1dIFP~ULaPxz8XjHTlNS?BBj%}{NZu!lIL7mv zQ}~jQf54VmkHz0MCV?uOjgn_dD=UjdV&{h_To)t78KFrRR?oWBa0Vehw>>M+xO3BX z@qV(QH1_Sc%0Yp64a&z{j}8~OczDcU|0brUJ)@&-4gRF({H1gCY7;+y7C`j6#&tVh z$d+lM`o)5ap35{bRO-RRx@Tbb0xP&36exs3*2acsd8mNXaHQB2rCag3daa5yu3Z+A z6`UZ$cIu1xAwD`IE34S+*b{NR;Tl(dc+i>Dqove?fdWri9UTU6SGGFB9B%>~jb1^V z-~7B8^6-D%Pj~sfJA@deS;^*nlI_;A{&C_`Uv`O6(|IUi*Tu9z?GiKcbh+>u?J}E* zwl5yPaNXVV8997QGaxZ)+0o$H(z3F|0|NspDWY%nYF|z}SJU4%IxRGAcdA?JSX@dBJHpjQyy_tta9J-bc8^`|ALzO(f@Jh#{emaOAr-n#dH9J z3q;T2*|V9@D`*2E$Vo(s#%;Qmg|+nqwuNlBsYb4K6Z-$A?)Q5yxehPVMp8935L@J(dXHswk1 z1om)wiS?Ku;w`aTTMj3^iK02xImE;mfJ%sIb-!lD=_#2*GH2A*rnE+L&ThJFxQMGH z3IvCQoWIGQ}CbP;zEXW~#zlz||Z#v6 z5PNXgSKRp(K5_b<30YYjk_DtZ6|WSdIig}?L7>lrLSWHku!(a}+E!y_;Yqe%5^{4< zkaV<9oTwn0w{*%jFhB;H*=m_y$44L%Dt#vKwa?|{{H|Lj;!KoGk%6$_{rmUtn3}Sm zgRQeo!)a%|Sf9+u&ejCMeECu|FE6iVr&n3mV|PH;uAVp}Gqb1G?FEPWI~6xKG305n z-lxuhh2TTD^REH1_4hx3dluAeotOIA6GFcdSCbZPn zWbs=Xqq>I1MQdwo0U@D2!;SCth&*;d))r}#wHF^0Q(P650dMg5xsz4`tC3JJDgXhr zz$UO?y-y*xM3ec})QF36b91Ldh7}Ac2kz`RIXF1{_3`7hc3WH9jT<+$jNQX6D!n0&=qNA4#=tz(P@B?5#?kFcmauv?! z)ESD5;^H^m4ucr;=}ni#+}zwSAD@#odc0SA`}$g2Thp?#NZN~U@bYH=y_5Ey#H1v6 zOg1SgW-NLUz=`X|jrZ^+3JVJhGG<9ec+(D#qk=s_y|$pqL`}@hdh5KrA|7Hetsp}Q zplwq}d*!#uPDSOnsnODgHU-JB>@4*KA~iO(-ZJN~=?WI$;OOXj{Cl5X+y!lFYHDI) z@~zxf{~{!#XB{(CL-4$FwaDt{zTqz(V!#jxXClyb^!t}_$;jE$C)pZ}Zu9Z;D+aa9 zx`S_sZ+GxNc<=yTF~7DOwaD&C=rn`e{&Ev=ZrDl?9`#WC-)qa7gNagrszPiKEB7HL z6&|fzc-P(oS$Bql@jZY5F)5ARXTXWL*>fbm{R0EHEqd7^oMB?spO~ zF)_#jJz1(r&E|@#s+lEr!W~F1b8#7hHZ!gQk+5G3w%hoA2Ov#2HXwjRrLS>edsE6@ zm=OrN2Ln2iWihjTxQOE7ItMP_Gnk9P`kkYulXxi*V0f+f?a0y$5HgZ?TliKsXmbip z+i75*fKGL9vD4oP+uh~^pS0Z9-KLDO0pyo1Uq(z*T1|~Yr_2ff5!~-U+^C2yO2Mz2 z&jfb?@dn^Ogm<8zot6i~Pn;q_)~tHIEO&hL8^Pr1(jmRs9(iU{u+(JN`GnzB=TDzL zAqJ+;3H61dVWlH`^X^^O)J?!1kcbNuf%cWUPSBS*L0<*=z-Kv#%C9?mc|-$+3;hvd zySqdB-3!y(ha10sk9!^eCc7#cQ*alyshOoR4KUg`ZMR_xeHWZ*!XK72L;7A4Ek+oc zgoK2Zk&-}TC>ns6D_5=@u((SyZ@MHyC`Ch?jAU4-kiVc1H6J|igZ9tqImeS>pnBv8 z4mPIo^Yd@eE*l1)a&kWA`^JIGxia=i=Bk=T=!-dptjCqRxgbim} zTADYQ?iV$pAIJTMv<_u1A3e-lF?214T5Fw%k#sBwpEk<-CKr6GrA0LW}qS9T(nYOmJ z4!-+R7NSBa!o$PecY5UU3k%yA(0jN)=!PgMiSL6)kNTi^jGM#gFVWDjIPjsDSU&XJ zfa?*#`SAmBZK+=)-DgRB$DPNl0l6*)kkL1MOS|iekCKPVgd-8Oo$N4}sj`j4(6D(0@lZ0&Ni&~hB8~o0JK}6XBg_k(5 zKA!YC_JG?1^~p1P#6XNBm0>J^>*&BY(duUu7G4O%-jRm99VxeE1`EK?%|(5;6UKFQ zWr6AeLI9#Ldmdb8XJ;2?q>wBCIfj^y)Vc|QDaoYYk6;JCfw(%aPpSezK(`6}#Gw-Z z71{oLXHu{X3v7?c6;BmFakcIB^}E8cedXb+Lo}qL=$;!%p{`|SnWfN(5|Iw5pn+Z`cDFq*xQy2nuz;>XpL6Q-U zK+p@pxt~8@!b)y?E7RdZlh>|0@GJi{18Z9_#1;y%X{v{?g!O2!cTf{_zFZ z{fQSJ!A-V-H9ll!`a>6}siUKerpw6Bk9fX3Xb+ln5zhFoIFmWFUn^tfk&xmT3_Z+P zAX1(izRVk-UYnzq1ymG)uwn6|gIN#)(6Iy1Dy}dFp@_HKkBVKl&EW9hc;Fuw&-*W; z=*akh3}R6jA6)BKL1^_w2q|yl;z|taPsZNTX-47-O^Y%>CN-xTzL~+c5sa?hrd$&` za!~gKP#MRCE>mcV34{eHbI5YKfcj0k0PmLB>80${d4v(57ATynQyLni_tvMn5x53) zhqiofLF!n1seWXqD%8??b!B9IQm)9Q|YuY<&!w#9Hg(9*hX z)OZ%M8p*o#+I=Qy1HspN(x4Ig^V(O}g%o)J1PlfPM>^k;fJHhqKuG9G7;kZNhk`u7 zo?T{wIq5_k*r4=40(!I6nQ3l4ZoK+pyneLQQskJheYm9V71Fna*G^XB1PinpF7yU~ z-VT%^cmovV*K8@3*-mwV$V9f!v9PoI-!^W(2OjLPKOt{#f4iXWNED<9<{ePpzxGyV zYxgIO2?v`{u+R(8@tctW)rDBY=W@ZUo$!sDHyh?00JB@Wy38Oc#zDlODIzG!jAQ1PM1mO38z3nVFe8>r<%!6VP-%{Z9|OG+8TV`{j^BL_`EcrVp%WyN$a5 z4YUrNqoAZT!+bQ&EDX~dO7RUM$N7$Fb+4b)P(EQ-{s^&|sIvdOx92?RzO4#Z188KI zz=#b=SD;MDZ04q>rkbOl%aEy%kam^2(53J_>%SprJ=zG*-|~BZsyqKlwJ@;WBJ2Y~ z3@!C`zoxo9^lY1u*SEn6v(!@~pdGqSM^+3%(;RVC8CW%i9GDqY0yzulq+8b}sw?Lc zEfv(%nwNLqq^7D%gG@lNrUQY&n1?JXzw4>Bb*Zp_%-gs2z%!b&`t0q+3WX@r zLnH90dNf(pMKP8w+E~*lXlHM$Qe)AtqoG{E<6#=52zX50T8w(E?-{t^+kK&6_>}4` z9BoW&h)4!y{#XHu-u-Hn+o1=zZ zH1Ou9&n1d93cbCfNxH=@Pt6!bV=r6Ql=Tnqu5Bv8KR-??qp^6Ms4dK#FRgS?`pQ zk-Qw)0{AO(NFQ)VoM}NOxMlW&sE<3bv^>Cs6EO#ik0}Nx6#35r*Yzd9#ohS-c@}p^ z?bxPZ$eXQ!B2*}H-~ZOwcm)R3MC8^~JYM^*6mk(8Gx3T$%1Z&b*2ah+ClQ*B1>ZkV z1Q+Tt%Ap>cCPhJOyld5V=yh3l&JtdSA4;{WN*ehLksfx;g=5!fSoMY!4)pao1=drG z60uIWVZ!M>ZxI1rm&9*1UL5sy)f;)q@>|2UJym-iSMsYEazr{lcEN49Xwc+HnXpWNc+W~z?Jv@n7yzmyQfxJvrOdREd?Z&lL6OQacr$!gK1A^1pQhEE4 z72L(w0?nn= zZC0PK&?m$m?pOM}lwh)bJlj=se}z;?vv`3uacm5yq&B_QC&$lae)j5*bVJWdW+2Z&ths&la^ctQ8r9KBFCfCFSOg-4$SB9a}Q{`8rCsM~w2+p{OvgBm;IK zt+qJ!-e#S_AAw8XicKy@+%}&{wquHL3~)qoNma)5r>e0{<1~5us^%r|b@4$8aYel2 z9W9;YF3=^%^(1xoUWqLFg)?mab;eG;o=)!hdTaIWi7Z<;-$9qKE>E4JsD+cv{Cu^X ztbJ}8%;9$X5#_^l#-=|y*W=@ZAs!**2_Kl z#HG02a0wJ$KjWI z-+5J{W4L+0Zny?9pS`G8OLJ)HEQ4pb-YQ@}Y9&y*`N&~niEJ|?+JHz>p6}e{w3inr zB`;l@_R006Bb0WMpDBE$fNGXnpH!1(8&vyrE7)WD!fu|SxFSVHXz>`jSEEo`9$n&| zF=m=H;ZWTDQm7A&H(YUmSY$aYEbcDX*7gMbe!$Lq=r_ zO^HXf`z+JiVnh2<(dR^bgPV=Vx9Tkg$*5x>Y(u-eub1B_59mj#uZPT z6l(1+wiu1T0Z*Xfn4{hUZgU+SG$zU)!xRjMV8FH`(+ag;0gfm78L_*E&s zjwHn@tm0jPhWuD8iplc?B>(sxn;Ux?@mXazTC>8tm)j-}#dUPLMyn*k zyp}OPvoff{}II1Z3F@M%R?0j%7&V=&A^()gUKZzDhcjng!J-A1_ zTP;%5OpY8}$IC{#k38e>>oosI2}xC=2ZhSMxgSR}s=K+8%fBN~uO%Eaw75>OfSP?q zVf>g_Rllxcs*F7`=w6&;9k{$0HyVyIKQFs9qQcB~vD#v5xGRrf zv+yu~S?6p2IF&n9?GvVVOotvvX>Jq)o#DBMCPH&*FG;FA*mmqHv_*bs@U+u6ykk`z z*WYAnclN+dmp$xSjP-W+pqM%$QsrmPthEx#8Vdg%<~{t=gsQ+YV{Y0jbNW*?ID~ub zJh3{phcUlgNOV5~5BA*tt0Liz(L2&!g(NP6J4c>NW7jjQXL{WEN`4)W|i~h%r6S5Rxi080n zX=BqYpsIGMPhi?Sjz!-)^+||Dq7$*R3|v__Vg-I(?|TNOvB08$4-O7NFqKHZ4~=@3 zg%JWJf3FXpw8n*9w<4-@qbhmHZ01OJXf$I(yXh?fi_TQJkO2cCH!fjiNi80+fyi`fVe$M*5H1_I3ua7x0`N8mQ)D#E8G1_rP~gXN7?8pK0u1dwzz;XjxMW$p zfnRIInK7*H zfsvM$e^3za<6kf+h>fM`@REn#;$L4vPG0QATBCrf%2D5#ZCxic69BKUo-JQ{@i6>M zjBx$c6+*U)coz&N8ez7)I8iNRQ_c|Cau-4fS<6{nRwf8(06h&d!h(Sn8TKn=+L6@o Y{931;!7m2*-z { }); }); }); + +frameworks.forEach(framework => { + const json = { + "pages": [ + { + "name": "page1", + "elements": [{ + "type": "paneldynamic", + "panelCount": 1, + "name": "question1", + "templateElements": [ + { + "type": "text", + "name": "question2" + } + ], + "confirmDelete": true + }] + } + ] + }; + fixture`${framework} ${title} ${theme}` + .page`${url_test}${theme}/${framework}`.beforeEach(async t => { + await applyTheme(theme); + await initSurvey(framework, json); + }); + test("Paneldynamic confirm dialog", async (t) => { + await wrapVisualTest(t, async (t, comparer) => { + await t.resizeWindow(1280, 900); + await t.click(Selector(".sd-paneldynamic__remove-btn")); + await takeElementScreenshot("paneldynamic-confirm-dialog", Selector(".sv-popup--confirm-delete .sv-popup__body-content"), t, comparer); + }); + }); +});