mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-13 21:24:58 +08:00
169 lines
5.3 KiB
JavaScript
169 lines
5.3 KiB
JavaScript
import React, { Component } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import ReactDOM from 'react-dom';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { Actions, AttachmentStore } from 'mailspring-exports';
|
|
import { ImageAttachmentItem } from 'mailspring-component-kit';
|
|
|
|
export default class InlineImageUploadContainer extends Component {
|
|
static displayName = 'InlineImageUploadContainer';
|
|
|
|
static supportsPreviewWithinEditor = false;
|
|
|
|
static propTypes = {
|
|
draft: PropTypes.object.isRequired,
|
|
fileId: PropTypes.string.isRequired,
|
|
session: PropTypes.object,
|
|
isPreview: PropTypes.bool,
|
|
};
|
|
|
|
_onGoEdit = () => {
|
|
if (!this.props.session) {
|
|
console.warn(
|
|
'InlineImage editor cannot be activated, `session` prop not present. (isPreview?)'
|
|
);
|
|
return;
|
|
}
|
|
// This is just a fun temporary hack because I was jealous of Apple Mail.
|
|
//
|
|
const el = ReactDOM.findDOMNode(this);
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
const editorEl = document.createElement('div');
|
|
editorEl.style.position = 'absolute';
|
|
editorEl.style.left = `${rect.left}px`;
|
|
editorEl.style.top = `${rect.top}px`;
|
|
editorEl.style.width = `${rect.width}px`;
|
|
editorEl.style.height = `${rect.height}px`;
|
|
editorEl.style.zIndex = 2000;
|
|
|
|
const editorCanvas = document.createElement('canvas');
|
|
editorCanvas.width = rect.width * window.devicePixelRatio;
|
|
editorCanvas.height = rect.height * window.devicePixelRatio;
|
|
editorCanvas.style.width = `${rect.width}px`;
|
|
editorCanvas.style.height = `${rect.height}px`;
|
|
editorEl.appendChild(editorCanvas);
|
|
|
|
const editorCtx = editorCanvas.getContext('2d');
|
|
editorCtx.drawImage(
|
|
el.querySelector('.file-preview img'),
|
|
0,
|
|
0,
|
|
editorCanvas.width,
|
|
editorCanvas.height
|
|
);
|
|
editorCtx.strokeStyle = '#df4b26';
|
|
editorCtx.lineJoin = 'round';
|
|
editorCtx.lineWidth = 3 * window.devicePixelRatio;
|
|
|
|
let penDown = false;
|
|
let penXY = null;
|
|
editorCanvas.addEventListener('mousedown', event => {
|
|
penDown = true;
|
|
penXY = {
|
|
x: event.offsetX,
|
|
y: event.offsetY,
|
|
};
|
|
});
|
|
editorCanvas.addEventListener('mousemove', event => {
|
|
if (penDown) {
|
|
const nextPenXY = {
|
|
x: event.offsetX,
|
|
y: event.offsetY,
|
|
};
|
|
editorCtx.beginPath();
|
|
editorCtx.moveTo(penXY.x * window.devicePixelRatio, penXY.y * window.devicePixelRatio);
|
|
editorCtx.lineTo(
|
|
nextPenXY.x * window.devicePixelRatio,
|
|
nextPenXY.y * window.devicePixelRatio
|
|
);
|
|
editorCtx.closePath();
|
|
editorCtx.stroke();
|
|
penXY = nextPenXY;
|
|
}
|
|
});
|
|
|
|
editorCanvas.addEventListener('mouseup', () => {
|
|
penDown = false;
|
|
penXY = null;
|
|
});
|
|
|
|
const backgroundEl = document.createElement('div');
|
|
backgroundEl.style.background = 'rgba(0,0,0,0.4)';
|
|
backgroundEl.style.position = 'absolute';
|
|
backgroundEl.style.top = '0px';
|
|
backgroundEl.style.left = '0px';
|
|
backgroundEl.style.right = '0px';
|
|
backgroundEl.style.bottom = '0px';
|
|
backgroundEl.style.zIndex = 1999;
|
|
backgroundEl.addEventListener('click', () => {
|
|
editorCanvas.toBlob(blob => {
|
|
const reader = new FileReader();
|
|
reader.addEventListener('loadend', () => {
|
|
const { draft, session, fileId } = this.props;
|
|
const buffer = new Buffer(new Uint8Array(reader.result));
|
|
const file = draft.files.find(u => u.id === fileId);
|
|
|
|
const filepath = AttachmentStore.pathForFile(file);
|
|
const nextFileName = `edited-${Date.now()}.png`;
|
|
const nextFilePath = path.join(path.dirname(filepath), nextFileName);
|
|
|
|
fs.writeFile(nextFilePath, buffer, err => {
|
|
if (err) {
|
|
AppEnv.showErrorDialog(err.toString());
|
|
return;
|
|
}
|
|
const img = el.querySelector('.file-preview img');
|
|
img.style.width = `${rect.width}px`;
|
|
img.style.height = `${rect.height}px`;
|
|
img.src = `${img.src}?${Date.now()}`;
|
|
|
|
fs.unlink(filepath, () => {});
|
|
|
|
const nextFiles = [].concat(draft.files);
|
|
nextFiles.forEach(f => {
|
|
if (f.id === file.id) {
|
|
f.filename = nextFileName;
|
|
}
|
|
});
|
|
session.changes.add({ files: nextFiles });
|
|
});
|
|
});
|
|
reader.readAsArrayBuffer(blob);
|
|
});
|
|
document.body.removeChild(editorEl);
|
|
document.body.removeChild(backgroundEl);
|
|
});
|
|
document.body.appendChild(backgroundEl);
|
|
document.body.appendChild(editorEl);
|
|
};
|
|
|
|
render() {
|
|
const { draft, fileId, isPreview } = this.props;
|
|
const file = draft.files.find(u => fileId === u.id);
|
|
|
|
if (!file) {
|
|
return <span />;
|
|
}
|
|
if (isPreview) {
|
|
return <img src={`cid:${file.contentId}`} alt={file.name} />;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
data-src={`cid:${file.contentId}`}
|
|
className="inline-image-upload-container"
|
|
onDoubleClick={this._onGoEdit}
|
|
>
|
|
<ImageAttachmentItem
|
|
className="file-upload"
|
|
draggable={false}
|
|
filePath={AttachmentStore.pathForFile(file)}
|
|
displayName={file.filename}
|
|
onRemoveAttachment={() => Actions.removeAttachment(draft.headerMessageId, file)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
}
|