Skip to content

Commit b0d82eb

Browse files
committed
Implement image upload for iOS
1 parent b65f4da commit b0d82eb

File tree

2 files changed

+187
-32
lines changed

2 files changed

+187
-32
lines changed

src/components/write/Toolbar.tsx

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export interface ToolbarProps {
120120
onClick?: Function;
121121
onConvert?: () => void;
122122
innerRef?: React.RefObject<HTMLDivElement>;
123+
ios?: boolean;
123124
}
124125

125126
const Toolbar: React.FC<ToolbarProps> = ({
@@ -128,6 +129,7 @@ const Toolbar: React.FC<ToolbarProps> = ({
128129
onClick = () => {},
129130
onConvert,
130131
innerRef,
132+
ios,
131133
}) => {
132134
const forMarkdown = mode === 'MARKDOWN';
133135
return (
@@ -174,39 +176,46 @@ const Toolbar: React.FC<ToolbarProps> = ({
174176
</Heading>
175177
</ToolbarItem>
176178
<Separator />
177-
<ToolbarItem className="ql-bold" onClick={() => onClick('bold')}>
178-
<MdFormatBold />
179-
</ToolbarItem>
180-
<ToolbarItem className="ql-italic" onClick={() => onClick('italic')}>
181-
<MdFormatItalic />
182-
</ToolbarItem>
183-
{!forMarkdown && (
184-
<ToolbarItem className="ql-underline">
185-
<MdFormatUnderlined />
186-
</ToolbarItem>
179+
{!ios && (
180+
<>
181+
<ToolbarItem className="ql-bold" onClick={() => onClick('bold')}>
182+
<MdFormatBold />
183+
</ToolbarItem>
184+
<ToolbarItem className="ql-italic" onClick={() => onClick('italic')}>
185+
<MdFormatItalic />
186+
</ToolbarItem>
187+
{!forMarkdown && (
188+
<ToolbarItem className="ql-underline">
189+
<MdFormatUnderlined />
190+
</ToolbarItem>
191+
)}
192+
<ToolbarItem className="ql-strike" onClick={() => onClick('strike')}>
193+
<MdFormatStrikethrough />
194+
</ToolbarItem>
195+
<Separator />
196+
<ToolbarItem
197+
className="ql-blockquote"
198+
onClick={() => onClick('blockquote')}
199+
>
200+
<MdFormatQuote />
201+
</ToolbarItem>
202+
<ToolbarItem className="ql-link" onClick={() => onClick('link')}>
203+
<MdInsertLink />
204+
</ToolbarItem>
205+
</>
187206
)}
188-
<ToolbarItem className="ql-strike" onClick={() => onClick('strike')}>
189-
<MdFormatStrikethrough />
190-
</ToolbarItem>
191-
<Separator />
192-
<ToolbarItem
193-
className="ql-blockquote"
194-
onClick={() => onClick('blockquote')}
195-
>
196-
<MdFormatQuote />
197-
</ToolbarItem>
198-
<ToolbarItem className="ql-link" onClick={() => onClick('link')}>
199-
<MdInsertLink />
200-
</ToolbarItem>
201207
<ToolbarItem className="ql-image" onClick={() => onClick('image')}>
202208
<MdImage />
203209
</ToolbarItem>
204-
<ToolbarItem
205-
className="ql-code-block"
206-
onClick={() => onClick('codeblock')}
207-
>
208-
<MdCode />
209-
</ToolbarItem>
210+
211+
{!ios && (
212+
<ToolbarItem
213+
className="ql-code-block"
214+
onClick={() => onClick('codeblock')}
215+
>
216+
<MdCode />
217+
</ToolbarItem>
218+
)}
210219
<div className="mobile-placeholder"></div>
211220
{/* <Separator /> */}
212221
{/* <ToolbarGroup> */}

src/components/write/WriteMarkdownEditor.tsx

Lines changed: 149 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,25 @@ export default class WriteMarkdownEditor extends React.Component<
216216
};
217217

218218
addImageToEditor = (image: string) => {
219+
if (this.isIOS) {
220+
const textarea = this.appleEditorElement.current;
221+
if (!textarea) return;
222+
const { markdown, onChangeMarkdown } = this.props;
223+
224+
const cursorPos = textarea.selectionEnd;
225+
const textBefore = markdown.slice(0, cursorPos);
226+
const textAfter = markdown.slice(cursorPos, markdown.length);
227+
const imageMarkdown = `![](${encodeURI(image)})`;
228+
const nextMarkdown = `${textBefore}${imageMarkdown}${textAfter}`;
229+
onChangeMarkdown(nextMarkdown);
230+
setTimeout(() => {
231+
textarea.focus();
232+
const nextCursorPos = cursorPos + imageMarkdown.length;
233+
textarea.selectionStart = nextCursorPos;
234+
textarea.selectionEnd = nextCursorPos;
235+
}, 0);
236+
return;
237+
}
219238
if (!this.codemirror) return;
220239
this.codemirror.getDoc().replaceSelection(`![](${encodeURI(image)})`);
221240
};
@@ -325,17 +344,143 @@ export default class WriteMarkdownEditor extends React.Component<
325344
};
326345

327346
handleToolbarClickForApple = (mode: string) => {
347+
if (!this.appleEditorElement.current) return;
328348
const cursorPos = this.appleEditorElement.current?.selectionStart || 0;
329349
const { markdown, onChangeMarkdown } = this.props;
330350
const sliced = markdown.slice(0, cursorPos);
331-
console.log(sliced);
332351

333352
// const lineNumber = sliced.split('\n').length;
334353
const lastNewLineIndex = sliced.lastIndexOf('\n');
335354
const textBefore = sliced.slice(0, lastNewLineIndex + 1);
336355
const textAfter = markdown.slice(lastNewLineIndex + 1, markdown.length);
337-
const result = textBefore + '# ' + textAfter;
338-
onChangeMarkdown(result);
356+
const currentNewLineIndex = textAfter.indexOf('\n');
357+
const lineText = textAfter.slice(0, currentNewLineIndex);
358+
const textBelowCurrentLine = textAfter.slice(
359+
currentNewLineIndex,
360+
textAfter.length,
361+
);
362+
363+
const setCursorPos = (pos: number) => {
364+
setTimeout(() => {
365+
this.appleEditorElement.current!.selectionStart = pos;
366+
this.appleEditorElement.current!.selectionEnd = pos;
367+
}, 0);
368+
};
369+
const handlers: {
370+
[key: string]: () => void;
371+
} = {
372+
heading1: () => {
373+
const applied = /^# /.test(lineText);
374+
if (applied) {
375+
const replacedLine = lineText.replace(/^# /, '');
376+
onChangeMarkdown(
377+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
378+
);
379+
setCursorPos(cursorPos - 2);
380+
return;
381+
}
382+
383+
const anotherHeading = /^#{1,4} /.test(lineText);
384+
if (anotherHeading) {
385+
const replacedLine = lineText.replace(/^#{1,4} /, '# ');
386+
onChangeMarkdown(
387+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
388+
);
389+
const posDiff = replacedLine.length - lineText.length;
390+
setCursorPos(cursorPos + posDiff);
391+
392+
return;
393+
}
394+
395+
onChangeMarkdown(`${textBefore}# ${textAfter}`);
396+
// this.appleEditorElement.current!.selectionStart = cursorPos;
397+
setCursorPos(cursorPos + 2);
398+
},
399+
heading2: () => {
400+
const applied = /^## /.test(lineText);
401+
if (applied) {
402+
const replacedLine = lineText.replace(/^## /, '');
403+
onChangeMarkdown(
404+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
405+
);
406+
setCursorPos(cursorPos - 3);
407+
408+
return;
409+
}
410+
411+
const anotherHeading = /^#{1,4} /.test(lineText);
412+
if (anotherHeading) {
413+
const replacedLine = lineText.replace(/^#{1,4} /, '## ');
414+
onChangeMarkdown(
415+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
416+
);
417+
const posDiff = replacedLine.length - lineText.length;
418+
setCursorPos(cursorPos + posDiff);
419+
return;
420+
}
421+
422+
onChangeMarkdown(`${textBefore}## ${textAfter}`);
423+
setCursorPos(cursorPos + 3);
424+
},
425+
heading3: () => {
426+
const applied = /^### /.test(lineText);
427+
if (applied) {
428+
const replacedLine = lineText.replace(/^### /, '');
429+
onChangeMarkdown(
430+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
431+
);
432+
setCursorPos(cursorPos - 4);
433+
434+
return;
435+
}
436+
437+
const anotherHeading = /^#{1,4} /.test(lineText);
438+
if (anotherHeading) {
439+
const replacedLine = lineText.replace(/^#{1,4} /, '### ');
440+
onChangeMarkdown(
441+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
442+
);
443+
const posDiff = replacedLine.length - lineText.length;
444+
setCursorPos(cursorPos + posDiff);
445+
return;
446+
}
447+
448+
onChangeMarkdown(`${textBefore}### ${textAfter}`);
449+
setCursorPos(cursorPos + 4);
450+
},
451+
heading4: () => {
452+
const applied = /^#### /.test(lineText);
453+
if (applied) {
454+
const replacedLine = lineText.replace(/^#### /, '');
455+
onChangeMarkdown(
456+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
457+
);
458+
setCursorPos(cursorPos - 5);
459+
460+
return;
461+
}
462+
463+
const anotherHeading = /^#{1,4} /.test(lineText);
464+
if (anotherHeading) {
465+
const replacedLine = lineText.replace(/^#{1,4} /, '#### ');
466+
onChangeMarkdown(
467+
`${textBefore}${replacedLine}${textBelowCurrentLine}`,
468+
);
469+
const posDiff = replacedLine.length - lineText.length;
470+
setCursorPos(cursorPos + posDiff);
471+
return;
472+
}
473+
474+
onChangeMarkdown(`${textBefore}#### ${textAfter}`);
475+
setCursorPos(cursorPos + 5);
476+
},
477+
image: () => {
478+
this.props.onUpload();
479+
},
480+
};
481+
482+
this.appleEditorElement.current!.focus();
483+
handlers[mode]();
339484

340485
// const handlers: {
341486
// [key: string]: Function;
@@ -726,6 +871,7 @@ ${selected}
726871
onClick={this.handleToolbarClick}
727872
onConvert={this.handleAskConvert}
728873
innerRef={this.toolbarElement}
874+
ios={this.isIOS}
729875
/>
730876
<MarkdownWrapper>
731877
{addLink.visible && (

0 commit comments

Comments
 (0)