зеркало из
https://github.com/rs-pro/activeadmin-quill_editor.git
synced 2026-09-07 20:15:51 +03:00
build: Update quill.imageUploader plugin
Этот коммит содержится в:
198
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
198
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
@@ -0,0 +1,198 @@
|
|||||||
|
import LoadingImage from "./blots/image.js";
|
||||||
|
|
||||||
|
class ImageUploader {
|
||||||
|
constructor(quill, options) {
|
||||||
|
this.quill = quill;
|
||||||
|
this.options = options;
|
||||||
|
this.range = null;
|
||||||
|
this.placeholderDelta = null;
|
||||||
|
|
||||||
|
if (typeof this.options.upload !== "function")
|
||||||
|
console.warn(
|
||||||
|
"[Missing config] upload function that returns a promise is required"
|
||||||
|
);
|
||||||
|
|
||||||
|
var toolbar = this.quill.getModule("toolbar");
|
||||||
|
if (toolbar) {
|
||||||
|
toolbar.addHandler("image", this.selectLocalImage.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleDrop = this.handleDrop.bind(this);
|
||||||
|
this.handlePaste = this.handlePaste.bind(this);
|
||||||
|
|
||||||
|
this.quill.root.addEventListener("drop", this.handleDrop, false);
|
||||||
|
this.quill.root.addEventListener("paste", this.handlePaste, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectLocalImage() {
|
||||||
|
this.quill.focus();
|
||||||
|
this.range = this.quill.getSelection();
|
||||||
|
this.fileHolder = document.createElement("input");
|
||||||
|
this.fileHolder.setAttribute("type", "file");
|
||||||
|
this.fileHolder.setAttribute("accept", "image/*");
|
||||||
|
this.fileHolder.setAttribute("style", "visibility:hidden");
|
||||||
|
|
||||||
|
this.fileHolder.onchange = this.fileChanged.bind(this);
|
||||||
|
|
||||||
|
document.body.appendChild(this.fileHolder);
|
||||||
|
|
||||||
|
this.fileHolder.click();
|
||||||
|
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
document.body.removeChild(this.fileHolder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDrop(evt) {
|
||||||
|
if (
|
||||||
|
evt.dataTransfer &&
|
||||||
|
evt.dataTransfer.files &&
|
||||||
|
evt.dataTransfer.files.length
|
||||||
|
) {
|
||||||
|
evt.stopPropagation();
|
||||||
|
evt.preventDefault();
|
||||||
|
if (document.caretRangeFromPoint) {
|
||||||
|
const selection = document.getSelection();
|
||||||
|
const range = document.caretRangeFromPoint(evt.clientX, evt.clientY);
|
||||||
|
if (selection && range) {
|
||||||
|
selection.setBaseAndExtent(
|
||||||
|
range.startContainer,
|
||||||
|
range.startOffset,
|
||||||
|
range.startContainer,
|
||||||
|
range.startOffset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const selection = document.getSelection();
|
||||||
|
const range = document.caretPositionFromPoint(evt.clientX, evt.clientY);
|
||||||
|
if (selection && range) {
|
||||||
|
selection.setBaseAndExtent(
|
||||||
|
range.offsetNode,
|
||||||
|
range.offset,
|
||||||
|
range.offsetNode,
|
||||||
|
range.offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.quill.focus();
|
||||||
|
this.range = this.quill.getSelection();
|
||||||
|
let file = evt.dataTransfer.files[0];
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.quill.focus();
|
||||||
|
this.range = this.quill.getSelection();
|
||||||
|
this.readAndUploadFile(file);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePaste(evt) {
|
||||||
|
let clipboard = evt.clipboardData || window.clipboardData;
|
||||||
|
|
||||||
|
// IE 11 is .files other browsers are .items
|
||||||
|
if (clipboard && (clipboard.items || clipboard.files)) {
|
||||||
|
let items = clipboard.items || clipboard.files;
|
||||||
|
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
if (IMAGE_MIME_REGEX.test(items[i].type)) {
|
||||||
|
let file = items[i].getAsFile ? items[i].getAsFile() : items[i];
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
this.quill.focus();
|
||||||
|
this.range = this.quill.getSelection();
|
||||||
|
evt.preventDefault();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.quill.focus();
|
||||||
|
this.range = this.quill.getSelection();
|
||||||
|
this.readAndUploadFile(file);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readAndUploadFile(file) {
|
||||||
|
let isUploadReject = false;
|
||||||
|
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
|
||||||
|
fileReader.addEventListener(
|
||||||
|
"load",
|
||||||
|
() => {
|
||||||
|
if (!isUploadReject) {
|
||||||
|
let base64ImageSrc = fileReader.result;
|
||||||
|
this.insertBase64Image(base64ImageSrc);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
fileReader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.upload(file).then(
|
||||||
|
(imageUrl) => {
|
||||||
|
this.insertToEditor(imageUrl);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
isUploadReject = true;
|
||||||
|
this.removeBase64Image();
|
||||||
|
console.warn(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileChanged() {
|
||||||
|
const file = this.fileHolder.files[0];
|
||||||
|
this.readAndUploadFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertBase64Image(url) {
|
||||||
|
const range = this.range;
|
||||||
|
|
||||||
|
this.placeholderDelta = this.quill.insertEmbed(
|
||||||
|
range.index,
|
||||||
|
LoadingImage.blotName,
|
||||||
|
`${url}`,
|
||||||
|
"user"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertToEditor(url) {
|
||||||
|
const range = this.range;
|
||||||
|
|
||||||
|
const lengthToDelete = this.calculatePlaceholderInsertLength();
|
||||||
|
|
||||||
|
// Delete the placeholder image
|
||||||
|
this.quill.deleteText(range.index, lengthToDelete, "user");
|
||||||
|
// Insert the server saved image
|
||||||
|
this.quill.insertEmbed(range.index, "image", `${url}`, "user");
|
||||||
|
|
||||||
|
range.index++;
|
||||||
|
this.quill.setSelection(range, "user");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The length of the insert delta from insertBase64Image can vary depending on what part of the line the insert occurs
|
||||||
|
calculatePlaceholderInsertLength() {
|
||||||
|
return this.placeholderDelta.ops.reduce((accumulator, deltaOperation) => {
|
||||||
|
if (deltaOperation.hasOwnProperty('insert'))
|
||||||
|
accumulator++;
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBase64Image() {
|
||||||
|
const range = this.range;
|
||||||
|
const lengthToDelete = this.calculatePlaceholderInsertLength();
|
||||||
|
|
||||||
|
this.quill.deleteText(range.index, lengthToDelete, "user");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ImageUploader = ImageUploader;
|
||||||
|
export default ImageUploader;
|
||||||
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
33
app/assets/stylesheets/activeadmin/quill.imageUploader.css
Обычный файл
33
app/assets/stylesheets/activeadmin/quill.imageUploader.css
Обычный файл
@@ -0,0 +1,33 @@
|
|||||||
|
.image-uploading {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-uploading img {
|
||||||
|
max-width: 98% !important;
|
||||||
|
filter: blur(5px);
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-uploading::before {
|
||||||
|
content: "";
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin-top: -15px;
|
||||||
|
margin-left: -15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid #ccc;
|
||||||
|
border-top-color: #1e986c;
|
||||||
|
z-index: 1;
|
||||||
|
animation: spinner 0.6s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,12 @@ wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.css" -O "app/assets/s
|
|||||||
|
|
||||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.js"
|
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.js"
|
||||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.core.js"
|
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.core.js"
|
||||||
|
|
||||||
|
wget "https://github.com/NoelOConnell/quill-image-uploader/raw/refs/heads/master/src/quill.imageUploader.js" -O "app/assets/javascripts/activeadmin/quill.imageUploader.js"
|
||||||
|
wget "https://github.com/NoelOConnell/quill-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.js" -O "app/assets/javascripts/activeadmin/quill.imageUploader.min.js"
|
||||||
|
|
||||||
|
wget "https://github.com/NoelOConnell/quill-image-uploader/raw/refs/heads/master/src/quill.imageUploader.css" -O "app/assets/stylesheets/activeadmin/quill.imageUploader.css"
|
||||||
|
wget "https://github.com/NoelOConnell/quill-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.css" -O "app/assets/stylesheets/activeadmin/quill.imageUploader.min.css"
|
||||||
```
|
```
|
||||||
|
|
||||||
- Check the changes, most of them should be for updated files plus some new / removed file
|
- Check the changes, most of them should be for updated files plus some new / removed file
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user