mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
feat: attachment download & progress from editor
This commit is contained in:
@@ -124,6 +124,9 @@ function init_tiny(size) {
|
||||
directionality: EDITOR_SETTINGS.directionality,
|
||||
skin_url: 'dist/skins/notesnook',
|
||||
content_css: 'dist/skins/notesnook',
|
||||
attachmenthandler_download_attachment:(hash) => {
|
||||
reactNativeEventHandler('attachment_download',hash);
|
||||
},
|
||||
plugins: [
|
||||
'checklist advlist autolink textpattern hr lists link noneditable image',
|
||||
'searchreplace codeblock inlinecode keyboardquirks attachmentshandler',
|
||||
@@ -177,24 +180,6 @@ function init_tiny(size) {
|
||||
.h {
|
||||
display: none;
|
||||
}
|
||||
.img_float_left {
|
||||
float:left;
|
||||
}
|
||||
.img_float_right {
|
||||
float:right;
|
||||
}
|
||||
.img_float_none {
|
||||
float:none;
|
||||
}
|
||||
.img_size_one {
|
||||
width:100%;
|
||||
}
|
||||
.img_size_two {
|
||||
width:50%;
|
||||
}
|
||||
.img_size_three {
|
||||
width:25%;
|
||||
}
|
||||
span.diff-del {
|
||||
background-color: #FDB0C0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
import {Platform, ScrollView, Text, View} from 'react-native';
|
||||
import {Platform, TouchableOpacity, View} from 'react-native';
|
||||
import {FlatList} from 'react-native-gesture-handler';
|
||||
import * as Progress from 'react-native-progress';
|
||||
import * as ScopedStorage from 'react-native-scoped-storage';
|
||||
import Sodium from 'react-native-sodium';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import {useTracked} from '../../provider';
|
||||
import {useAttachmentStore} from '../../provider/stores';
|
||||
@@ -12,24 +15,15 @@ import {
|
||||
import {db} from '../../utils/database';
|
||||
import {
|
||||
eCloseAttachmentDialog,
|
||||
eCloseTagsDialog,
|
||||
eOpenAttachmentsDialog,
|
||||
eOpenTagsDialog
|
||||
eOpenAttachmentsDialog
|
||||
} from '../../utils/Events';
|
||||
import filesystem from '../../utils/filesystem';
|
||||
import {SIZE} from '../../utils/SizeUtils';
|
||||
import {sleep} from '../../utils/TimeUtils';
|
||||
import Storage from '../../utils/storage';
|
||||
import {ActionIcon} from '../ActionIcon';
|
||||
import ActionSheetWrapper from '../ActionSheetComponent/ActionSheetWrapper';
|
||||
import DialogHeader from '../Dialog/dialog-header';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import * as Progress from 'react-native-progress';
|
||||
import filesystem from '../../utils/filesystem';
|
||||
import * as ScopedStorage from 'react-native-scoped-storage';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import Sodium from 'react-native-sodium';
|
||||
import Storage from '../../utils/storage';
|
||||
|
||||
export const AttachmentDialog = () => {
|
||||
const [state] = useTracked();
|
||||
@@ -142,7 +136,6 @@ const Attachment = ({attachment, note, setNote}) => {
|
||||
const [state] = useTracked();
|
||||
const colors = state.colors;
|
||||
const progress = useAttachmentStore(state => state.progress);
|
||||
const setProgress = useAttachmentStore(state => state.setProgress);
|
||||
const [currentProgress, setCurrentProgress] = useState(null);
|
||||
|
||||
const onPress = async () => {
|
||||
@@ -151,57 +144,22 @@ const Attachment = ({attachment, note, setNote}) => {
|
||||
useAttachmentStore.getState().remove(attachment.metadata.hash);
|
||||
return;
|
||||
}
|
||||
|
||||
let folder = {};
|
||||
if (Platform.OS === 'android') {
|
||||
folder = await ScopedStorage.openDocumentTree(false);
|
||||
if (!folder) return;
|
||||
} else {
|
||||
folder.uri = await Storage.checkAndCreateDir('/Downloads/');
|
||||
}
|
||||
|
||||
try {
|
||||
setCurrentProgress({
|
||||
value: 0,
|
||||
percent: '0%'
|
||||
});
|
||||
await db.fs.downloadFile(
|
||||
attachment.metadata.hash,
|
||||
attachment.metadata.hash
|
||||
);
|
||||
let key = await db.user.getEncryptionKey();
|
||||
let info = {
|
||||
iv: attachment.iv,
|
||||
salt: attachment.salt,
|
||||
length: attachment.length,
|
||||
alg: attachment.alg,
|
||||
hash: attachment.metadata.hash,
|
||||
hashType: attachment.metadata.hashType,
|
||||
mime: attachment.metadata.type,
|
||||
fileName: attachment.metadata.filename,
|
||||
uri: folder.uri
|
||||
};
|
||||
await Sodium.decryptFile(key, info, false);
|
||||
ToastEvent.show({
|
||||
heading: 'Download successful',
|
||||
message: attachment.metadata.filename + 'downloaded',
|
||||
type: 'success',
|
||||
context: 'local'
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('download attachment error: ', e);
|
||||
useAttachmentStore.getState().remove(attachment.metadata.hash);
|
||||
}
|
||||
filesystem.downloadAttachment(attachment.metadata.hash);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let prog = progress[attachment.metadata.hash];
|
||||
if (prog && prog.type === 'download') {
|
||||
prog = prog.recieved / prog.total;
|
||||
if (prog) {
|
||||
let type = prog.type;
|
||||
let loaded = prog.type === 'download' ? prog.recieved : prog.sent;
|
||||
prog = loaded / prog.total;
|
||||
prog = (prog * 100).toFixed(0);
|
||||
console.log('progress: ', prog);
|
||||
console.log(prog);
|
||||
setCurrentProgress({
|
||||
value: prog,
|
||||
percent: prog + '%'
|
||||
percent: prog + '%',
|
||||
type: type
|
||||
});
|
||||
} else {
|
||||
setCurrentProgress(null);
|
||||
@@ -263,30 +221,38 @@ const Attachment = ({attachment, note, setNote}) => {
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph color={colors.icon} size={SIZE.xs}>
|
||||
{formatBytes(attachment.length)} ({attachment.metadata.type})
|
||||
{formatBytes(attachment.length)}{' '}
|
||||
{currentProgress?.type ? '(' + currentProgress.type + 'ing - tap to cancel)' : ''}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{currentProgress ? (
|
||||
<View
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.9}
|
||||
onPress={() => {
|
||||
db.fs.cancel(attachment.metadata.hash);
|
||||
setCurrentProgress(null);
|
||||
}}
|
||||
style={{
|
||||
justifyContent: 'center',
|
||||
marginLeft: 5
|
||||
marginLeft: 5,
|
||||
marginTop:5,
|
||||
marginRight:-5
|
||||
}}>
|
||||
<Progress.Circle
|
||||
size={SIZE.xxl}
|
||||
progress={currentProgress?.value ? currentProgress?.value / 100 : 0}
|
||||
showsText
|
||||
textStyle={{
|
||||
fontSize: 9
|
||||
fontSize: 10
|
||||
}}
|
||||
color={colors.accent}
|
||||
formatText={progress => (progress * 100).toFixed(0)}
|
||||
borderWidth={0}
|
||||
thickness={2}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<ActionIcon
|
||||
onPress={() => onPress(attachment)}
|
||||
|
||||
@@ -158,11 +158,10 @@ interface AttachmentStore {
|
||||
hash: string,
|
||||
recieved: number,
|
||||
type: "upload" | "download",
|
||||
success: boolean
|
||||
}
|
||||
},
|
||||
remove:(hash:string) => void
|
||||
setProgress: (sent: number, total: number, hash: string, recieved: number, type: "upload" | "download", success) => void
|
||||
setProgress: (sent: number, total: number, hash: string, recieved: number, type: "upload" | "download") => void
|
||||
}
|
||||
|
||||
export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
|
||||
@@ -170,11 +169,20 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
|
||||
remove:(hash) => {
|
||||
let _p = get().progress;
|
||||
_p[hash] = null
|
||||
tiny.call(EditorWebView, `
|
||||
(function() {
|
||||
let progress = ${JSON.stringify({
|
||||
loaded:1,
|
||||
total:1,
|
||||
hash
|
||||
})}
|
||||
tinymce.activeEditor.execCommand("mceUpdateAttachmentProgress",progress);
|
||||
})()`);
|
||||
set({ progress: { ..._p } });
|
||||
},
|
||||
setProgress: (sent, total, hash, recieved, type, success) => {
|
||||
setProgress: (sent, total, hash, recieved, type) => {
|
||||
let _p = get().progress;
|
||||
_p[hash] = { sent, total, hash, recieved, type, success };
|
||||
_p[hash] = { sent, total, hash, recieved, type };
|
||||
let progress = { total, hash, loaded: type === "download" ? recieved : sent };
|
||||
tiny.call(EditorWebView, `
|
||||
(function() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -19,6 +19,7 @@ import {
|
||||
eShowGetPremium,
|
||||
eShowMergeDialog
|
||||
} from '../../utils/Events';
|
||||
import filesystem from '../../utils/filesystem';
|
||||
import {openLinkInBrowser} from '../../utils/functions';
|
||||
import {MMKV} from '../../utils/mmkv';
|
||||
import {tabBarRef} from '../../utils/Refs';
|
||||
@@ -31,6 +32,7 @@ export const editorTitleInput = createRef();
|
||||
export const sourceUri =
|
||||
Platform.OS === 'android' ? 'file:///android_asset/' : 'Web.bundle/site/';
|
||||
|
||||
let lastEditTime = 0;
|
||||
let EDITOR_SETTINGS = null;
|
||||
let webviewOK = true;
|
||||
let noteEdited = false;
|
||||
@@ -153,6 +155,7 @@ async function setNote(item) {
|
||||
title = note.title;
|
||||
id = note.id;
|
||||
noteEdited = false;
|
||||
lastEditTime = item.dateEdited;
|
||||
if (note.locked) {
|
||||
content.data = note.content.data;
|
||||
content.type = note.content.type;
|
||||
@@ -188,6 +191,7 @@ export const loadNote = async item => {
|
||||
console.log('.....OPEN NOTE.....');
|
||||
editing.currentlyEditing = true;
|
||||
editing.movedAway = false;
|
||||
|
||||
if (editing.isFocused) {
|
||||
tiny.call(EditorWebView, tiny.blur);
|
||||
}
|
||||
@@ -197,6 +201,7 @@ export const loadNote = async item => {
|
||||
await clearEditor(true, true, true);
|
||||
}
|
||||
disableSaving = false;
|
||||
lastEditTime = 0;
|
||||
clearNote();
|
||||
noteEdited = false;
|
||||
isFirstLoad = false;
|
||||
@@ -274,7 +279,6 @@ const checkStatus = async noreset => {
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
let lastEditTime = 0;
|
||||
|
||||
export const _onMessage = async evt => {
|
||||
if (!evt || !evt.nativeEvent || !evt.nativeEvent.data) return;
|
||||
@@ -303,7 +307,6 @@ export const _onMessage = async evt => {
|
||||
case 'title':
|
||||
if (message.value !== title) {
|
||||
noteEdited = true;
|
||||
|
||||
lastEditTime = Date.now();
|
||||
title = message.value;
|
||||
eSendEvent('editorScroll', {
|
||||
@@ -315,6 +318,9 @@ export const _onMessage = async evt => {
|
||||
case 'scroll':
|
||||
eSendEvent('editorScroll', message);
|
||||
break;
|
||||
case 'attachment_download':
|
||||
filesystem.downloadAttachment(message.value);
|
||||
break;
|
||||
case 'noteLoaded':
|
||||
tiny.call(EditorWebView, tiny.notLoading);
|
||||
eSendEvent('loadingNote');
|
||||
@@ -611,6 +617,7 @@ export async function saveNote(preventUpdate) {
|
||||
Navigation.routeNames.Notes
|
||||
]);
|
||||
let n = db.notes.note(id)?.data?.dateEdited;
|
||||
lastEditTime = n + 10;
|
||||
tiny.call(EditorWebView, tiny.updateDateEdited(timeConverter(n)));
|
||||
tiny.call(EditorWebView, tiny.updateSavingState('Saved'));
|
||||
}
|
||||
@@ -678,16 +685,28 @@ export async function updateNoteInEditor() {
|
||||
presentResolveConflictDialog(_note);
|
||||
return;
|
||||
}
|
||||
let data = await db.content.raw(note.contentId);
|
||||
let data = await db.content.raw(_note.contentId);
|
||||
if (lastEditTime > _note.dateEdited) return;
|
||||
if (data.data === content.data) return;
|
||||
if (content.data.indexOf(data.data) !== -1) return;
|
||||
if (note.dateEdited === _note.dateEdited) return;
|
||||
|
||||
console.log('injecting note in editor', lastEditTime, _note.dateEdited);
|
||||
title = note.title;
|
||||
content.data = data.data;
|
||||
note = _note;
|
||||
lastEditTime = _note.dateEdited + 10;
|
||||
tiny.call(EditorWebView, tiny.isLoading);
|
||||
await setNote(_note);
|
||||
tiny.call(EditorWebView, tiny.isLoading);
|
||||
post('title', title);
|
||||
post('inject', content.data);
|
||||
setTimeout(() => {
|
||||
tiny.call(EditorWebView, tiny.notLoading);
|
||||
}, 50);
|
||||
if (id) {
|
||||
db.attachments.download(id);
|
||||
}
|
||||
tiny.call(EditorWebView, tiny.notLoading);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,12 @@ export const execCommands = {
|
||||
EditorWebView,
|
||||
`
|
||||
(function() {
|
||||
let file = ${JSON.stringify(attachment)}
|
||||
let file = ${JSON.stringify({
|
||||
hash:hash,
|
||||
filename:file.name,
|
||||
type:file.type,
|
||||
size:file.size
|
||||
})}
|
||||
tinymce.activeEditor.execCommand('mceAttachFile',file);
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
@@ -127,8 +132,7 @@ export const execCommands = {
|
||||
maxHeight: 2000,
|
||||
quality: 0.8,
|
||||
mediaType: 'photo',
|
||||
encryptToFile: false,
|
||||
...key
|
||||
encryptToFile: false
|
||||
},
|
||||
handleImageResponse
|
||||
);
|
||||
@@ -147,8 +151,7 @@ export const execCommands = {
|
||||
maxHeight: 2000,
|
||||
quality: 0.8,
|
||||
mediaType: 'photo',
|
||||
encryptToFile: false,
|
||||
...key
|
||||
encryptToFile: false
|
||||
},
|
||||
handleImageResponse
|
||||
);
|
||||
@@ -170,69 +173,9 @@ export const execCommands = {
|
||||
tablesplitcell: "tinymce.activeEditor.execCommand('mceTableSplitCells');",
|
||||
tablemergecell: "tinymce.activeEditor.execCommand('mceTableMergeCells');",
|
||||
tablerowprops: "tinymce.activeEditor.execCommand('mceTableRowProps');",
|
||||
imageResize25: `(function() {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
|
||||
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_one")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_one")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_two")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_two")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_size_three")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
`,
|
||||
imageResize50: `(function() {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_one")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_one")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_three")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_three")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_size_two")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
})()
|
||||
|
||||
`,
|
||||
imageResize100: `(function() {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_three")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_three")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_size_two")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_size_two")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_size_one")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
|
||||
});
|
||||
}
|
||||
})()
|
||||
|
||||
`,
|
||||
imageResize25: () => setImageSize(0.25),
|
||||
imageResize50: () => setImageSize(0.5),
|
||||
imageResize100: () => setImageSize(1),
|
||||
imagepreview: `(function() {
|
||||
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
|
||||
var xhr = new XMLHttpRequest();
|
||||
@@ -272,67 +215,9 @@ export const execCommands = {
|
||||
}
|
||||
})();
|
||||
`,
|
||||
imagefloatleft: `(function () {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (node.tagName === 'IMG') {
|
||||
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_right")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_float_right")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_none")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_float_none")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_float_left")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
`,
|
||||
imagefloatright: `(function () {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (node.tagName === 'IMG') {
|
||||
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_left")) {
|
||||
tinymce.activeEditor.dom.removeClass(node, "img_float_left")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_none")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_float_none")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_float_right")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
|
||||
});
|
||||
}
|
||||
})()
|
||||
|
||||
`,
|
||||
imagefloatnone: `(function () {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (node.tagName === 'IMG') {
|
||||
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_left")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_float_left")
|
||||
}
|
||||
if (tinymce.activeEditor.dom.hasClass(node,"img_float_right")) {
|
||||
tinymce.activeEditor.dom.removeClass(node,"img_float_right")
|
||||
}
|
||||
tinymce.activeEditor.dom.addClass(node,"img_float_none")
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
});
|
||||
}
|
||||
})()
|
||||
|
||||
`,
|
||||
imagefloatleft: () => setFloat('left'),
|
||||
imagefloatright: () => setFloat('right'),
|
||||
imagefloatnone: () => setFloat('none'),
|
||||
'line-break': `
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
tinymce.activeEditor.execCommand('InsertLineBreak');
|
||||
@@ -358,7 +243,7 @@ const handleImageResponse = async response => {
|
||||
uri: image.uri,
|
||||
type: 'url'
|
||||
});
|
||||
console.log('hash: ',hash);
|
||||
|
||||
tiny.call(
|
||||
EditorWebView,
|
||||
`
|
||||
@@ -367,7 +252,8 @@ const handleImageResponse = async response => {
|
||||
hash: hash,
|
||||
type: image.type,
|
||||
filename: image.fileName,
|
||||
dataurl: b64
|
||||
dataurl: b64,
|
||||
size: image.fileSize
|
||||
})}
|
||||
tinymce.activeEditor.execCommand('mceAttachImage',image);
|
||||
setTimeout(function() {
|
||||
@@ -404,3 +290,39 @@ async function attachFile(uri, hash, type, filename) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const setFloat = float => `(function () {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (node.tagName === 'IMG') {
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
node.style.float = "${float}";
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
});
|
||||
}
|
||||
})()`;
|
||||
|
||||
const setImageSize = size => `(function() {
|
||||
let node = tinymce.activeEditor.selection.getNode();
|
||||
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
|
||||
tinymce.activeEditor.undoManager.transact(function() {
|
||||
let rect = node.getBoundingClientRect();
|
||||
let originalWidth = rect.width;
|
||||
let originalHeight = rect.height;
|
||||
if (node.dataset.width) {
|
||||
originalWidth = node.dataset.width;
|
||||
originalHeight = node.dataset.height;
|
||||
} else {
|
||||
node.dataset.width = originalWidth;
|
||||
node.dataset.height = originalHeight;
|
||||
}
|
||||
|
||||
node.width = originalWidth * ${size}
|
||||
setTimeout(function() {
|
||||
tinymce.activeEditor.nodeChanged({selectionChange:true})
|
||||
},100)
|
||||
});
|
||||
}
|
||||
})();
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user