Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Implement a proprietary confirmation dialog #7015

Merged
merged 25 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1980943
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 19, 2023
886c069
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 19, 2023
a94038c
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 22, 2023
c9c6480
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 22, 2023
9199cbb
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 22, 2023
b78a5db
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 25, 2023
86d3557
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 25, 2023
6ca0dea
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 26, 2023
25b9076
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 26, 2023
8d6dc5d
Update descriptions
Sep 26, 2023
576fa08
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 26, 2023
1d13a68
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 26, 2023
d26e3d5
Merge branch 'feature/6362-custom-confirmation-dialog' of https://git…
dmitry-kurmanov Sep 26, 2023
28da9b3
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 26, 2023
d734ec7
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 27, 2023
fd8afd6
work for the https://github.com/surveyjs/private-tasks/issues/300
dmitry-kurmanov Sep 27, 2023
fbc3002
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
1131075
Merge branch 'master' into feature/6362-custom-confirmation-dialog
dmitry-kurmanov Sep 27, 2023
b499a2a
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
231b2f0
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
61f8ef0
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
758e06a
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
1539ec2
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
7d01221
work for the https://github.com/surveyjs/survey-library/issues/6362
dmitry-kurmanov Sep 27, 2023
c1679ba
Fix popup container is not removed in Vue
dk981234 Sep 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/common-styles/sv-popup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
5 changes: 5 additions & 0 deletions src/default-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
20 changes: 20 additions & 0 deletions src/defaultV2-theme/blocks/sd-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions src/localization/english.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/plugins/themes/common-theme-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;",
Expand Down
1 change: 1 addition & 0 deletions src/popup-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
1 change: 1 addition & 0 deletions src/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface IDialogOptions extends IPopupOptionsBase {
componentName: string;
data: any;
onApply: () => boolean;
isFocusedContent?: boolean;
}
export interface IPopupModel<T = any> extends IDialogOptions {
contentComponentName: string;
Expand Down
20 changes: 16 additions & 4 deletions src/settings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IDialogOptions } from "./popup";
import { showConfirmDialog } from "./utils/utils";

export type ISurveyEnvironment = {
root: Document | ShadowRoot,
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
37 changes: 37 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -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+)+$/;
Expand All @@ -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 {
Expand Down Expand Up @@ -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(<IDialogOptions>{
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,
Expand Down
3 changes: 2 additions & 1 deletion src/vue/components/popup/popup-container.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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: (<HTMLElement>popupViewModel.container).appendChild(document.createElement("div")),
propsData: { model: popupViewModel },
});
popupViewModel.model.isVisible = true;
Expand Down
48 changes: 28 additions & 20 deletions testCafe/questions/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions visualRegressionTests/tests/defaultV2/paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,37 @@ frameworks.forEach(framework => {
});
});
});

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);
});
});
});
Loading