Skip to content

Commit c5b98a8

Browse files
committed
Squashed 'libs/editor/' changes from a35d654..0f6fba8
0f6fba8 Merge pull request #334 from wordpress-mobile/issue/292-backspace-bug 041f285 Changed ZSSEditor.getYCaretInfo to find parent contenteditable divs correctly 92cb325 Fixed an issue with losing cursor focus on API<19 0c2b5fd Made blockquote parsing handle DIVs tags as paragraphs c62ce8e Convert divs to paragraph tags when extracting the HTML from the editor f5e5d26 Changed getFocusedField to use this.focusedField, in order to avoid div targeting issues now that paragraphs are also divs c925ebd Add line height and margin styling to div tags (duplicated from p tags, and excluding the contenteditable and separator divs eb1677c Drop defaultParagraphSeparator assignment and use divs instead of ps for paragraphs (WebView default) 5e90578 Merge pull request #333 from wordpress-mobile/issue/258-remove-failed-uploads-when-switching-to-html-mode 9a0ef46 Merge commit '4c9324cf1eee00b66c76e0d5a917c86e1293a845' into develop ac96e74 fix #258: prompt the user to delete failed uploads before switching to HTML mode b856f7b update to android-gradle 2.0.0-rc1 e6f4e6b Add missing classes for images inserted from media library - also fix a bug with undefined alt text 31d2970 Add missing attributes for uploaded images ce6ab9d update to android-gradle-2.0.0-rc1 git-subtree-dir: libs/editor git-subtree-split: 0f6fba8fc434c4007c7cdd300c4dd9fa2df5a218
1 parent 4c9324c commit c5b98a8

File tree

6 files changed

+128
-59
lines changed

6 files changed

+128
-59
lines changed

WordPressEditor/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ buildscript {
33
jcenter()
44
}
55
dependencies {
6-
classpath 'com.android.tools.build:gradle:2.0.0-beta7'
6+
classpath 'com.android.tools.build:gradle:2.0.0-rc1'
77
}
88
}
99

WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragment.java

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.app.FragmentTransaction;
66
import android.content.Context;
77
import android.content.DialogInterface;
8+
import android.content.DialogInterface.OnClickListener;
89
import android.content.Intent;
910
import android.content.res.Configuration;
1011
import android.net.Uri;
@@ -407,55 +408,82 @@ protected void initJsEditor() {
407408
}
408409
}
409410

410-
@Override
411-
public void onClick(View v) {
412-
int id = v.getId();
413-
if (id == R.id.format_bar_button_html) {
414-
mEditorFragmentListener.onTrackableEvent(TrackableEvent.HTML_BUTTON_TAPPED);
411+
public void checkForFailedUploadAndSwitchToHtmlMode(final ToggleButton toggleButton) {
412+
// Show an Alert Dialog asking the user if he wants to remove all failed media before upload
413+
if (hasFailedMediaUploads()) {
414+
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
415+
builder.setMessage(R.string.editor_failed_uploads_switch_html)
416+
.setPositiveButton(R.string.editor_remove_failed_uploads, new OnClickListener() {
417+
public void onClick(DialogInterface dialog, int id) {
418+
// Clear failed uploads and switch to HTML mode
419+
removeAllFailedMediaUploads();
420+
toggleHtmlMode(toggleButton);
421+
}
422+
}).setNegativeButton(android.R.string.cancel, new OnClickListener() {
423+
@Override
424+
public void onClick(DialogInterface dialog, int which) {
425+
toggleButton.setChecked(false);
426+
}
427+
});
428+
builder.create().show();
429+
} else {
430+
toggleHtmlMode(toggleButton);
431+
}
432+
}
415433

416-
// Don't switch to HTML mode if currently uploading media
417-
if (!mUploadingMedia.isEmpty()) {
418-
((ToggleButton) v).setChecked(false);
434+
private void toggleHtmlMode(final ToggleButton toggleButton) {
435+
mEditorFragmentListener.onTrackableEvent(TrackableEvent.HTML_BUTTON_TAPPED);
419436

420-
if (isAdded()) {
421-
ToastUtils.showToast(getActivity(), R.string.alert_html_toggle_uploading, ToastUtils.Duration.LONG);
422-
}
423-
return;
437+
// Don't switch to HTML mode if currently uploading media
438+
if (!mUploadingMedia.isEmpty()) {
439+
toggleButton.setChecked(false);
440+
441+
if (isAdded()) {
442+
ToastUtils.showToast(getActivity(), R.string.alert_html_toggle_uploading, ToastUtils.Duration.LONG);
424443
}
444+
return;
445+
}
425446

426-
clearFormatBarButtons();
427-
updateFormatBarEnabledState(true);
447+
clearFormatBarButtons();
448+
updateFormatBarEnabledState(true);
428449

429-
if (((ToggleButton) v).isChecked()) {
430-
mSourceViewTitle.setText(getTitle());
450+
if (toggleButton.isChecked()) {
451+
mSourceViewTitle.setText(getTitle());
431452

432-
SpannableString spannableContent = new SpannableString(getContent());
433-
HtmlStyleUtils.styleHtmlForDisplay(spannableContent);
434-
mSourceViewContent.setText(spannableContent);
453+
SpannableString spannableContent = new SpannableString(getContent());
454+
HtmlStyleUtils.styleHtmlForDisplay(spannableContent);
455+
mSourceViewContent.setText(spannableContent);
435456

436-
mWebView.setVisibility(View.GONE);
437-
mSourceView.setVisibility(View.VISIBLE);
457+
mWebView.setVisibility(View.GONE);
458+
mSourceView.setVisibility(View.VISIBLE);
438459

439-
mSourceViewContent.requestFocus();
440-
mSourceViewContent.setSelection(0);
460+
mSourceViewContent.requestFocus();
461+
mSourceViewContent.setSelection(0);
441462

442-
InputMethodManager imm = ((InputMethodManager) getActivity()
443-
.getSystemService(Context.INPUT_METHOD_SERVICE));
444-
imm.showSoftInput(mSourceViewContent, InputMethodManager.SHOW_IMPLICIT);
445-
} else {
446-
mWebView.setVisibility(View.VISIBLE);
447-
mSourceView.setVisibility(View.GONE);
463+
InputMethodManager imm = ((InputMethodManager) getActivity()
464+
.getSystemService(Context.INPUT_METHOD_SERVICE));
465+
imm.showSoftInput(mSourceViewContent, InputMethodManager.SHOW_IMPLICIT);
466+
} else {
467+
mWebView.setVisibility(View.VISIBLE);
468+
mSourceView.setVisibility(View.GONE);
448469

449-
mTitle = mSourceViewTitle.getText().toString();
450-
mContentHtml = mSourceViewContent.getText().toString();
451-
updateVisualEditorFields();
470+
mTitle = mSourceViewTitle.getText().toString();
471+
mContentHtml = mSourceViewContent.getText().toString();
472+
updateVisualEditorFields();
452473

453-
// Update the list of failed media uploads
454-
mWebView.execJavaScriptFromString("ZSSEditor.getFailedMedia();");
474+
// Update the list of failed media uploads
475+
mWebView.execJavaScriptFromString("ZSSEditor.getFailedMedia();");
455476

456-
// Reset selection to avoid buggy cursor behavior
457-
mWebView.execJavaScriptFromString("ZSSEditor.resetSelectionOnField('zss_field_content');");
458-
}
477+
// Reset selection to avoid buggy cursor behavior
478+
mWebView.execJavaScriptFromString("ZSSEditor.resetSelectionOnField('zss_field_content');");
479+
}
480+
}
481+
482+
@Override
483+
public void onClick(View v) {
484+
int id = v.getId();
485+
if (id == R.id.format_bar_button_html) {
486+
checkForFailedUploadAndSwitchToHtmlMode((ToggleButton) v);
459487
} else if (id == R.id.format_bar_button_media) {
460488
mEditorFragmentListener.onTrackableEvent(TrackableEvent.MEDIA_BUTTON_TAPPED);
461489
((ToggleButton) v).setChecked(false);

WordPressEditor/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,7 @@
8181
<string name="image_thumbnail">Image thumbnail</string>
8282

8383

84+
<string name="editor_failed_uploads_switch_html">Some media uploads have failed. You can\'t switch to HTML mode
85+
in this state. Remove all failed uploads and continue?</string>
86+
<string name="editor_remove_failed_uploads">Remove failed uploads</string>
8487
</resources>

example/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ buildscript {
33
jcenter()
44
}
55
dependencies {
6-
classpath 'com.android.tools.build:gradle:2.0.0-beta7'
6+
classpath 'com.android.tools.build:gradle:2.0.0-rc1'
77
}
88
}
99

libs/editor-common/assets/ZSSRichTextEditor.js

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ const NodeName = {
2626
LI: "LI",
2727
CODE: "CODE",
2828
SPAN: "SPAN",
29-
BR: "BR"
29+
BR: "BR",
30+
DIV: "DIV",
31+
BODY: "BODY"
3032
};
3133

3234
// The editor object
@@ -63,7 +65,7 @@ ZSSEditor.editableFields = {};
6365
ZSSEditor.lastTappedNode = null;
6466

6567
// The default paragraph separator
66-
ZSSEditor.defaultParagraphSeparator = 'p';
68+
ZSSEditor.defaultParagraphSeparator = 'div';
6769

6870
// Video format tags supported by the [video] shortcode: https://codex.wordpress.org/Video_Shortcode
6971
// mp4, m4v and webm prioritized since they're supported by the stock player as of Android API 23
@@ -92,7 +94,6 @@ ZSSEditor.init = function() {
9294
}
9395

9496
document.execCommand('insertBrOnReturn', false, false);
95-
document.execCommand('defaultParagraphSeparator', false, this.defaultParagraphSeparator);
9697

9798
var editor = $('div.field').each(function() {
9899
var editableField = new ZSSField($(this));
@@ -172,7 +173,7 @@ ZSSEditor.formatNewLine = function(e) {
172173
this.formatNewLineInsideBlockquote(e);
173174
} else if (!ZSSEditor.isCommandEnabled('insertOrderedList')
174175
&& !ZSSEditor.isCommandEnabled('insertUnorderedList')) {
175-
document.execCommand('formatBlock', false, 'p');
176+
document.execCommand('formatBlock', false, 'div');
176177
}
177178
} else {
178179
e.preventDefault();
@@ -192,20 +193,13 @@ ZSSEditor.getField = function(fieldId) {
192193
};
193194

194195
ZSSEditor.getFocusedField = function() {
195-
var currentField = $(this.closerParentNodeWithName('div'));
196+
var currentField = $(this.findParentContenteditableDiv());
196197
var currentFieldId;
197198

198199
if (currentField) {
199200
currentFieldId = currentField.attr('id');
200201
}
201202

202-
while (currentField && (!currentFieldId || this.editableFields[currentFieldId] == null)) {
203-
currentField = this.closerParentNodeStartingAtNode('div', currentField);
204-
if (currentField) {
205-
currentFieldId = currentField.attr('id');
206-
}
207-
}
208-
209203
if (!currentFieldId) {
210204
ZSSEditor.resetSelectionOnField('zss_field_content');
211205
currentFieldId = 'zss_field_content';
@@ -480,7 +474,7 @@ ZSSEditor.getYCaretInfo = function() {
480474
//
481475
if (needsToWorkAroundNewlineBug) {
482476
var closerParentNode = ZSSEditor.closerParentNode();
483-
var closerDiv = ZSSEditor.closerParentNodeWithName('div');
477+
var closerDiv = ZSSEditor.findParentContenteditableDiv();
484478

485479
var fontSize = $(closerParentNode).css('font-size');
486480
var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
@@ -654,7 +648,7 @@ ZSSEditor.setHeading = function(heading) {
654648
};
655649

656650
ZSSEditor.setParagraph = function() {
657-
var formatTag = "p";
651+
var formatTag = "div";
658652
var formatBlock = document.queryCommandValue('formatBlock');
659653

660654
if (formatBlock.length > 0 && formatBlock.toLowerCase() == formatTag) {
@@ -1028,8 +1022,11 @@ ZSSEditor.updateImage = function(url, alt) {
10281022
};
10291023

10301024
ZSSEditor.insertImage = function(url, remoteId, alt) {
1031-
var html = '<img src="' + url + '" alt="' + alt + '" class="wp-image-' + remoteId + '" />';
1032-
1025+
var html = '<img src="' + url + '" class="wp-image-' + remoteId + ' alignnone size-full';
1026+
if (alt) {
1027+
html += '" alt="' + alt
1028+
}
1029+
html += '"/>'
10331030
this.insertHTML(this.wrapInParagraphTags(html));
10341031
this.sendEnabledStyles();
10351032
};
@@ -1138,6 +1135,9 @@ ZSSEditor.finishLocalImageSwap = function(image, imageNode, imageNodeIdentifier,
11381135
imageNode.attr('remoteurl', image.getAttribute("remoteurl"));
11391136
}
11401137
imageNode.attr('src', image.src);
1138+
// Set extra attributes and classes used by WordPress
1139+
imageNode.attr({'width': image.width, 'height': image.height});
1140+
imageNode.addClass("alignnone size-full");
11411141
ZSSEditor.markImageUploadDone(imageNodeIdentifier);
11421142
var joinedArguments = ZSSEditor.getJoinedFocusedFieldIdAndCaretArguments();
11431143
ZSSEditor.callback("callback-input", joinedArguments);
@@ -2289,7 +2289,7 @@ ZSSEditor.removeVisualFormatting = function( html ) {
22892289
str = ZSSEditor.replaceVideoPressVideosForShortcode( str );
22902290
str = ZSSEditor.replaceVideosForShortcode( str );
22912291
return str;
2292-
}
2292+
};
22932293

22942294
ZSSEditor.insertHTML = function(html) {
22952295
document.execCommand('insertHTML', false, html);
@@ -2618,7 +2618,9 @@ ZSSEditor.getAncestorElementForSettingBlockquote = function(range) {
26182618
|| parentElement.nodeName == NodeName.OL
26192619
|| parentElement.nodeName == NodeName.LI
26202620
|| parentElement.nodeName == NodeName.CODE
2621-
|| parentElement.nodeName == NodeName.SPAN)) {
2621+
|| parentElement.nodeName == NodeName.SPAN
2622+
// Include nested divs, but ignore the parent contenteditable field div
2623+
|| (parentElement.nodeName == NodeName.DIV && parentElement.parentElement.nodeName != NodeName.BODY))) {
26222624
parentElement = parentElement.parentNode;
26232625
}
26242626

@@ -2740,6 +2742,23 @@ ZSSEditor.hasPreviousSiblingWithName = function(node, siblingNodeName) {
27402742

27412743
// MARK: - Parent nodes & tags
27422744

2745+
ZSSEditor.findParentContenteditableDiv = function() {
2746+
var parentNode = null;
2747+
var selection = window.getSelection();
2748+
if (selection.rangeCount < 1) {
2749+
return null;
2750+
}
2751+
var range = selection.getRangeAt(0).cloneRange();
2752+
2753+
var referenceNode = this.closerParentNodeWithNameRelativeToNode('div', range.commonAncestorContainer);
2754+
2755+
while (referenceNode.parentNode.nodeName != NodeName.BODY) {
2756+
referenceNode = this.closerParentNodeWithNameRelativeToNode('div', referenceNode.parentNode);
2757+
}
2758+
2759+
return referenceNode;
2760+
};
2761+
27432762
ZSSEditor.closerParentNode = function() {
27442763

27452764
var parentNode = null;
@@ -3246,7 +3265,7 @@ ZSSField.prototype.wrapCaretInParagraphIfNecessary = function()
32463265
var range = selection.getRangeAt(0);
32473266

32483267
if (range.startContainer == range.endContainer) {
3249-
var paragraph = document.createElement("p");
3268+
var paragraph = document.createElement("div");
32503269
var textNode = document.createTextNode("&#x200b;");
32513270

32523271
paragraph.appendChild(textNode);
@@ -3285,7 +3304,11 @@ ZSSField.prototype.isEmpty = function() {
32853304
};
32863305

32873306
ZSSField.prototype.getHTML = function() {
3288-
var html = wp.saveText(this.wrappedObject.html());
3307+
var html = this.wrappedObject.html();
3308+
if (ZSSEditor.defaultParagraphSeparator == 'div') {
3309+
html = html.replace(/(<div)/igm, '<p').replace(/<\/div>/igm, '</p>');
3310+
}
3311+
html = wp.saveText(html);
32893312
html = ZSSEditor.removeVisualFormatting( html );
32903313
return html;
32913314
};
@@ -3312,6 +3335,12 @@ ZSSField.prototype.setHTML = function(html) {
33123335
ZSSEditor.currentEditingImage = null;
33133336
var mutatedHTML = wp.loadText(html);
33143337
mutatedHTML = ZSSEditor.applyVisualFormatting(mutatedHTML);
3338+
3339+
if (ZSSEditor.defaultParagraphSeparator == 'div') {
3340+
// Replace the paragraph tags we get from wpload with divs
3341+
mutatedHTML = mutatedHTML.replace(/(<p)/igm, '<div').replace(/<\/p>/igm, '</div>');
3342+
}
3343+
33153344
this.wrappedObject.html(mutatedHTML);
33163345
};
33173346

libs/editor-common/assets/editor-android.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ video::-webkit-media-controls-fullscreen-button {
1616
display: none;
1717
}
1818

19+
/* Duplicates paragraph tag formatting for div tags, which are needed on Android API 19+ due to autocorrect issues:
20+
https://bugs.chromium.org/p/chromium/issues/detail?id=599890
21+
*/
22+
div:not(.field):not(#separatorDiv) {
23+
line-height: 24px;
24+
margin-top: 0px;
25+
margin-bottom: 24px;
26+
}
27+
1928
/* --- API<19 workarounds --- */
2029

2130
/* Used only on older APIs (API<19), which don't support CSS filter effects (specifically, blur). */

0 commit comments

Comments
 (0)