aboutsummaryrefslogtreecommitdiff
path: root/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java
diff options
context:
space:
mode:
Diffstat (limited to 'libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java')
-rwxr-xr-xlibs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java236
1 files changed, 236 insertions, 0 deletions
diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java
new file mode 100755
index 000000000..b8212fcef
--- /dev/null
+++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java
@@ -0,0 +1,236 @@
+package org.wordpress.android.editor;
+
+import android.webkit.JavascriptInterface;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.wordpress.android.util.AppLog;
+import org.wordpress.android.util.JSONUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.wordpress.android.editor.EditorFragmentAbstract.MediaType;
+
+public class JsCallbackReceiver {
+ private static final String JS_CALLBACK_DELIMITER = "~";
+
+ private static final String CALLBACK_DOM_LOADED = "callback-dom-loaded";
+ private static final String CALLBACK_NEW_FIELD = "callback-new-field";
+
+ private static final String CALLBACK_INPUT = "callback-input";
+ private static final String CALLBACK_SELECTION_CHANGED = "callback-selection-changed";
+ private static final String CALLBACK_SELECTION_STYLE = "callback-selection-style";
+
+ private static final String CALLBACK_FOCUS_IN = "callback-focus-in";
+ private static final String CALLBACK_FOCUS_OUT = "callback-focus-out";
+
+ private static final String CALLBACK_IMAGE_REPLACED = "callback-image-replaced";
+ private static final String CALLBACK_VIDEO_REPLACED = "callback-video-replaced";
+ private static final String CALLBACK_IMAGE_TAP = "callback-image-tap";
+ private static final String CALLBACK_LINK_TAP = "callback-link-tap";
+ private static final String CALLBACK_MEDIA_REMOVED = "callback-media-removed";
+
+ private static final String CALLBACK_VIDEOPRESS_INFO_REQUEST = "callback-videopress-info-request";
+
+ private static final String CALLBACK_LOG = "callback-log";
+
+ private static final String CALLBACK_RESPONSE_STRING = "callback-response-string";
+
+ private static final String CALLBACK_ACTION_FINISHED = "callback-action-finished";
+
+ private final OnJsEditorStateChangedListener mListener;
+
+ private Set<String> mPreviousStyleSet = new HashSet<>();
+
+ public JsCallbackReceiver(EditorFragmentAbstract editorFragmentAbstract) {
+ mListener = (OnJsEditorStateChangedListener) editorFragmentAbstract;
+ }
+
+ @JavascriptInterface
+ public void executeCallback(String callbackId, String params) {
+ switch (callbackId) {
+ case CALLBACK_DOM_LOADED:
+ mListener.onDomLoaded();
+ break;
+ case CALLBACK_SELECTION_STYLE:
+ // Compare the new styles to the previous ones, and notify the JsCallbackListener of the changeset
+ Set<String> rawStyleSet = Utils.splitDelimitedString(params, JS_CALLBACK_DELIMITER);
+
+ // Strip link details from active style set
+ Set<String> newStyleSet = new HashSet<>();
+ for (String element : rawStyleSet) {
+ if (element.matches("link:(.*)")) {
+ newStyleSet.add("link");
+ } else if (!element.matches("link-title:(.*)")) {
+ newStyleSet.add(element);
+ }
+ }
+
+ mListener.onSelectionStyleChanged(Utils.getChangeMapFromSets(mPreviousStyleSet, newStyleSet));
+ mPreviousStyleSet = newStyleSet;
+ break;
+ case CALLBACK_SELECTION_CHANGED:
+ // Called for changes to the field in current focus and for changes made to selection
+ // (includes moving the caret without selecting text)
+ // TODO: Possibly needed for handling WebView scrolling when caret moves (from iOS)
+ Set<String> selectionKeyValueSet = Utils.splitDelimitedString(params, JS_CALLBACK_DELIMITER);
+ mListener.onSelectionChanged(Utils.buildMapFromKeyValuePairs(selectionKeyValueSet));
+ break;
+ case CALLBACK_INPUT:
+ // Called on key press
+ // TODO: Possibly needed for handling WebView scrolling when caret moves (from iOS)
+ break;
+ case CALLBACK_FOCUS_IN:
+ // TODO: Needed to handle displaying/graying the format bar when focus changes between the title and content
+ AppLog.d(AppLog.T.EDITOR, "Focus in callback received");
+ break;
+ case CALLBACK_FOCUS_OUT:
+ // TODO: Needed to handle displaying/graying the format bar when focus changes between the title and content
+ AppLog.d(AppLog.T.EDITOR, "Focus out callback received");
+ break;
+ case CALLBACK_NEW_FIELD:
+ // TODO: Used for logging/testing purposes on iOS
+ AppLog.d(AppLog.T.EDITOR, "New field created, " + params);
+ break;
+ case CALLBACK_IMAGE_REPLACED:
+ AppLog.d(AppLog.T.EDITOR, "Image replaced, " + params);
+
+ // Extract the local media id from the callback string (stripping the 'id=' part)
+ if (params.length() > 3) {
+ mListener.onMediaReplaced(params.substring(3));
+ }
+ break;
+ case CALLBACK_VIDEO_REPLACED:
+ AppLog.d(AppLog.T.EDITOR, "Video replaced, " + params);
+
+ // Extract the local media id from the callback string (stripping the 'id=' part)
+ if (params.length() > 3) {
+ mListener.onMediaReplaced(params.substring(3));
+ }
+ break;
+ case CALLBACK_IMAGE_TAP:
+ AppLog.d(AppLog.T.EDITOR, "Image tapped, " + params);
+
+ String uploadStatus = "";
+
+ List<String> mediaIds = new ArrayList<>();
+ mediaIds.add("id");
+ mediaIds.add("url");
+ mediaIds.add("meta");
+ mediaIds.add("type");
+
+ Set<String> mediaDataSet = Utils.splitValuePairDelimitedString(params, JS_CALLBACK_DELIMITER, mediaIds);
+ Map<String, String> mediaDataMap = Utils.buildMapFromKeyValuePairs(mediaDataSet);
+
+ String mediaId = mediaDataMap.get("id");
+
+ String mediaUrl = mediaDataMap.get("url");
+ if (mediaUrl != null) {
+ mediaUrl = Utils.decodeHtml(mediaUrl);
+ }
+
+ MediaType mediaType = MediaType.fromString(mediaDataMap.get("type"));
+
+ String mediaMeta = mediaDataMap.get("meta");
+ JSONObject mediaMetaJson = new JSONObject();
+
+ if (mediaMeta != null) {
+ mediaMeta = Utils.decodeHtml(mediaMeta);
+
+ try {
+ mediaMetaJson = new JSONObject(mediaMeta);
+ String classes = JSONUtils.getString(mediaMetaJson, "classes");
+ Set<String> classesSet = Utils.splitDelimitedString(classes, ", ");
+
+ if (classesSet.contains("uploading")) {
+ uploadStatus = "uploading";
+ } else if (classesSet.contains("failed")) {
+ uploadStatus = "failed";
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ AppLog.d(AppLog.T.EDITOR, "Media meta data from callback-image-tap was not JSON-formatted");
+ }
+ }
+
+ mListener.onMediaTapped(mediaId, mediaType, mediaMetaJson, uploadStatus);
+ break;
+ case CALLBACK_LINK_TAP:
+ // Extract and HTML-decode the link data from the callback params
+ AppLog.d(AppLog.T.EDITOR, "Link tapped, " + params);
+
+ List<String> linkIds = new ArrayList<>();
+ linkIds.add("url");
+ linkIds.add("title");
+
+ Set<String> linkDataSet = Utils.splitValuePairDelimitedString(params, JS_CALLBACK_DELIMITER, linkIds);
+ Map<String, String> linkDataMap = Utils.buildMapFromKeyValuePairs(linkDataSet);
+
+ String url = linkDataMap.get("url");
+ if (url != null) {
+ url = Utils.decodeHtml(url);
+ }
+
+ String title = linkDataMap.get("title");
+ if (title != null) {
+ title = Utils.decodeHtml(title);
+ }
+
+ mListener.onLinkTapped(url, title);
+ break;
+ case CALLBACK_MEDIA_REMOVED:
+ AppLog.d(AppLog.T.EDITOR, "Media removed, " + params);
+ // Extract the media id from the callback string (stripping the 'id=' part of the callback string)
+ if (params.length() > 3) {
+ mListener.onMediaRemoved(params.substring(3));
+ }
+ break;
+ case CALLBACK_VIDEOPRESS_INFO_REQUEST:
+ // Extract the VideoPress id from the callback string (stripping the 'id=' part of the callback string)
+ if (params.length() > 3) {
+ mListener.onVideoPressInfoRequested(params.substring(3));
+ }
+ break;
+ case CALLBACK_LOG:
+ // Strip 'msg=' from beginning of string
+ if (params.length() > 4) {
+ AppLog.d(AppLog.T.EDITOR, callbackId + ": " + params.substring(4));
+ }
+ break;
+ case CALLBACK_RESPONSE_STRING:
+ AppLog.d(AppLog.T.EDITOR, callbackId + ": " + params);
+ Set<String> responseDataSet;
+ if (params.startsWith("function=") && params.contains(JS_CALLBACK_DELIMITER)) {
+ String functionName = params.substring("function=".length(), params.indexOf(JS_CALLBACK_DELIMITER));
+
+ List<String> responseIds = new ArrayList<>();
+ switch (functionName) {
+ case "getHTMLForCallback":
+ responseIds.add("id");
+ responseIds.add("contents");
+ break;
+ case "getSelectedTextToLinkify":
+ responseIds.add("result");
+ break;
+ case "getFailedMedia":
+ responseIds.add("ids");
+ }
+
+ responseDataSet = Utils.splitValuePairDelimitedString(params, JS_CALLBACK_DELIMITER, responseIds);
+ } else {
+ responseDataSet = Utils.splitDelimitedString(params, JS_CALLBACK_DELIMITER);
+ }
+ mListener.onGetHtmlResponse(Utils.buildMapFromKeyValuePairs(responseDataSet));
+ break;
+ case CALLBACK_ACTION_FINISHED:
+ mListener.onActionFinished();
+ break;
+ default:
+ AppLog.d(AppLog.T.EDITOR, "Unhandled callback: " + callbackId + ":" + params);
+ }
+ }
+}