js-draw
Version:
Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.
127 lines (126 loc) • 5.02 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const TextComponent_1 = __importDefault(require("../components/TextComponent"));
const SVGLoader_1 = __importDefault(require("../SVGLoader/SVGLoader"));
const math_1 = require("@js-draw/math");
const BaseTool_1 = __importDefault(require("./BaseTool"));
const TextTool_1 = __importDefault(require("./TextTool"));
const ImageComponent_1 = __importDefault(require("../components/ImageComponent"));
/**
* A tool that handles paste events (e.g. as triggered by ctrl+V).
*
* @example
* While `ToolController` has a `PasteHandler` in its default list of tools,
* if a non-default set is being used, `PasteHandler` can be added as follows:
* ```ts
* const toolController = editor.toolController;
* toolController.addTool(new PasteHandler(editor));
* ```
*/
class PasteHandler extends BaseTool_1.default {
constructor(editor) {
super(editor.notifier, editor.localization.pasteHandler);
this.editor = editor;
}
// @internal
onPaste(event, onComplete) {
const mime = event.mime.toLowerCase();
const svgData = (() => {
if (mime === 'image/svg+xml') {
return event.data;
}
// In some environments, it isn't possible to write non-text data to the
// clipboard. To support these cases, auto-detect text/plain SVG data.
if (mime === 'text/plain') {
const trimmedData = event.data.trim();
if (trimmedData.startsWith('<svg') && trimmedData.endsWith('</svg>')) {
return trimmedData;
}
}
if (mime !== 'text/html') {
return false;
}
// text/html is sometimes handlable SVG data. Use a hueristic
// to determine if this is the case:
// We use [^] and not . so that newlines are included.
const match = event.data.match(/^[^]{0,200}<svg.*/i); // [^]{0,200} <- Allow for metadata near start
if (!match) {
return false;
}
// Extract the SVG element from the pasted data
let svgEnd = event.data.toLowerCase().lastIndexOf('</svg>');
if (svgEnd === -1)
svgEnd = event.data.length;
return event.data.substring(event.data.search(/<svg/i), svgEnd);
})();
if (svgData) {
void this.doSVGPaste(svgData).then(onComplete);
return true;
}
else if (mime === 'text/plain') {
void this.doTextPaste(event.data).then(onComplete);
return true;
}
else if (mime === 'image/png' || mime === 'image/jpeg') {
void this.doImagePaste(event.data).then(onComplete);
return true;
}
return false;
}
async addComponentsFromPaste(components) {
await this.editor.addAndCenterComponents(components, true, this.editor.localization.pasted(components.length));
}
async doSVGPaste(data) {
this.editor.showLoadingWarning(0);
try {
const loader = SVGLoader_1.default.fromString(data, {
sanitize: true,
plugins: this.editor.getCurrentSettings().svg?.loaderPlugins ?? [],
});
const components = [];
await loader.start((component) => {
components.push(component);
}, (_countProcessed, _totalToProcess) => null);
await this.addComponentsFromPaste(components);
}
finally {
this.editor.hideLoadingWarning();
}
}
async doTextPaste(text) {
const textTools = this.editor.toolController.getMatchingTools(TextTool_1.default);
textTools.sort((a, b) => {
if (!a.isEnabled() && b.isEnabled()) {
return -1;
}
if (!b.isEnabled() && a.isEnabled()) {
return 1;
}
return 0;
});
const defaultTextStyle = {
size: 12,
fontFamily: 'sans',
renderingStyle: { fill: math_1.Color4.red },
};
const pastedTextStyle = textTools[0]?.getTextStyle() ?? defaultTextStyle;
// Don't paste text that would be invisible.
if (text.trim() === '') {
return;
}
const lines = text.split('\n');
await this.addComponentsFromPaste([
TextComponent_1.default.fromLines(lines, math_1.Mat33.identity, pastedTextStyle),
]);
}
async doImagePaste(dataURL) {
const image = new Image();
image.src = dataURL;
const component = await ImageComponent_1.default.fromImage(image, math_1.Mat33.identity);
await this.addComponentsFromPaste([component]);
}
}
exports.default = PasteHandler;
;