diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 97863101a..aedc27d08 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -1261,9 +1261,13 @@ public void setViewModeVisibility(boolean show, final boolean animate) { @JavascriptInterface public void webViewJavascriptCallback(final String[] jsArgs) { final String[] args = (jsArgs == null || jsArgs.length == 0 || jsArgs[0] == null) ? new String[0] : jsArgs; - final String type = args.length == 0 || TextUtils.isEmpty(args[0]) ? "" : args[0]; - if (type.equalsIgnoreCase("toast") && args.length == 2) { - Toast.makeText(getActivity(), args[1], Toast.LENGTH_SHORT).show(); + final Activity activity = getActivity(); + if (activity != null) { + activity.runOnUiThread(() -> { + if (_format != null) { + _format.getActions().onWebViewJavascriptCallback(args); + } + }); } } diff --git a/app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java b/app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java index 409d431ef..d3fc159d2 100644 --- a/app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java +++ b/app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java @@ -27,6 +27,7 @@ import android.webkit.WebView; import android.widget.EditText; import android.widget.ImageView; +import android.widget.Toast; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; @@ -105,6 +106,13 @@ public boolean onActionLongClick(final @StringRes int action) { return runCommonLongPressAction(action); } + // Override to implement custom callbacks from view-mode JavaScript + public void onWebViewJavascriptCallback(final String[] args) { + if (args.length == 2 && "toast".equalsIgnoreCase(args[0]) && _activity != null) { + Toast.makeText(_activity, args[1], Toast.LENGTH_SHORT).show(); + } + } + private TextSearchViewHolder _textSearchViewHolder; public ActionButtonBase initTextSearch(DocumentEditAndViewFragment fragment) { diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java index 1bba5a940..d6b8a1f0c 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java @@ -57,6 +57,43 @@ public MarkdownActionButtons(@NonNull Context context, Document document) { super(context, document); } + @Override + public void onWebViewJavascriptCallback(final String[] args) { + if (isMarkdownCheckboxAction(args)) { + runViewModeCheckboxAction(args); + return; + } + super.onWebViewJavascriptCallback(args); + } + + private boolean isMarkdownCheckboxAction(final String[] args) { + return args.length == 3 && + "markdown-checkbox".equals(args[0]) && + ("true".equals(args[2]) || "false".equals(args[2])) && + _hlEditor != null; + } + + private void runViewModeCheckboxAction(final String[] args) { + final int sourceIndex = GsTextUtils.tryParseInt(args[1], -1); + final Editable text = _hlEditor.getText(); + if (sourceIndex <= 0 || + sourceIndex >= text.length() - 1 || + text.charAt(sourceIndex - 1) != '[' || + text.charAt(sourceIndex + 1) != ']') { + return; + } + + final char current = text.charAt(sourceIndex); + if (current != ' ' && current != 'x' && current != 'X') { + return; + } + + final char replacement = "true".equals(args[2]) ? 'x' : ' '; + if (current != replacement) { + _hlEditor.withAutoFormatDisabled(() -> text.replace(sourceIndex, sourceIndex + 1, String.valueOf(replacement))); + } + } + @Override protected @StringRes int getFormatActionsKey() { diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java index a23bb4fa2..26dd5becd 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownTextConverter.java @@ -18,6 +18,7 @@ import com.vladsch.flexmark.ext.footnotes.FootnoteExtension; import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughSubscriptExtension; import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension; +import com.vladsch.flexmark.ext.gfm.tasklist.TaskListItem; import com.vladsch.flexmark.ext.gitlab.GitLabExtension; import com.vladsch.flexmark.ext.ins.InsExtension; import com.vladsch.flexmark.ext.jekyll.front.matter.JekyllFrontMatterExtension; @@ -153,8 +154,6 @@ public class MarkdownTextConverter extends TextConverterBase { //######################## // private static final String toDashChars = " -_"; // See HtmlRenderer.HEADER_ID_GENERATOR_TO_DASH_CHARS.getFrom(document) private static final Pattern linkPattern = Pattern.compile("\\[(.*?)\\]\\((.*?)(\\s+\".*\")?\\)"); - - //######################## //## Methods //######################## @@ -165,6 +164,9 @@ public String convertMarkup(String markup, Context context, boolean lightMode, b final MutableDataSet options = new MutableDataSet(); options.set(Parser.EXTENSIONS, flexmarkExtensions); + final String sourceMarkup = markup; + final Document sourceDocument = flexmarkParser.parse(sourceMarkup); + final List checkboxSourceIndices = getCheckboxSourceIndices(sourceDocument); options.set(Parser.SPACE_IN_LINK_URLS, true); // Allow links like [this](some filename with spaces.md) @@ -179,6 +181,13 @@ public String convertMarkup(String markup, Context context, boolean lightMode, b final String checkedCheckbox = ""; options.set(TaskListExtension.ITEM_NOT_DONE_MARKER, checkedCheckbox.replace("checked=checked", "")) .set(TaskListExtension.ITEM_DONE_MARKER, checkedCheckbox); + if (!checkboxSourceIndices.isEmpty()) { + onLoadJs += "var checkboxSourceIndices=" + checkboxSourceIndices + ";" + + "var boxes=document.querySelectorAll('input.task-list-item-checkbox');" + + "for(var i=0;i + ref#(click) --> remove line break) @@ -375,6 +384,21 @@ private String escapeSpacesInLink(final String markup) { return sb.toString(); } + private static List getCheckboxSourceIndices(final Document document) { + final List indices = new ArrayList<>(); + collectCheckboxSourceIndices(document, indices); + return indices; + } + + private static void collectCheckboxSourceIndices(final Node parent, final List indices) { + for (Node node = parent.getFirstChild(); node != null; node = node.getNext()) { + if (node instanceof TaskListItem) { + indices.add(((TaskListItem) node).getMarkerSuffix().getStartOffset() + 1); + } + collectCheckboxSourceIndices(node, indices); + } + } + private String getViewHlPrismIncludes(final String theme) { return CSS_PREFIX + "prism/themes/prism" + theme + ".min.css" + CSS_POSTFIX + @@ -490,4 +514,4 @@ public static HtmlRenderer.HtmlRendererExtension create() { return new LineNumberIdExtension(); } } -} \ No newline at end of file +}