From 108ed89ccdc90830463e57ce4ff5ba64ef0acc8f Mon Sep 17 00:00:00 2001 From: Alex Forcier Date: Tue, 23 Feb 2016 15:28:15 -0800 Subject: [PATCH] Squashed 'libs/editor/' changes from 50ddd25..7f3b589 7f3b589 Updated example app to use the modified onMediaUploadSucceeded call b203bf0 Fixed an outdated reference in the ZSSEditor f9dbe59 Editor 0.6 version bump 76711d6 Updated localized string calls in ZSSEditor video methods c0b804b Merge branch 'feature/visual-editor' into feature/visual-editor-insert-video b87b917 Escape quotes for URLs being passed to the JS editor d06f2e2 Use hasAttribute to null-check when parsing for failed media items d3dff92 Wrapped called to getThumbnailURL in notNullStr() in the editor fragment 951bb3d Removed unnecessary console.logs 11feabd Drop data-failed attribute from ZSSEditor.insertLocalVideo 3c54e44 Merge branch 'feature/visual-editor' into feature/visual-editor-insert-video 7feb0e9 Use API<19 compatibility upload UI for video (imported from images) d806115 Include videos in count of failed media uploads 2fc0151 Mark uploading videos as failed when opening a post containing them, so they can be retried c6ac1e9 Send VideoPress shortcode and poster URL to visual editor when video upload completes 8f74166 Stop adding unnecessary 'data-wpid' attributed to completed video uploads b16606a Merge branch 'feature/visual-editor' into feature/visual-editor-insert-video 916c025 Handle video upload failure and support retrying fe3e855 Support cancelling in-progress video uploads and removing the video from the UI 2b14632 Differentiate media types in OnJsEditorStateChangedListener.onMediaTapped() native-side 26032af Added handling for completed video uploads, using the new remote URL and clearing placeholder and container adebbff Add CSS for video_container in API<19 compatibility mode 282dbea Use appropriate JS methods for local video insertion and upload progress updates d6ca1c7 Use placeholder image instead of video tag for uploading videos 10ae531 Track media type along with id in current uploads 2c9380b s/photo/image/ in example activity demo menu 7486336 Added video upload demo options to example activity d923987 Merge branch 'feature/visual-editor' into feature/visual-editor-insert-video 7487a90 Add support for remote video insertion to visual editor 5497330 Merge branch 'feature/visual-editor' into feature/visual-editor-add-video 9594791 Append break tags when inserting video tags for non-VideoPress videos a8a7858 Remove unused fullscreen video functionality from ZSSEditor git-subtree-dir: libs/editor git-subtree-split: 7f3b589d033fea945b226ccd85f31fe7dd7f0832 --- WordPressEditor/build.gradle | 4 +- .../android/editor/EditorFragment.java | 156 ++++++++--- .../editor/EditorFragmentAbstract.java | 15 ++ .../editor/EditorMediaUploadListener.java | 4 +- .../android/editor/JsCallbackReceiver.java | 9 +- .../OnJsEditorStateChangedListener.java | 4 +- .../org/wordpress/android/editor/Utils.java | 7 + .../example/EditorExampleActivity.java | 42 ++- example/src/main/res/values/strings.xml | 6 +- .../editor-common/assets/ZSSRichTextEditor.js | 253 +++++++++--------- libs/editor-common/assets/editor-android.css | 18 +- 11 files changed, 324 insertions(+), 194 deletions(-) diff --git a/WordPressEditor/build.gradle b/WordPressEditor/build.gradle index 4898792eca6a..c63ac5abf601 100644 --- a/WordPressEditor/build.gradle +++ b/WordPressEditor/build.gradle @@ -23,8 +23,8 @@ android { buildToolsVersion "23.0.2" defaultConfig { - versionCode 5 - versionName "0.5" + versionCode 6 + versionName "0.6" minSdkVersion 14 targetSdkVersion 23 } diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragment.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragment.java index 439cce75807d..e81895deba11 100755 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragment.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragment.java @@ -36,6 +36,7 @@ import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.JSONUtils; import org.wordpress.android.util.ProfilingUtils; +import org.wordpress.android.util.ShortcodeUtils; import org.wordpress.android.util.StringUtils; import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.UrlUtils; @@ -93,7 +94,7 @@ public class EditorFragment extends EditorFragmentAbstract implements View.OnCli private ConcurrentHashMap mWaitingMediaFiles; private Set mWaitingGalleries; - private Set mUploadingMediaIds; + private Map mUploadingMedia; private Set mFailedMediaIds; private MediaGallery mUploadingMediaGallery; @@ -137,7 +138,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa mWaitingMediaFiles = new ConcurrentHashMap<>(); mWaitingGalleries = Collections.newSetFromMap(new ConcurrentHashMap()); - mUploadingMediaIds = new HashSet<>(); + mUploadingMedia = new HashMap<>(); mFailedMediaIds = new HashSet<>(); // -- WebView configuration @@ -234,7 +235,7 @@ public void onResume() { @Override public void onDetach() { // Soft cancel (delete flag off) all media uploads currently in progress - for (String mediaId : mUploadingMediaIds) { + for (String mediaId : mUploadingMedia.keySet()) { mEditorFragmentListener.onMediaUploadCancelClicked(mediaId, false); } super.onDetach(); @@ -411,7 +412,7 @@ public void onClick(View v) { mEditorFragmentListener.onTrackableEvent(TrackableEvent.HTML_BUTTON_TAPPED); // Don't switch to HTML mode if currently uploading media - if (!mUploadingMediaIds.isEmpty()) { + if (!mUploadingMedia.isEmpty()) { ((ToggleButton) v).setChecked(false); if (isAdded()) { @@ -753,17 +754,38 @@ public void appendMediaFile(final MediaFile mediaFile, final String mediaUrl, Im return; } + final String safeMediaUrl = Utils.escapeQuotes(mediaUrl); + mWebView.post(new Runnable() { @Override public void run() { if (URLUtil.isNetworkUrl(mediaUrl)) { String mediaId = mediaFile.getMediaId(); - mWebView.execJavaScriptFromString("ZSSEditor.insertImage('" + mediaUrl + "', '" + mediaId + "');"); + if (mediaFile.isVideo()) { + String posterUrl = Utils.escapeQuotes(StringUtils.notNullStr(mediaFile.getThumbnailURL())); + String videoPressId = ShortcodeUtils.getVideoPressIdFromShortCode( + mediaFile.getVideoPressShortCode()); + + mWebView.execJavaScriptFromString("ZSSEditor.insertVideo('" + safeMediaUrl + "', '" + + posterUrl + "', '" + videoPressId + "');"); + } else { + mWebView.execJavaScriptFromString("ZSSEditor.insertImage('" + safeMediaUrl + "', '" + mediaId + + "');"); + } } else { String id = mediaFile.getMediaId(); - mWebView.execJavaScriptFromString("ZSSEditor.insertLocalImage(" + id + ", '" + mediaUrl + "');"); - mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + id + ", " + 0 + ");"); - mUploadingMediaIds.add(id); + if (mediaFile.isVideo()) { + String posterUrl = Utils.escapeQuotes(StringUtils.notNullStr(mediaFile.getThumbnailURL())); + mWebView.execJavaScriptFromString("ZSSEditor.insertLocalVideo(" + id + ", '" + posterUrl + + "');"); + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnVideo(" + id + ", " + 0 + ");"); + mUploadingMedia.put(id, MediaType.VIDEO); + } else { + mWebView.execJavaScriptFromString("ZSSEditor.insertLocalImage(" + id + ", '" + safeMediaUrl + + "');"); + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + id + ", " + 0 + ");"); + mUploadingMedia.put(id, MediaType.IMAGE); + } } } }); @@ -796,8 +818,8 @@ public void setUrlForVideoPressId(final String videoId, final String videoUrl, f mWebView.post(new Runnable() { @Override public void run() { - mWebView.execJavaScriptFromString("ZSSEditor.setVideoPressLinks('" + videoId + "', '" + - videoUrl + "', '" + posterUrl + "');"); + mWebView.execJavaScriptFromString("ZSSEditor.setVideoPressLinks('" + videoId + "', '" + + Utils.escapeQuotes(videoUrl) + "', '" + Utils.escapeQuotes(posterUrl) + "');"); } }); } @@ -823,27 +845,48 @@ public void setContentPlaceholder(CharSequence placeholderText) { } @Override - public void onMediaUploadSucceeded(final String mediaId, final String remoteId, final String remoteUrl) { - mWebView.post(new Runnable() { - @Override - public void run() { - mWebView.execJavaScriptFromString("ZSSEditor.replaceLocalImageWithRemoteImage(" + mediaId + ", '" + - remoteId + "', '" + remoteUrl + "');"); - mUploadingMediaIds.remove(mediaId); - } - }); + public void onMediaUploadSucceeded(final String localMediaId, final MediaFile mediaFile) { + final MediaType mediaType = mUploadingMedia.get(localMediaId); + if (mediaType != null) { + mWebView.post(new Runnable() { + @Override + public void run() { + String remoteUrl = Utils.escapeQuotes(mediaFile.getFileURL()); + if (mediaType.equals(MediaType.IMAGE)) { + String remoteMediaId = mediaFile.getMediaId(); + mWebView.execJavaScriptFromString("ZSSEditor.replaceLocalImageWithRemoteImage(" + localMediaId + + ", '" + remoteMediaId + "', '" + remoteUrl + "');"); + } else if (mediaType.equals(MediaType.VIDEO)) { + String posterUrl = Utils.escapeQuotes(StringUtils.notNullStr(mediaFile.getThumbnailURL())); + String videoPressId = ShortcodeUtils.getVideoPressIdFromShortCode( + mediaFile.getVideoPressShortCode()); + mWebView.execJavaScriptFromString("ZSSEditor.replaceLocalVideoWithRemoteVideo(" + localMediaId + + ", '" + remoteUrl + "', '" + posterUrl + "', '" + videoPressId + "');"); + } + mUploadingMedia.remove(localMediaId); + } + }); + } } @Override public void onMediaUploadProgress(final String mediaId, final float progress) { - mWebView.post(new Runnable() { - @Override - public void run() { - String progressString = String.format(Locale.US, "%.1f", progress); - mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + mediaId + ", " + - progressString + ");"); - } - }); + final MediaType mediaType = mUploadingMedia.get(mediaId); + if (mediaType != null) { + mWebView.post(new Runnable() { + @Override + public void run() { + String progressString = String.format(Locale.US, "%.1f", progress); + if (mediaType.equals(MediaType.IMAGE)) { + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + mediaId + ", " + + progressString + ");"); + } else if (mediaType.equals(MediaType.VIDEO)) { + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnVideo(" + mediaId + ", " + + progressString + ");"); + } + } + }); + } } @Override @@ -851,10 +894,18 @@ public void onMediaUploadFailed(final String mediaId, final String errorMessage) mWebView.post(new Runnable() { @Override public void run() { - mWebView.execJavaScriptFromString("ZSSEditor.markImageUploadFailed(" + mediaId + ", '" - + errorMessage.replace("'", "\\'").replace("\"", "\\\"") + "');"); + MediaType mediaType = mUploadingMedia.get(mediaId); + switch (mediaType) { + case IMAGE: + mWebView.execJavaScriptFromString("ZSSEditor.markImageUploadFailed(" + mediaId + ", '" + + Utils.escapeQuotes(errorMessage) + "');"); + break; + case VIDEO: + mWebView.execJavaScriptFromString("ZSSEditor.markVideoUploadFailed(" + mediaId + ", '" + + Utils.escapeQuotes(errorMessage) + "');"); + } mFailedMediaIds.add(mediaId); - mUploadingMediaIds.remove(mediaId); + mUploadingMedia.remove(mediaId); } }); } @@ -900,11 +951,11 @@ public void run() { // If there are images that are still in progress (because the editor exited before they completed), // set them to failed, so the user can restart them (otherwise they will stay stuck in 'uploading' mode) - mWebView.execJavaScriptFromString("ZSSEditor.markAllUploadingImagesAsFailed('" + mWebView.execJavaScriptFromString("ZSSEditor.markAllUploadingMediaAsFailed('" + getString(R.string.tap_to_try_again) + "');"); // Update the list of failed media uploads - mWebView.execJavaScriptFromString("ZSSEditor.getFailedImages();"); + mWebView.execJavaScriptFromString("ZSSEditor.getFailedMedia();"); hideActionBarIfNeeded(); @@ -980,7 +1031,11 @@ public void run() { }); } - public void onMediaTapped(final String mediaId, String url, final JSONObject meta, String uploadStatus) { + public void onMediaTapped(final String mediaId, final MediaType mediaType, final JSONObject meta, String uploadStatus) { + if (mediaType == null) { + return; + } + switch (uploadStatus) { case "uploading": // Display 'cancel upload' dialog @@ -993,8 +1048,14 @@ public void onClick(DialogInterface dialog, int id) { mWebView.post(new Runnable() { @Override public void run() { - mWebView.execJavaScriptFromString("ZSSEditor.removeImage(" + mediaId + ");"); - mUploadingMediaIds.remove(mediaId); + switch (mediaType) { + case IMAGE: + mWebView.execJavaScriptFromString("ZSSEditor.removeImage(" + mediaId + ");"); + break; + case VIDEO: + mWebView.execJavaScriptFromString("ZSSEditor.removeVideo(" + mediaId + ");"); + } + mUploadingMedia.remove(mediaId); } }); dialog.dismiss(); @@ -1017,15 +1078,30 @@ public void onClick(DialogInterface dialog, int id) { mWebView.post(new Runnable() { @Override public void run() { - mWebView.execJavaScriptFromString("ZSSEditor.unmarkImageUploadFailed(" + mediaId + ");"); - mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + mediaId + ", " + 0 + ");"); + switch (mediaType) { + case IMAGE: + mWebView.execJavaScriptFromString("ZSSEditor.unmarkImageUploadFailed(" + mediaId + + ");"); + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnImage(" + mediaId + ", " + + 0 + ");"); + break; + case VIDEO: + mWebView.execJavaScriptFromString("ZSSEditor.unmarkVideoUploadFailed(" + mediaId + + ");"); + mWebView.execJavaScriptFromString("ZSSEditor.setProgressOnVideo(" + mediaId + ", " + + 0 + ");"); + } mFailedMediaIds.remove(mediaId); - mUploadingMediaIds.add(mediaId); + mUploadingMedia.put(mediaId, mediaType); } }); break; default: - // Show media options fragment + if (!mediaType.equals(MediaType.IMAGE)) { + return; + } + + // Only show image options fragment for image taps FragmentManager fragmentManager = getFragmentManager(); if (fragmentManager.findFragmentByTag(ImageSettingsDialogFragment.IMAGE_SETTINGS_DIALOG_TAG) != null) { @@ -1125,7 +1201,7 @@ public void onGetHtmlResponse(Map inputArgs) { mJavaScriptResult = inputArgs.get("result"); mGetSelectedTextCountDownLatch.countDown(); break; - case "getFailedImages": + case "getFailedMedia": String[] mediaIds = inputArgs.get("ids").split(","); for (String mediaId : mediaIds) { if (!mediaId.equals("")) { diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java index c8101d88829a..d2eb0d011709 100644 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java @@ -27,6 +27,21 @@ public abstract class EditorFragmentAbstract extends Fragment { // TODO: remove this as soon as we can (we'll need to drop the legacy editor or fix html2spanned translation) public abstract Spanned getSpannedContent(); + public enum MediaType { + IMAGE, VIDEO; + + public static MediaType fromString(String value) { + if (value != null) { + for (MediaType mediaType : MediaType.values()) { + if (value.equalsIgnoreCase(mediaType.toString())) { + return mediaType; + } + } + } + return null; + } + } + private static final String FEATURED_IMAGE_SUPPORT_KEY = "featured-image-supported"; private static final String FEATURED_IMAGE_WIDTH_KEY = "featured-image-width"; diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorMediaUploadListener.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorMediaUploadListener.java index 5d52fd95943b..26ba44150379 100644 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorMediaUploadListener.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorMediaUploadListener.java @@ -1,7 +1,9 @@ package org.wordpress.android.editor; +import org.wordpress.android.util.helpers.MediaFile; + public interface EditorMediaUploadListener { - void onMediaUploadSucceeded(String localId, String remoteId, String remoteUrl); + void onMediaUploadSucceeded(String localId, MediaFile mediaFile); void onMediaUploadProgress(String localId, float progress); void onMediaUploadFailed(String localId, String errorMessage); void onGalleryMediaUploadSucceeded(long galleryId, String remoteId, int remaining); diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java index 6e74071c66a4..c957e095d8e0 100755 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/JsCallbackReceiver.java @@ -13,6 +13,8 @@ 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 = "~"; @@ -103,6 +105,7 @@ public void executeCallback(String callbackId, String params) { mediaIds.add("id"); mediaIds.add("url"); mediaIds.add("meta"); + mediaIds.add("type"); Set mediaDataSet = Utils.splitValuePairDelimitedString(params, JS_CALLBACK_DELIMITER, mediaIds); Map mediaDataMap = Utils.buildMapFromKeyValuePairs(mediaDataSet); @@ -114,6 +117,8 @@ public void executeCallback(String callbackId, String params) { mediaUrl = Utils.decodeHtml(mediaUrl); } + MediaType mediaType = MediaType.fromString(mediaDataMap.get("type")); + String mediaMeta = mediaDataMap.get("meta"); JSONObject mediaMetaJson = new JSONObject(); @@ -136,7 +141,7 @@ public void executeCallback(String callbackId, String params) { } } - mListener.onMediaTapped(mediaId, mediaUrl, mediaMetaJson, uploadStatus); + mListener.onMediaTapped(mediaId, mediaType, mediaMetaJson, uploadStatus); break; case CALLBACK_LINK_TAP: // Extract and HTML-decode the link data from the callback params @@ -188,7 +193,7 @@ public void executeCallback(String callbackId, String params) { case "getSelectedText": responseIds.add("result"); break; - case "getFailedImages": + case "getFailedMedia": responseIds.add("ids"); } diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/OnJsEditorStateChangedListener.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/OnJsEditorStateChangedListener.java index 27d9b7fa5082..58de357ea496 100755 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/OnJsEditorStateChangedListener.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/OnJsEditorStateChangedListener.java @@ -4,11 +4,13 @@ import java.util.Map; +import static org.wordpress.android.editor.EditorFragmentAbstract.MediaType; + public interface OnJsEditorStateChangedListener { void onDomLoaded(); void onSelectionChanged(Map selectionArgs); void onSelectionStyleChanged(Map changeSet); - void onMediaTapped(String mediaId, String url, JSONObject meta, String uploadStatus); + void onMediaTapped(String mediaId, MediaType mediaType, JSONObject meta, String uploadStatus); void onLinkTapped(String url, String title); void onVideoPressInfoRequested(String videoId); void onGetHtmlResponse(Map responseArgs); diff --git a/WordPressEditor/src/main/java/org/wordpress/android/editor/Utils.java b/WordPressEditor/src/main/java/org/wordpress/android/editor/Utils.java index c4c5665defef..62297005e542 100644 --- a/WordPressEditor/src/main/java/org/wordpress/android/editor/Utils.java +++ b/WordPressEditor/src/main/java/org/wordpress/android/editor/Utils.java @@ -73,6 +73,13 @@ public static String decodeHtml(String html) { return html; } + public static String escapeQuotes(String text) { + if (text != null) { + text = text.replace("'", "\\'").replace("\"", "\\\""); + } + return text; + } + /** * Splits a delimited string into a set of strings. * @param string the delimited string to split diff --git a/example/src/main/java/org/wordpress/example/EditorExampleActivity.java b/example/src/main/java/org/wordpress/example/EditorExampleActivity.java index 0980b250ee40..e9525daad480 100644 --- a/example/src/main/java/org/wordpress/example/EditorExampleActivity.java +++ b/example/src/main/java/org/wordpress/example/EditorExampleActivity.java @@ -37,8 +37,10 @@ public class EditorExampleActivity extends AppCompatActivity implements EditorFr public static final String MEDIA_REMOTE_ID_SAMPLE = "123"; - private static final int SELECT_PHOTO_MENU_POSITION = 0; - private static final int SELECT_PHOTO_FAIL_MENU_POSITION = 1; + private static final int SELECT_IMAGE_MENU_POSITION = 0; + private static final int SELECT_IMAGE_FAIL_MENU_POSITION = 1; + private static final int SELECT_VIDEO_MENU_POSITION = 2; + private static final int SELECT_VIDEO_FAIL_MENU_POSITION = 3; private EditorFragmentAbstract mEditorFragment; @@ -79,8 +81,10 @@ public void onBackPressed() { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - menu.add(0, SELECT_PHOTO_MENU_POSITION, 0, getString(R.string.select_photo)); - menu.add(0, SELECT_PHOTO_FAIL_MENU_POSITION, 0, getString(R.string.select_photo_fail)); + menu.add(0, SELECT_IMAGE_MENU_POSITION, 0, getString(R.string.select_image)); + menu.add(0, SELECT_IMAGE_FAIL_MENU_POSITION, 0, getString(R.string.select_image_fail)); + menu.add(0, SELECT_VIDEO_MENU_POSITION, 0, getString(R.string.select_video)); + menu.add(0, SELECT_VIDEO_FAIL_MENU_POSITION, 0, getString(R.string.select_video_fail)); } @Override @@ -88,17 +92,31 @@ public boolean onContextItemSelected(MenuItem item) { Intent intent = new Intent(Intent.ACTION_PICK); switch (item.getItemId()) { - case SELECT_PHOTO_MENU_POSITION: + case SELECT_IMAGE_MENU_POSITION: intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); - intent = Intent.createChooser(intent, getString(R.string.select_photo)); + intent = Intent.createChooser(intent, getString(R.string.select_image)); startActivityForResult(intent, ADD_MEDIA_ACTIVITY_REQUEST_CODE); return true; - case SELECT_PHOTO_FAIL_MENU_POSITION: + case SELECT_IMAGE_FAIL_MENU_POSITION: intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); - intent = Intent.createChooser(intent, getString(R.string.select_photo_fail)); + intent = Intent.createChooser(intent, getString(R.string.select_image_fail)); + + startActivityForResult(intent, ADD_MEDIA_FAIL_ACTIVITY_REQUEST_CODE); + return true; + case SELECT_VIDEO_MENU_POSITION: + intent.setType("video/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + intent = Intent.createChooser(intent, getString(R.string.select_video)); + + startActivityForResult(intent, ADD_MEDIA_ACTIVITY_REQUEST_CODE); + return true; + case SELECT_VIDEO_FAIL_MENU_POSITION: + intent.setType("video/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + intent = Intent.createChooser(intent, getString(R.string.select_video_fail)); startActivityForResult(intent, ADD_MEDIA_FAIL_ACTIVITY_REQUEST_CODE); return true; @@ -120,6 +138,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { MediaFile mediaFile = new MediaFile(); String mediaId = String.valueOf(System.currentTimeMillis()); mediaFile.setMediaId(mediaId); + mediaFile.setVideo(imageUri.toString().contains("video")); switch (requestCode) { case ADD_MEDIA_ACTIVITY_REQUEST_CODE: @@ -217,8 +236,11 @@ public void run() { count += 0.1; } - ((EditorMediaUploadListener) mEditorFragment).onMediaUploadSucceeded(mediaId, - MEDIA_REMOTE_ID_SAMPLE, mediaUrl); + MediaFile mediaFile = new MediaFile(); + mediaFile.setMediaId(MEDIA_REMOTE_ID_SAMPLE); + mediaFile.setFileURL(mediaUrl); + + ((EditorMediaUploadListener) mEditorFragment).onMediaUploadSucceeded(mediaId, mediaFile); if (mFailedUploads.containsKey(mediaId)) { mFailedUploads.remove(mediaId); diff --git a/example/src/main/res/values/strings.xml b/example/src/main/res/values/strings.xml index 753eff8d993f..bfffb0de8fb7 100644 --- a/example/src/main/res/values/strings.xml +++ b/example/src/main/res/values/strings.xml @@ -13,6 +13,8 @@ Post 2 Content

Quoted text

]]>
- Select a photo - Select a photo (failure demo) + Select an image + Select an image (failure demo) + Select a video + Select a video (failure demo) diff --git a/libs/editor-common/assets/ZSSRichTextEditor.js b/libs/editor-common/assets/ZSSRichTextEditor.js index 4918e6ee6306..6cab98bca9cd 100755 --- a/libs/editor-common/assets/ZSSRichTextEditor.js +++ b/libs/editor-common/assets/ZSSRichTextEditor.js @@ -1079,16 +1079,19 @@ ZSSEditor.unmarkImageUploadFailed = function(imageNodeIdentifier) { /** * @brief Marks all in-progress images as failed to upload */ -ZSSEditor.markAllUploadingImagesAsFailed = function(message) { +ZSSEditor.markAllUploadingMediaAsFailed = function(message) { var html = ZSSEditor.getField("zss_field_content").getHTML(); var tmp = document.createElement( "div" ); var tmpDom = $( tmp ).html( html ); var matches = tmpDom.find("img.uploading"); for(var i = 0; i < matches.size(); i++) { - var mediaId = matches[i].getAttribute("data-wpid"); - if (mediaId != null) { + if (matches[i].hasAttribute('data-wpid')) { + var mediaId = matches[i].getAttribute('data-wpid'); ZSSEditor.markImageUploadFailed(mediaId, message); + } else if (matches[i].hasAttribute('data-video_wpid')) { + var videoId = matches[i].getAttribute('data-video_wpid'); + ZSSEditor.markVideoUploadFailed(videoId, message); } } }; @@ -1096,18 +1099,24 @@ ZSSEditor.markAllUploadingImagesAsFailed = function(message) { /** * @brief Sends a callback with a list of failed images */ -ZSSEditor.getFailedImages = function() { +ZSSEditor.getFailedMedia = function() { var html = ZSSEditor.getField("zss_field_content").getHTML(); var tmp = document.createElement( "div" ); var tmpDom = $( tmp ).html( html ); var matches = tmpDom.find("img.failed"); - var functionArgument = "function=getFailedImages"; + var functionArgument = "function=getFailedMedia"; var mediaIdArray = []; - for (var i = 0; i < matches.size(); i ++) { - var mediaId = matches[i].getAttribute("data-wpid"); - if (mediaId != null) { + for (var i = 0; i < matches.size(); i++) { + var mediaId; + if (matches[i].hasAttribute("data-wpid")) { + mediaId = matches[i].getAttribute("data-wpid"); + } else if (matches[i].hasAttribute("data-video_wpid")) { + mediaId = matches[i].getAttribute("data-video_wpid"); + } + + if (mediaId.length > 0) { mediaIdArray.push(mediaId); } } @@ -1138,45 +1147,76 @@ ZSSEditor.removeImage = function(imageNodeIdentifier) { * @brief Inserts a video tag using the videoURL as source and posterURL as the * image to show while video is loading. * - * @param videoURL the url of the video to present - * @param posterURL the url of an image to show while the video is loading - * @param alt the alt description when the video is not supported. + * @param videoURL the url of the video + * @param posterURL the url of an image to show while the video is loading + * @param videoPressID the VideoPress ID of the video, when applicable * */ -ZSSEditor.insertVideo = function(videoURL, posterURL, alt) { - var html = ''; +ZSSEditor.insertVideo = function(videoURL, posterURL, videopressID) { + var html = ''; + out += ' onclick="" controls="controls">
'; return out; } @@ -1531,8 +1538,6 @@ ZSSEditor.setVideoPressLinks = function(videopressID, videoURL, posterURL ) { videoNode.attr('controls', ''); videoNode.attr('poster', posterURL); var thisObj = this; - videoNode.on('webkitbeginfullscreen', function (event){ thisObj.sendVideoFullScreenStarted(); } ); - videoNode.on('webkitendfullscreen', function (event){ thisObj.sendVideoFullScreenEnded(); } ); videoNode.load(); }; @@ -2785,7 +2790,7 @@ ZSSField.prototype.handleTapEvent = function(e) { if (targetNode.nodeName.toLowerCase() == 'img') { // If the image is uploading, or is a local image do not select it. - if ( targetNode.dataset.wpid ) { + if ( targetNode.dataset.wpid || targetNode.dataset.video_wpid ) { this.sendImageTappedCallback( targetNode ); return; } @@ -2858,17 +2863,21 @@ ZSSField.prototype.handleTapEvent = function(e) { } }; -ZSSField.prototype.sendImageTappedCallback = function( imageNode ) { - var meta = JSON.stringify( ZSSEditor.extractImageMeta( imageNode ) ); - var imageId = ""; - if ( imageNode.hasAttribute( 'data-wpid' ) ){ - imageId = imageNode.getAttribute( 'data-wpid' ) +ZSSField.prototype.sendImageTappedCallback = function(imageNode) { + var meta = JSON.stringify(ZSSEditor.extractImageMeta(imageNode)); + var imageId = "", mediaType = "image"; + if (imageNode.hasAttribute('data-wpid')){ + imageId = imageNode.getAttribute('data-wpid'); + } else if (imageNode.hasAttribute('data-video_wpid')){ + imageId = imageNode.getAttribute('data-video_wpid'); + mediaType = "video"; } - var arguments = ['id=' + encodeURIComponent( imageId ), - 'url=' + encodeURIComponent( imageNode.src ), - 'meta=' + encodeURIComponent( meta )]; + var arguments = ['id=' + encodeURIComponent(imageId), + 'url=' + encodeURIComponent(imageNode.src), + 'meta=' + encodeURIComponent(meta), + 'type=' + mediaType]; - var joinedArguments = arguments.join( defaultCallbackSeparator ); + var joinedArguments = arguments.join(defaultCallbackSeparator); var thisObj = this; @@ -2890,22 +2899,6 @@ ZSSField.prototype.sendVideoTappedCallback = function( videoNode ) { ZSSEditor.callback('callback-video-tap', joinedArguments); } -/** - * @brief Callbacks to native that the video entered full screen mode - * - */ -ZSSField.prototype.sendVideoFullScreenStarted = function() { - this.callback("callback-video-fullscreen-started", "empty"); -}; - -/** - * @brief Callbacks to native that the video entered full screen mode - * - */ -ZSSField.prototype.sendVideoFullScreenEnded = function() { - this.callback("callback-video-fullscreen-ended", "empty"); -}; - // MARK: - Callback Execution ZSSField.prototype.callback = function(callbackScheme, callbackPath) { diff --git a/libs/editor-common/assets/editor-android.css b/libs/editor-common/assets/editor-android.css index e3d0aef8701a..34d8dd54b6fe 100644 --- a/libs/editor-common/assets/editor-android.css +++ b/libs/editor-common/assets/editor-android.css @@ -30,13 +30,15 @@ video::-webkit-media-controls-fullscreen-button { } /* Used only on older APIs (API<19), where using inline-block is buggy and sometimes displays a very small container */ -span.img_container.compat { +span.img_container.compat, +span.video_container.compat { display: block; } /* Used on API<19 to darken the image so that the 'uploading' and 'retry' overlays can still be seen when the image is light */ -.img_container .upload-overlay-bg { +.img_container .upload-overlay-bg, +.video_container .upload-overlay-bg { position: absolute; width: 100%; height: 100%; @@ -48,19 +50,22 @@ light */ than its containing image. The upload-overlay-bg is larger as well, leaving a dark line below the image. By setting display:block on the image and setting a width limit we get around this issue. */ -.img_container .upload-overlay-bg ~ img.uploading { +.img_container .upload-overlay-bg ~ img.uploading, +.video_container .upload-overlay-bg ~ img.uploading { display:block; max-width:100%; } -.img_container .upload-overlay-bg ~ img.failed { +.img_container .upload-overlay-bg ~ img.failed, +.video_container .upload-overlay-bg ~ img.failed{ display:block; max-width:100%; } /* Used only on older APIs (API<19) instead of a progress bar for uploading images, since the WebView at those API levels does not support the progress tag */ -.img_container .upload-overlay { +.img_container .upload-overlay, +.video_container .upload-overlay{ position: absolute; top: 50%; -webkit-transform: translateY(-50%); @@ -75,6 +80,7 @@ display:block on the image and setting a width limit we get around this issue. * color: white; } -.img_container .upload-overlay.failed { +.img_container .upload-overlay.failed, +.video_container .upload-overlay.failed{ visibility: hidden; } \ No newline at end of file