Skip to content

Instantly share code, notes, and snippets.

@macrozone
Last active May 31, 2017 22:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save macrozone/b2207c19aed0838d5982a09a5399dcae to your computer and use it in GitHub Desktop.
Save macrozone/b2207c19aed0838d5982a09a5399dcae to your computer and use it in GitHub Desktop.
File-filed with uniforms and ostrio:files in meteor
import React from 'react';
import { connectField } from 'uniforms';
import Dropzone from 'react-dropzone';
import withMeteorUploader from '../../hocs/with_meteor_uploader';
import CollectionImage from '/client/modules/core/containers/collection_image';
export const ImageFile = ({
disabled,
id,
label,
uploadFile,
uploadProgress,
uploadState,
uploadError,
name,
onChange,
placeholder,
hintText,
hintTitle,
value,
...props,
}) => {
const onDrop = (files) => {
// only take one
const file = files[0];
uploadFile(file, (error, file) => {
if (error) {
console.error(error);
} else {
onChange(file._id);
}
});
};
return (
<div>
{label && (
<span>{label}</span>
)}
<div>
<Dropzone onDrop={onDrop}>
{uploadState === 'uploading' ?
<div>Uploading... {uploadProgress}</div> :
<div>
{value ? <CollectionImage aspectRatio={aspectRatio} imageId={value} /> : null}
</div>
}
</Dropzone>
{uploadError ? <p>{uploadError.message}</p> : null}
</div>
</div>
);
});
export default connectField(withMeteorUploader(ImageFile));
import { Meteor } from 'meteor/meteor';
if (Meteor.isClient) {
require('blueimp-canvas-to-blob'); // polyfill
}
export default (file, { maxDimension = 640, quality = 0.6 } = {}, onResult) => {
// thx http://stackoverflow.com/questions/23945494/use-html5-to-resize-an-image-before-upload
// Load the image
const reader = new global.FileReader();
reader.onload = function (readerEvent) {
const image = new global.Image();
image.onload = function (imageEvent) {
// Resize the image
const canvas = global.document.createElement('canvas');
let width = image.width;
let height = image.height;
if (width > height) {
if (width > maxDimension) {
height *= maxDimension / width;
width = maxDimension;
}
} else if (height > maxDimension) {
width *= maxDimension / height;
height = maxDimension;
}
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
canvas.toBlob((blob) => {
onResult(null, blob);
}, 'image/jpeg', quality);
};
image.src = readerEvent.target.result;
};
reader.readAsDataURL(file);
};
import { useDeps, composeAll, composeWithTracker, compose } from 'mantra-core';
import { withState } from 'recompose';
import resize from '/manul-files/resize';
import _ from 'lodash';
const RESIZABLE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'];
const RESIZE_OPTIONS = {
maxDimension: 720,
quality: 0.8,
};
export const composer = ({ context, imageId, setUploadState, setUploadError, setUploadProgress, directiveName }, onData) => {
const { Collections: { Images } } = context();
const shouldResize = ({ size, type }) => {
if (Images.MAX_SIZE * 1024 >= size) {
return false;
}
if (_.includes(RESIZABLE_MIME_TYPES, type)) {
return true;
}
return false;
};
const upload = (file, onUploadDone) => {
const uploader = Images.insert({
file,
meta: { directiveName },
streams: 'dynamic',
chunkSize: 'dynamic',
}, false);
uploader.on('progress', (progress) => {
setUploadProgress(progress);
});
uploader.on('end', (error, result) => {
setUploadState(null);
setUploadError(error);
onUploadDone(error, result);
});
uploader.on('start', () => {
setUploadState('uploading');
});
uploader.start();
};
const uploadFile = (file, onUploadDone) => {
if (shouldResize(file)) {
resize(file, RESIZE_OPTIONS, (error, fileResized) => {
if (!error) {
fileResized.name = file.name + '.jpg';
upload(fileResized, onUploadDone);
} else {
onUploadDone(error);
}
});
} else {
upload(file, onUploadDone);
}
};
onData(null, { uploadFile, maxSize: Images.MAX_SIZE });
};
export const depsMapper = (context, actions) => ({
context: () => context,
});
export default C => composeAll(
compose(composer),
withState('uploadError', 'setUploadError', null),
withState('uploadProgress', 'setUploadProgress', 0),
withState('uploadState', 'setUploadState', null),
useDeps(depsMapper)
)(C);
@macrozone
Copy link
Author

macrozone commented Dec 30, 2016

withMeteorUploader is a hoc (higher order component) that injects properties to the wrapped component:

  • uploadError (string)
  • uploadProgress (percent)
  • uploadState (string)
  • uploadFile (function to upload: uploadFile(file, callback)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment