Skip to content

Commit

Permalink
Resolved #5264 - creator.onOpenFileChooser - Introduce a parameter wh…
Browse files Browse the repository at this point in the history
…ich would indicate the source property (#5329)

* Resolved #5264 - creator.onOpenFileChooser - Introduce a parameter which would indicate the source property

* Work for #5264 - creator.onOpenFileChooser - Introduce a parameter which would indicate the source property

* Work for #5264 - creator.onOpenFileChooser - Introduce a parameter which would indicate the source property

* Fixed lint

---------

Co-authored-by: tsv2013 <tsv2013@noreply.github.com>
  • Loading branch information
tsv2013 and tsv2013 committed Mar 19, 2024
1 parent daacff0 commit ad208b2
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 93 deletions.
7 changes: 6 additions & 1 deletion packages/survey-creator-core/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@
// "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"editor.tabSize": 2,
"editor.formatOnSave": true,
"eslint.format.enable": true
"eslint.format.enable": true,
"jest.outputConfig": {
"revealOn": "run",
"revealWithFocus": "test-results",
"clearOnRun": "none"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class LogoImageViewModel extends Base {
if (fileInput.files.length === 0) {
model.creator.chooseFiles(fileInput, (files: File[]) => {
model.uploadFile(model, fileInput, files);
});
}, { element: this.survey, elementType: this.survey.getType(), propertyName: "logo" });
}
else model.uploadFile(model, fileInput, [fileInput.files[0]]);
}
Expand Down
60 changes: 2 additions & 58 deletions packages/survey-creator-core/src/components/image-item-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class ImageItemValueWrapperViewModel extends ItemValueWrapperViewModel {
}
model.isUploading = false;
});
}, { element: model.question, item: model.item });
}, { element: model.question, item: model.item, elementType: model.item.getType(), propertyName: "imageLink" });
}

public uploadFiles(files) {
Expand All @@ -61,7 +61,7 @@ export class ImageItemValueWrapperViewModel extends ItemValueWrapperViewModel {
model.creator.chooseFiles(fileInput, (files: File[]) => {
this.isChoosingNewFile = true;
model.uploadFiles(files);
}, { element: model.question, item: model.item });
}, { element: model.question, item: model.item, elementType: model.item.getType(), propertyName: "imageLink" });
}
onDragOver = (event: any) => {
this.isFileDragging = true;
Expand All @@ -86,59 +86,3 @@ export class ImageItemValueWrapperViewModel extends ItemValueWrapperViewModel {
return getAcceptedTypesByContentMode(this.question.contentMode);
}
}

// chooseFiles() {
// editor.chooseFiles(fileInput, (files: File[]) => {
// var itemText = Survey.surveyLocalization.getString("choices_Item");
// var nextValue = getNextValue(
// itemText,
// (model.choices || []).map(c => c.value)
// );
// var itemValue = new (<any>Survey)["ItemValue"](
// nextValue,
// undefined,
// "imageitemvalue"
// );
// itemValue.locOwner = <any>{
// getLocale: () => {
// if (!!model["getLocale"]) return model.getLocale();
// return "";
// },
// getMarkdownHtml: (text: string) => {
// return text;
// },
// getProcessedText: (text: string) => {
// return text;
// }
// };
// model.choices = model.choices.concat([itemValue]);
// itemValue = model.choices[model.choices.length - 1];
// editor.onQuestionEditorChanged(model);
// editor.onItemValueAddedCallback(
// model,
// "choices",
// itemValue,
// model.choices
// );

// var property = Survey.Serializer.findProperty(
// "imageitemvalue",
// "imageLink"
// );
// editor.uploadFiles(files, (_, link) => {
// var options = {
// propertyName: property.name,
// obj: itemValue,
// value: link,
// newValue: null,
// doValidation: false
// };
// editor.onValueChangingCallback(options);
// link = options.newValue === null ? options.value : options.newValue;
// itemValue["imageLink"] = link;
// editor.onPropertyValueChanged(property, itemValue, link);
// editor.onQuestionEditorChanged(model);
// });
// });
// });
// }
6 changes: 3 additions & 3 deletions packages/survey-creator-core/src/components/question-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export class QuestionImageAdornerViewModel extends QuestionAdornerViewModel {
this.filePresentationModel.acceptedTypes = "image/*";
this.filePresentationModel.storeDataAsText = false;
this.filePresentationModel.cssClasses.chooseFileIconId = "icon-choosefile";
surveyModel.onOpenFileChooser.add((s, o) => {
this.creator.chooseFiles(o.input, o.callback, { element: o.element as SurveyElement, item: o.item });
surveyModel.onOpenFileChooser.add((s, o: any) => {
this.creator.chooseFiles(o.input, o.callback, o.context);
});
surveyModel.onUploadFiles.add((s, o) => {
const fileToUpload = o.files[0];
Expand Down Expand Up @@ -57,7 +57,7 @@ export class QuestionImageAdornerViewModel extends QuestionAdornerViewModel {
(<QuestionImageModel>model.surveyElement).imageLink = link;
model.isUploading = false;
});
}, { element: model.question });
}, { element: model.question, elementType: model.question.getType(), propertyName: "imageLink" });
}
public get acceptedTypes(): string {
return getAcceptedTypesByContentMode((this.surveyElement as QuestionImageModel).contentMode);
Expand Down
34 changes: 28 additions & 6 deletions packages/survey-creator-core/src/components/tabs/theme-builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SurveySimulatorModel } from "../simulator";
import { Base, propertyArray, property, PageModel, SurveyModel, Action, IAction, ActionContainer, ComputedUpdater, defaultV2Css, ITheme, ItemValue, ImageFit, ImageAttachment, QuestionDropdownModel, ValueChangingEvent, ValueChangedEvent, EventBase, Serializer, Question, IHeader, IElement, PanelModel, PanelModelBase } from "survey-core";
import { Base, propertyArray, property, PageModel, SurveyModel, Action, IAction, ActionContainer, ComputedUpdater, defaultV2Css, ITheme, ItemValue, ImageFit, ImageAttachment, QuestionDropdownModel, ValueChangingEvent, ValueChangedEvent, EventBase, Serializer, Question, IHeader, IElement, PanelModel, PanelModelBase, QuestionFileModel } from "survey-core";
import { SurveyCreatorModel } from "../../creator-base";
import { editorLocalization, getLocString } from "../../editorLocalization";
import { setSurveyJSONForPropertyGrid } from "../../property-grid";
Expand Down Expand Up @@ -327,7 +327,7 @@ export class ThemeEditorModel extends Base {
component: "svc-complete-page",
data: this
});
if(!!json && !!json.locale) {
if (!!json && !!json.locale) {
survey.locale = json.locale;
}
survey.applyTheme(this.currentTheme);
Expand Down Expand Up @@ -769,6 +769,18 @@ export class ThemeEditorModel extends Base {
}
});

themeEditorSurvey.onOpenFileChooser.add((_, options) => {
const context: any = {};
assign(context, (options as any).context, { element: this.currentTheme as any, elementType: "theme" });
if (options.element) {
const question = options.element as QuestionFileModel;
context.propertyName = question.name;
if (question.parentQuestion) {
context.elementType = question.parentQuestion.name === "headerViewContainer" ? "header" : question.parentQuestion.name;
}
}
this.surveyProvider.chooseFiles(options.input, options.callback, context as any);
});
themeEditorSurvey.onUploadFiles.add((_, options) => {
const callback = (status: string, data: any) => options.callback(status, [{ content: data, file: options.files[0] }]);
this.surveyProvider.uploadFiles(options.files, undefined, callback);
Expand Down Expand Up @@ -837,7 +849,17 @@ export class ThemeEditorModel extends Base {
}
private patchFileEditors(survey: SurveyModel) {
const questionsToPatch = survey.getAllQuestions(false, false, true).filter(q => q.getType() == "fileedit");
questionsToPatch.forEach(q => { (<QuestionFileEditorModel>q).onChooseFilesCallback = (input, callback) => this.surveyProvider.chooseFiles(input, callback); });
questionsToPatch.forEach(q => {
(<QuestionFileEditorModel>q).onChooseFilesCallback = (input, callback) => {
const themePropertyName = q.name;
let elementType = "theme";
if (q.parentQuestion) {
elementType = q.parentQuestion.name === "headerViewContainer" ? "header" : q.parentQuestion.name;
}
(q.parentQuestion ? q.parentQuestion.name + "." : "") + q.name;
this.surveyProvider.chooseFiles(input, callback, { element: this.currentTheme as any, elementType: elementType, propertyName: themePropertyName });
};
});
}

private getCoverJson(headerSettings: any): any {
Expand Down Expand Up @@ -886,7 +908,7 @@ export class ThemeEditorModel extends Base {
private updateVisibilityOfPropertyGridGroups() {
const page = this.themeEditorSurvey.pages[0];
page.getElementByName("groupHeader").visible = this.surveyProvider.isMobileView ? false : settings.theme.allowEditHeaderSettings;
if(this.advancedModeSwitcher) {
if (this.advancedModeSwitcher) {
this.advancedModeSwitcher.visible = !this.surveyProvider.isMobileView;
}
}
Expand Down Expand Up @@ -916,7 +938,7 @@ export class ThemeEditorModel extends Base {
this.updateVisibilityOfPropertyGridGroups();

const headerViewContainerQuestion = this.themeEditorSurvey.getQuestionByName("headerViewContainer");
if(!headerViewContainerQuestion) return;
if (!headerViewContainerQuestion) return;

const panel = headerViewContainerQuestion.panels[0];
panel.getQuestionByName("backgroundColor").choices = this.getPredefinedColorsItemValues();
Expand Down Expand Up @@ -1000,7 +1022,7 @@ export class ThemeEditorModel extends Base {
this._setPGEditorPropertyValue(themeEditorSurvey.getQuestionByName("backgroundOpacity"), "value", this.currentTheme.backgroundOpacity * 100);

const primaryBackcolor = themeEditorSurvey.getQuestionByName("--sjs-primary-backcolor");
if(!!primaryBackcolor) {
if (!!primaryBackcolor) {
this._setPGEditorPropertyValue(themeEditorSurvey.getQuestionByName("generalPrimaryColor"), "value", primaryBackcolor.value);
}

Expand Down
9 changes: 6 additions & 3 deletions packages/survey-creator-core/src/creator-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2695,17 +2695,20 @@ export class SurveyCreatorModel extends Base
public chooseFiles(
input: HTMLInputElement,
callback: (files: File[]) => void,
context?: { element: SurveyElement, item?: ItemValue }
context?: { element: Base, item?: any, elementType?: string, propertyName?: string }
) {
if (this.onOpenFileChooser.isEmpty) {
chooseFiles(input, callback);
} else {
this.onOpenFileChooser.fire(this, {
input: input,
element: context && context.element || this.survey,
elementType: context && context.elementType,
item: context && context.item,
callback: callback
});
propertyName: context && context.propertyName,
callback: callback,
context: context
} as any);
}
}
/**
Expand Down
15 changes: 12 additions & 3 deletions packages/survey-creator-core/src/creator-events-api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
Base, IAction, ItemValue, JsonObjectProperty, LocalizableString, MatrixDropdownColumn, PageModel, PanelModel,
PopupBaseViewModel, Question, SurveyModel, IElement, ISurveyElement, IPanel
PopupBaseViewModel, Question, SurveyModel, IElement, ISurveyElement, IPanel, ITheme
} from "survey-core";
import { SurveyLogicItem } from "./components/tabs/logic-items";
import { ICreatorPlugin } from "./creator-settings";
Expand Down Expand Up @@ -635,9 +635,18 @@ export interface OpenFileChooserEvent {
*/
input: HTMLInputElement;
/**
* A question, panel, page, or survey for which this event is raised.
* A survey element (question, panel, page, or survey) or a theme JSON schema for which this event is raised.
*/
element: Base;
element: Base | ITheme;
/**
* The type of the element passed as the `options.element` parameter.\
* Possible values: `"theme"`, `"header"`, or any value returned from the [`getType()`](https://surveyjs.io/form-library/documentation/api-reference/question#getType) method.
*/
elementType: String;
/**
* The name of the survey element property or theme property for which files are being selected.
*/
propertyName: String;
/**
* A choice item for which the event is raised. This parameter has a value only when the dialog window is opened to select images for an [Image Picker](https://surveyjs.io/form-library/documentation/api-reference/image-picker-question-model) question.
*/
Expand Down
8 changes: 4 additions & 4 deletions packages/survey-creator-core/src/creator-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export interface ISurveyCreatorOptions {
onGetElementEditorTitleCallback(obj: Base, title: string): string;
startUndoRedoTransaction();
stopUndoRedoTransaction();
createSurvey(json: any, reason: string, model?: any, callback?: (survey: SurveyModel)=> void, area?: string);
createSurvey(json: any, reason: string, model?: any, callback?: (survey: SurveyModel) => void, area?: string);
onConditionQuestionsGetListCallback(
propertyName: string,
obj: Base,
Expand Down Expand Up @@ -325,7 +325,7 @@ export interface ISurveyCreatorOptions {
chooseFiles(
input: HTMLInputElement,
callback: (files: File[]) => void,
context?: { element: SurveyElement, item?: ItemValue }
context?: { element: Base, item?: any, elementType?: string, propertyName?: string }
): void;
}

Expand Down Expand Up @@ -446,7 +446,7 @@ export class EmptySurveyCreatorOptions implements ISurveyCreatorOptions {
stopUndoRedoTransaction() { }
createSurvey(json: any, reason: string, model?: any, callback?: (survey: SurveyModel) => void, area?: string): SurveyModel {
const survey = new SurveyModel(json);
if(!!callback) {
if (!!callback) {
callback(survey);
}
return survey;
Expand Down Expand Up @@ -478,7 +478,7 @@ export class EmptySurveyCreatorOptions implements ISurveyCreatorOptions {
): void { }
getHasMachineTranslation(): boolean { return this.machineTranslationValue; }
doMachineTranslation(fromLocale: string, toLocale: string, strings: Array<string>, callback: (translated: Array<string>) => void): void { }
chooseFiles(input: HTMLInputElement, callback: (files: File[]) => void, context?: { element: SurveyElement, item?: ItemValue }): void { }
chooseFiles(input: HTMLInputElement, callback: (files: File[]) => void, context?: { element: Base, item?: any, elementType?: string, propertyName?: string }): void { }
}

StylesManager.applyTheme("defaultV2");
2 changes: 1 addition & 1 deletion packages/survey-creator-core/src/property-grid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ export class PropertyGridLinkEditor extends PropertyGridEditor {
question.acceptedTypes = getAcceptedTypesByContentMode("image");
}
question.onChooseFilesCallback = ((input, callback) => {
options.chooseFiles(input, callback);
options.chooseFiles(input, callback, { element: obj, elementType: obj.getType(), propertyName: question.name });
});
}

Expand Down
7 changes: 6 additions & 1 deletion packages/survey-creator-core/tests/components.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -987,8 +987,10 @@ test("QuestionImageAdornerViewModel onOpenFileChooser event is raised", () => {
elements: [{ type: "image", name: "q1" }]
};
let log = "";
let lastContext: any;
creator.onOpenFileChooser.add((s, o) => {
log += "->onOpenFileChooser";
lastContext = o.context;
o.callback([]);
});
const question = <QuestionImageModel>creator.survey.getAllQuestions()[0];
Expand All @@ -997,6 +999,9 @@ test("QuestionImageAdornerViewModel onOpenFileChooser event is raised", () => {
const fileQuestionAdornerSurvey = imageAdorner.filePresentationModel.getSurvey();

expect(log).toBe("");
fileQuestionAdornerSurvey.chooseFiles(document.createElement("input"), () => { });
fileQuestionAdornerSurvey.chooseFiles(document.createElement("input"), () => { }, { element: question, elementType: question.getType(), propertyName: "imageLink" });
expect(log).toBe("->onOpenFileChooser");
expect(lastContext.element).toEqual(question);
expect(lastContext.elementType).toEqual("image");
expect(lastContext.propertyName).toEqual("imageLink");
});
31 changes: 21 additions & 10 deletions packages/survey-creator-core/tests/property-grid/file.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,29 @@ test("Check file editor with onDownloadfile and onUploadFile callbacks", () => {
question.loadFiles(<any>[{ name: "secondValue" }]);
expect(question.value).toBe("secondValueBase64");
expect(clearCallbackLog).toBe("->firstValue");
question.onInputBlur(<any>{ target: {
value: "url_from_input"
} });
question.onInputBlur(<any>{
target: {
value: "url_from_input"
}
});
expect(question.value).toBe("url_from_input");
expect(clearCallbackLog).toBe("->firstValue->secondValue");
expect(question["loadedFilesValue"]).toBe(undefined);
});

test("Check file editor event callbacks", () => {
const question: QuestionFileEditorModel = new QuestionFileEditorModel("q1");
question.onInputChange(<any>{ target: {
value: "first_base64"
} });
question.onInputChange(<any>{
target: {
value: "first_base64"
}
});
expect(question.value).toBe("first_base64");
question.onInputBlur(<any>{ target: {
value: "second_url"
} });
question.onInputBlur(<any>{
target: {
value: "second_url"
}
});
expect(question.value).toBe("second_url");
});

Expand Down Expand Up @@ -228,8 +234,10 @@ test("Check onOpenFileChooser called", () => {
questionEditor["rootElement"] = <any>{ querySelectorAll: () => [{}] };
let uploadCount = 0;
let log = "";
let lastContext: any;
creator.onOpenFileChooser.add((s, o) => {
log += "->openedFileChooser";
lastContext = o.context;
o.callback([{}]);
});
creator.onUploadFile.add((s, o) => {
Expand All @@ -239,8 +247,11 @@ test("Check onOpenFileChooser called", () => {
});
expect(uploadCount).toBe(0);
expect(log).toBe("");
questionEditor.chooseFiles(<any>{ preventDefault: () => {}, stopPropagation: () => {} });
questionEditor.chooseFiles(<any>{ preventDefault: () => { }, stopPropagation: () => { } });
expect(uploadCount).toBe(1);
expect(log).toBe("->openedFileChooser->uploadFile");
expect(questionEditor.value).toBe("url");
expect(lastContext.element).toEqual(question);
expect(lastContext.elementType).toEqual("image");
expect(lastContext.propertyName).toEqual("imageLink");
});

0 comments on commit ad208b2

Please sign in to comment.