sample, add wysiwyg sample
This commit is contained in:
parent
dcd9d428ee
commit
63ed271133
@ -1,4 +1,16 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"javaClassName": "io.noties.markwon.app.samples.editor.WYSIWYGEditorSample",
|
||||||
|
"id": "20200908133515",
|
||||||
|
"title": "WYSIWG editor",
|
||||||
|
"description": "A possible direction to implement what-you-see-is-what-you-get editor",
|
||||||
|
"artifacts": [
|
||||||
|
"EDITOR"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"rendering"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.ListTaskListSample",
|
"javaClassName": "io.noties.markwon.app.samples.tasklist.ListTaskListSample",
|
||||||
"id": "20200902174132",
|
"id": "20200902174132",
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
package io.noties.markwon.app.samples.editor;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.text.style.ReplacementSpan;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import io.noties.debug.Debug;
|
||||||
|
import io.noties.markwon.Markwon;
|
||||||
|
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
|
||||||
|
import io.noties.markwon.app.sample.Tags;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.BlockQuoteEditHandler;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.CodeEditHandler;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.LinkEditHandler;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||||
|
import io.noties.markwon.app.samples.editor.shared.StrikethroughEditHandler;
|
||||||
|
import io.noties.markwon.editor.MarkwonEditor;
|
||||||
|
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||||
|
import io.noties.markwon.editor.PersistedSpans;
|
||||||
|
import io.noties.markwon.editor.handler.EmphasisEditHandler;
|
||||||
|
import io.noties.markwon.editor.handler.StrongEmphasisEditHandler;
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||||
|
|
||||||
|
@MarkwonSampleInfo(
|
||||||
|
id = "20200908133515",
|
||||||
|
title = "WYSIWG editor",
|
||||||
|
description = "A possible direction to implement what-you-see-is-what-you-get editor",
|
||||||
|
artifacts = MarkwonArtifact.EDITOR,
|
||||||
|
tags = Tags.rendering
|
||||||
|
)
|
||||||
|
public class WYSIWYGEditorSample extends MarkwonEditTextSample {
|
||||||
|
@Override
|
||||||
|
public void render() {
|
||||||
|
|
||||||
|
// when automatic line break is inserted and text is inside margin span (blockquote, list, etc)
|
||||||
|
// be prepared to encounter selection bugs (selection would be drawn at the place as is no margin
|
||||||
|
// span is present)
|
||||||
|
|
||||||
|
final Markwon markwon = Markwon.builder(context)
|
||||||
|
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final MarkwonEditor editor = MarkwonEditor.builder(markwon)
|
||||||
|
.punctuationSpan(HidePunctuationSpan.class, new PersistedSpans.SpanFactory<HidePunctuationSpan>() {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public HidePunctuationSpan create() {
|
||||||
|
return new HidePunctuationSpan();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.useEditHandler(new EmphasisEditHandler())
|
||||||
|
.useEditHandler(new StrongEmphasisEditHandler())
|
||||||
|
.useEditHandler(new StrikethroughEditHandler())
|
||||||
|
.useEditHandler(new CodeEditHandler())
|
||||||
|
.useEditHandler(new BlockQuoteEditHandler())
|
||||||
|
.useEditHandler(new LinkEditHandler(new LinkEditHandler.OnClick() {
|
||||||
|
@Override
|
||||||
|
public void onClick(@NonNull View widget, @NonNull String link) {
|
||||||
|
Debug.e("clicked: %s", link);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.useEditHandler(new HeadingEditHandler())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// for links to be clickable
|
||||||
|
// NB! markwon MovementMethodPlugin cannot be used here as editor do not execute `beforeSetText`)
|
||||||
|
editText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
|
||||||
|
editText.addTextChangedListener(MarkwonEditorTextWatcher.withProcess(editor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HidePunctuationSpan extends ReplacementSpan {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
|
||||||
|
// last space (which is swallowed until next non-space character appears)
|
||||||
|
// block quote
|
||||||
|
// code tick
|
||||||
|
|
||||||
|
// Debug.i("text: '%s', %d-%d (%d)", text.subSequence(start, end), start, end, text.length());
|
||||||
|
if (end == text.length()) {
|
||||||
|
// TODO: find first non-space character (not just first one because commonmark allows
|
||||||
|
// arbitrary (0-3) white spaces before content starts
|
||||||
|
|
||||||
|
// TODO: if all white space - render?
|
||||||
|
final char c = text.charAt(start);
|
||||||
|
if ('#' == c
|
||||||
|
|| '>' == c
|
||||||
|
|| '-' == c // TODO: not thematic break
|
||||||
|
|| '+' == c
|
||||||
|
// `*` is fine but only for a list
|
||||||
|
|| isBulletList(text, c, start, end)
|
||||||
|
|| Character.isDigit(c) // assuming ordered list (replacement should only happen for ordered lists)
|
||||||
|
|| Character.isWhitespace(c)) {
|
||||||
|
return (int) (paint.measureText(text, start, end) + 0.5F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||||
|
// will be called only when getSize is not 0 (and if it was once reported as 0...)
|
||||||
|
if (end == text.length()) {
|
||||||
|
|
||||||
|
// if first non-space is `*` then check for is bullet
|
||||||
|
// else `**` would be still rendered at the end of the emphasis
|
||||||
|
if (text.charAt(start) == '*'
|
||||||
|
&& !isBulletList(text, '*', start, end)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: inline code last tick received here, handle it (do not highlight)
|
||||||
|
// why can't we have reported width in this method for supplied text?
|
||||||
|
|
||||||
|
// let's use color to make it distinct from the rest of the text for demonstration purposes
|
||||||
|
paint.setColor(0xFFff0000);
|
||||||
|
|
||||||
|
canvas.drawText(text, start, end, x, y, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBulletList(@NonNull CharSequence text, char firstChar, int start, int end) {
|
||||||
|
return '*' == firstChar
|
||||||
|
&& ((end - start == 1) || (Character.isWhitespace(text.charAt(start + 1))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user