Commit 1bbf9af7 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch '26113-webide-upload-encoding' into 'master'

Web IDE: Fix encoding issues when uploading

See merge request gitlab-org/gitlab!23761
parents d2820293 f4fced86
...@@ -43,21 +43,28 @@ export default { ...@@ -43,21 +43,28 @@ export default {
}, },
createFile(target, file) { createFile(target, file) {
const { name } = file; const { name } = file;
let { result } = target; const encodedContent = target.result.split('base64,')[1];
const encodedContent = result.split('base64,')[1];
const rawContent = encodedContent ? atob(encodedContent) : ''; const rawContent = encodedContent ? atob(encodedContent) : '';
const isText = this.isText(rawContent, file.type); const isText = this.isText(rawContent, file.type);
result = isText ? rawContent : encodedContent; const emitCreateEvent = content =>
this.$emit('create', { this.$emit('create', {
name: `${this.path ? `${this.path}/` : ''}${name}`, name: `${this.path ? `${this.path}/` : ''}${name}`,
type: 'blob', type: 'blob',
content: result, content,
base64: !isText, base64: !isText,
binary: !isText, binary: !isText,
rawPath: !isText ? target.result : '', rawPath: !isText ? target.result : '',
}); });
if (isText) {
const reader = new FileReader();
reader.addEventListener('load', e => emitCreateEvent(e.target.result), { once: true });
reader.readAsText(file);
} else {
emitCreateEvent(encodedContent);
}
}, },
readFile(file) { readFile(file) {
const reader = new FileReader(); const reader = new FileReader();
......
...@@ -13,6 +13,11 @@ export default { ...@@ -13,6 +13,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
filePath: {
type: String,
required: false,
default: '',
},
fileSize: { fileSize: {
type: Number, type: Number,
required: false, required: false,
...@@ -24,7 +29,8 @@ export default { ...@@ -24,7 +29,8 @@ export default {
return numberToHumanSize(this.fileSize); return numberToHumanSize(this.fileSize);
}, },
fileName() { fileName() {
return this.path.split('/').pop(); // path could be a base64 uri too, so check if filePath was passed additionally
return (this.filePath || this.path).split('/').pop();
}, },
}, },
}; };
...@@ -39,7 +45,13 @@ export default { ...@@ -39,7 +45,13 @@ export default {
({{ fileSizeReadable }}) ({{ fileSizeReadable }})
</template> </template>
</p> </p>
<gl-link :href="path" class="btn btn-default" rel="nofollow" download target="_blank"> <gl-link
:href="path"
class="btn btn-default"
rel="nofollow"
:download="fileName"
target="_blank"
>
<icon :size="16" name="download" class="float-left append-right-8" /> <icon :size="16" name="download" class="float-left append-right-8" />
{{ __('Download') }} {{ __('Download') }}
</gl-link> </gl-link>
......
---
title: Fix some of the file encoding issues when uploading in the Web IDE
merge_request: 23761
author:
type: fixed
...@@ -14,7 +14,7 @@ describe('new dropdown upload', () => { ...@@ -14,7 +14,7 @@ describe('new dropdown upload', () => {
vm.entryName = 'testing'; vm.entryName = 'testing';
spyOn(vm, '$emit'); spyOn(vm, '$emit').and.callThrough();
}); });
afterEach(() => { afterEach(() => {
...@@ -61,18 +61,26 @@ describe('new dropdown upload', () => { ...@@ -61,18 +61,26 @@ describe('new dropdown upload', () => {
const binaryTarget = { const binaryTarget = {
result: 'base64,w4I=', result: 'base64,w4I=',
}; };
const textFile = { const textFile = new File(['plain text'], 'textFile');
name: 'textFile',
type: 'text/plain',
};
const binaryFile = { const binaryFile = {
name: 'binaryFile', name: 'binaryFile',
type: 'image/png', type: 'image/png',
}; };
it('creates file in plain text (without encoding) if the file content is plain text', () => { beforeEach(() => {
spyOn(FileReader.prototype, 'readAsText').and.callThrough();
});
it('calls readAsText and creates file in plain text (without encoding) if the file content is plain text', done => {
const waitForCreate = new Promise(resolve => vm.$on('create', resolve));
vm.createFile(textTarget, textFile); vm.createFile(textTarget, textFile);
expect(FileReader.prototype.readAsText).toHaveBeenCalledWith(textFile);
waitForCreate
.then(() => {
expect(vm.$emit).toHaveBeenCalledWith('create', { expect(vm.$emit).toHaveBeenCalledWith('create', {
name: textFile.name, name: textFile.name,
type: 'blob', type: 'blob',
...@@ -81,11 +89,16 @@ describe('new dropdown upload', () => { ...@@ -81,11 +89,16 @@ describe('new dropdown upload', () => {
binary: false, binary: false,
rawPath: '', rawPath: '',
}); });
})
.then(done)
.catch(done.fail);
}); });
it('splits content on base64 if binary', () => { it('splits content on base64 if binary', () => {
vm.createFile(binaryTarget, binaryFile); vm.createFile(binaryTarget, binaryFile);
expect(FileReader.prototype.readAsText).not.toHaveBeenCalledWith(textFile);
expect(vm.$emit).toHaveBeenCalledWith('create', { expect(vm.$emit).toHaveBeenCalledWith('create', {
name: binaryFile.name, name: binaryFile.name,
type: 'blob', type: 'blob',
......
...@@ -58,14 +58,34 @@ describe('ContentViewer', () => { ...@@ -58,14 +58,34 @@ describe('ContentViewer', () => {
it('renders fallback download control', done => { it('renders fallback download control', done => {
createComponent({ createComponent({
path: 'test.abc', path: 'somepath/test.abc',
fileSize: 1024, fileSize: 1024,
}); });
setTimeout(() => { setTimeout(() => {
expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain('test.abc'); expect(
expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain('(1.00 KiB)'); vm.$el
expect(vm.$el.querySelector('.btn.btn-default').textContent.trim()).toContain('Download'); .querySelector('.file-info')
.textContent.trim()
.replace(/\s+/, ' '),
).toEqual('test.abc (1.00 KiB)');
expect(vm.$el.querySelector('.btn.btn-default').textContent.trim()).toEqual('Download');
done();
});
});
it('renders fallback download control for file with a data URL path properly', done => {
createComponent({
path: 'data:application/octet-stream;base64,U0VMRUNUICfEhHNnc2cnIGZyb20gVGFibGVuYW1lOwoK',
filePath: 'somepath/test.abc',
});
setTimeout(() => {
expect(vm.$el.querySelector('.file-info').textContent.trim()).toEqual('test.abc');
expect(vm.$el.querySelector('.btn.btn-default')).toHaveAttr('download', 'test.abc');
expect(vm.$el.querySelector('.btn.btn-default').textContent.trim()).toEqual('Download');
done(); done();
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment