diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/mail/static/src/components/file_uploader/file_uploader.js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mail/static/src/components/file_uploader/file_uploader.js')
| -rw-r--r-- | addons/mail/static/src/components/file_uploader/file_uploader.js | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/file_uploader/file_uploader.js b/addons/mail/static/src/components/file_uploader/file_uploader.js new file mode 100644 index 00000000..4e57eadd --- /dev/null +++ b/addons/mail/static/src/components/file_uploader/file_uploader.js @@ -0,0 +1,241 @@ +odoo.define('mail/static/src/components/file_uploader/file_uploader.js', function (require) { +'use strict'; + +const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js'); + +const core = require('web.core'); + +const { Component } = owl; +const { useRef } = owl.hooks; + +class FileUploader extends Component { + + /** + * @override + */ + constructor(...args) { + super(...args); + this._fileInputRef = useRef('fileInput'); + this._fileUploadId = _.uniqueId('o_FileUploader_fileupload'); + this._onAttachmentUploaded = this._onAttachmentUploaded.bind(this); + useShouldUpdateBasedOnProps({ + compareDepth: { + attachmentLocalIds: 1, + newAttachmentExtraData: 3, + }, + }); + } + + mounted() { + $(window).on(this._fileUploadId, this._onAttachmentUploaded); + } + + willUnmount() { + $(window).off(this._fileUploadId); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @param {FileList|Array} files + * @returns {Promise} + */ + async uploadFiles(files) { + await this._unlinkExistingAttachments(files); + this._createTemporaryAttachments(files); + await this._performUpload(files); + this._fileInputRef.el.value = ''; + } + + openBrowserFileUploader() { + this._fileInputRef.el.click(); + } + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @deprecated + * @private + * @param {Object} fileData + * @returns {mail.attachment} + */ + _createAttachment(fileData) { + return this.env.models['mail.attachment'].create(Object.assign( + {}, + fileData, + this.props.newAttachmentExtraData + )); + } + + /** + * @private + * @param {File} file + * @returns {FormData} + */ + _createFormData(file) { + let formData = new window.FormData(); + formData.append('callback', this._fileUploadId); + formData.append('csrf_token', core.csrf_token); + formData.append('id', this.props.uploadId); + formData.append('model', this.props.uploadModel); + formData.append('ufile', file, file.name); + return formData; + } + + /** + * @private + * @param {FileList|Array} files + */ + _createTemporaryAttachments(files) { + for (const file of files) { + this.env.models['mail.attachment'].create( + Object.assign( + { + filename: file.name, + isTemporary: true, + name: file.name + }, + this.props.newAttachmentExtraData + ), + ); + } + } + /** + * @private + * @param {FileList|Array} files + * @returns {Promise} + */ + async _performUpload(files) { + for (const file of files) { + const uploadingAttachment = this.env.models['mail.attachment'].find(attachment => + attachment.isTemporary && + attachment.filename === file.name + ); + if (!uploadingAttachment) { + // Uploading attachment no longer exists. + // This happens when an uploading attachment is being deleted by user. + continue; + } + try { + const response = await this.env.browser.fetch('/web/binary/upload_attachment', { + method: 'POST', + body: this._createFormData(file), + signal: uploadingAttachment.uploadingAbortController.signal, + }); + let html = await response.text(); + const template = document.createElement('template'); + template.innerHTML = html.trim(); + window.eval(template.content.firstChild.textContent); + } catch (e) { + if (e.name !== 'AbortError') { + throw e; + } + } + } + } + + /** + * @private + * @param {FileList|Array} files + * @returns {Promise} + */ + async _unlinkExistingAttachments(files) { + for (const file of files) { + const attachment = this.props.attachmentLocalIds + .map(attachmentLocalId => this.env.models['mail.attachment'].get(attachmentLocalId)) + .find(attachment => attachment.name === file.name && attachment.size === file.size); + // if the files already exits, delete the file before upload + if (attachment) { + attachment.remove(); + } + } + } + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @private + * @param {jQuery.Event} ev + * @param {...Object} filesData + */ + async _onAttachmentUploaded(ev, ...filesData) { + for (const fileData of filesData) { + const { error, filename, id, mimetype, name, size } = fileData; + if (error || !id) { + this.env.services['notification'].notify({ + type: 'danger', + message: owl.utils.escape(error), + }); + const relatedTemporaryAttachments = this.env.models['mail.attachment'] + .find(attachment => + attachment.filename === filename && + attachment.isTemporary + ); + for (const attachment of relatedTemporaryAttachments) { + attachment.delete(); + } + return; + } + // FIXME : needed to avoid problems on uploading + // Without this the useStore selector of component could be not called + // E.g. in attachment_box_tests.js + await new Promise(resolve => setTimeout(resolve)); + const attachment = this.env.models['mail.attachment'].insert( + Object.assign( + { + filename, + id, + mimetype, + name, + size, + }, + this.props.newAttachmentExtraData + ), + ); + this.trigger('o-attachment-created', { attachment }); + } + } + + /** + * Called when there are changes in the file input. + * + * @private + * @param {Event} ev + * @param {EventTarget} ev.target + * @param {FileList|Array} ev.target.files + */ + async _onChangeAttachment(ev) { + await this.uploadFiles(ev.target.files); + } + +} + +Object.assign(FileUploader, { + defaultProps: { + uploadId: 0, + uploadModel: 'mail.compose.message' + }, + props: { + attachmentLocalIds: { + type: Array, + element: String, + }, + newAttachmentExtraData: { + type: Object, + optional: true, + }, + uploadId: Number, + uploadModel: String, + }, + template: 'mail.FileUploader', +}); + +return FileUploader; + +}); |
