Skip to content

Commit

Permalink
feat: draw widget
Browse files Browse the repository at this point in the history
  • Loading branch information
Anro Swart committed Feb 26, 2024
1 parent b7d0052 commit 76507a3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
1 change: 1 addition & 0 deletions webapp/src/css/enketo/_widgets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import "../../../node_modules/enketo-core/src/widget/table/tablewidget.scss";
@import "../../../node_modules/enketo-core/src/widget/radio/radiopicker.scss";
@import "../../../node_modules/enketo-core/src/widget/date/datepicker-extended.scss";
@import "../../../node_modules/enketo-core/src/widget/draw/draw-widget.scss";
@import "../../../node_modules/enketo-core/src/widget/time/timepicker-extended.scss";
@import "../../../node_modules/enketo-core/src/widget/datetime/datetimepicker-extended.scss";
@import "../../../node_modules/enketo-core/src/widget/file/filepicker.scss";
Expand Down
1 change: 1 addition & 0 deletions webapp/src/js/enketo/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require( 'enketo-core/src/widget/table/tablewidget' ).default,
require( 'enketo-core/src/widget/radio/radiopicker' ).default,
require( 'enketo-core/src/widget/date/datepicker-extended' ).default,
require( 'enketo-core/src/widget/draw/draw-widget' ).default,
require( 'enketo-core/src/widget/time/timepicker-extended' ).default,
require( 'enketo-core/src/widget/datetime/datetimepicker-extended' ).default,
require( 'enketo-core/src/widget/columns/columns' ).default,
Expand Down
53 changes: 45 additions & 8 deletions webapp/src/ts/services/enketo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export class EnketoService {
instanceStr: instanceStr,
};
if (contactSummaryXML) {
options.external = [ contactSummaryXML ];
options.external = [contactSummaryXML];
}
const form = wrapper.find('form')[0];
return new window.EnketoForm(form, options, { language: userSettings.language });
Expand Down Expand Up @@ -222,7 +222,7 @@ export class EnketoService {
} // else the title is hardcoded in the form definition - leave it alone
}

private setNavigation(form, $wrapper, useWindowHistory=true) {
private setNavigation(form, $wrapper, useWindowHistory = true) {
if (useWindowHistory) {
// Handle page turning using browser history
window.history.replaceState({ enketo_page_number: 0 }, '');
Expand Down Expand Up @@ -473,12 +473,49 @@ export class EnketoService {
.each((idx, element) => {
const xpath = Xpath.getElementXPath(element);
const $input: any = $('input[type=file][name="' + xpath + '"]');
const file = $input[0].files[0];
const inputElement = $input[0];
let file: File | undefined | null;

if (inputElement?.files?.length > 0 && inputElement.files[0]) {
file = inputElement.files[0];
} else {
file = convertDrawDataToFile(xpath);
}

if (file) {
attach(element, file, file.type, false, xpath);
}
});

const convertDrawDataToFile = (xpath): File | undefined => {
try {
const canvasElement = <HTMLCanvasElement>document.querySelector('.draw-widget__body__canvas');
const imageDataURL = canvasElement.toDataURL('image/png'); // convert to base64
const blob = dataURLtoBlob(imageDataURL);

const parts = xpath.split('/');
const tagName = parts[parts.length - 1];

return new File([blob], `${tagName}.png`, { type: 'image/png' });
} catch (error) {
console.error('Error while processing draw widget data:', error);
}
}

const dataURLtoBlob = (dataURL) => {
const parts = dataURL.split(';base64,');
const contentType = parts[0].split(':')[1];
const byteString = atob(parts[1]);
const arrayBuffer = new ArrayBuffer(byteString.length);
const uint8Array = new Uint8Array(arrayBuffer);

for (let i = 0; i < byteString.length; i++) {
uint8Array[i] = byteString.charCodeAt(i);
}

return new Blob([arrayBuffer], { type: contentType });
}

$record
.find('[type=binary]')
.each((idx, element) => {
Expand Down Expand Up @@ -513,7 +550,7 @@ export class EnketoService {
}

private create(formInternalId, contact) {
return {
return {
form: formInternalId,
type: 'data_record',
content_type: 'xml',
Expand Down Expand Up @@ -617,7 +654,7 @@ interface XmlFormContext {
hasContactSummary: boolean;
};
wrapper: JQuery;
instanceData: null|string|Record<string, any>; // String for report forms, Record<> for contact forms.
instanceData: null | string | Record<string, any>; // String for report forms, Record<> for contact forms.
titleKey?: string;
isFormInModal?: boolean;
contactSummary?: Record<string, any>;
Expand All @@ -628,15 +665,15 @@ export class EnketoFormContext {
formDoc: Record<string, any>;
type: string; // 'contact'|'report'|'task'|'training-card'
editing: boolean;
instanceData: null|string|Record<string, any>;
instanceData: null | string | Record<string, any>;
editedListener: () => void;
valuechangeListener: () => void;
titleKey?: string;
isFormInModal?: boolean;
userContact?: Record<string, any>;
contactSummary? :Record<string, any>;
contactSummary?: Record<string, any>;

constructor(selector:string, type:string, formDoc:Record<string, any>, instanceData?) {
constructor(selector: string, type: string, formDoc: Record<string, any>, instanceData?) {
this.selector = selector;
this.type = type;
this.formDoc = formDoc;
Expand Down

0 comments on commit 76507a3

Please sign in to comment.