Skip to content

Commit

Permalink
Squashed 'libs/editor/' changes from e0a8651..244a513
Browse files Browse the repository at this point in the history
244a513 Removed unused ModalDialog style
2079b91 Removed styling of legacy.EditLinkActivity, leaving it up to WPAndroid
bcfe5db 0.3 version bump
13d8db4 Merge pull request #226 from wordpress-mobile/issue/210-blockquote-list-wrap
42a4a5e Fixed confusing comment
c103bdb Updates blockquoting after "double enter" to end a list; refactoed list code
331ea9b Merge branch 'develop' of github.com:wordpress-mobile/WordPress-Editor-Android into issue/210-blockquote-list-wrap
4092508 Merge pull request #225 from wordpress-mobile/feature/186-edit-link
7520bdf First crack at fixing blockquote and list bug
e3b1f23 Merge branch 'develop' into feature/186-edit-link
7347f12 Disabled all links in the WebView, so tapping links on API<19 doesn't cause the WebView to navigate to them
21d7817 Changed the link button to remove the current link instead of displaying the link dialog
3ac9fab Added a delete button to LinkDialogFragment which removes the link being updated
c5b64e5 Updated the editor to support modifying links when tapping them
a484307 Added tests for utility methods decodeHtml and splitValuePairDelimitedString
bd30fac Added handling for callback-link-tap
87e3028 Improved the process of extracting key-value pairs from callback strings
7d5f231 Merge pull request #220 from wordpress-mobile/issue/197-rotation-redraw
f579c2e Escape HTML in link url and text before passing to ZSSEditor.insertLink()
c306a83 Merge branch 'develop' into issue/197-rotation-redraw
845833c Merge pull request #217 from wordpress-mobile/issue/213-Merriweather-consistency
1a9beb4 Merge pull request #216 from wordpress-mobile/issue/215-legacy-toggle-button-size
5c2ee5b Merge pull request #221 from wordpress-mobile/issue/218-api16-html-crash
943542c Merge pull request #214 from wordpress-mobile/feature/185-insert-link
35f12c6 Update HtmlStyleUtils to not apply spans when running Android 4.1 and 4.1.1
74034ed Updated the editor to update HTML mode margins on rotation
25e378f Preserve the active format bar buttons on orientation change
9b97b2d Updated the editor to reload the format bar on rotation
09196d3 Changed the example activity to preserve the editor fragment on rotation, imitating the WPAndroid app
c963b80 Extracted format bar layout into width-specific XML files
8ab72ac Updated Merriweather font files
17a8fce Reverted changes to legacy format bar
f33c8b5 Moved EditLinkActivity back to legacy folder
b07a7ba Switched to using a DialogFragment for the link dialog
b863118 Improved recognition of link style
3fbccd6 Added support for inserting links in HTML mode
ae5c2aa Added support for adding a link to existing, highlighted text in visual mode
56a0e82 Changed ZSSEditor.insertLink() to use execCommand instead of document.createElement
8e146f6 Added support for retrieving the selected text from the ZSSEditor
54555f7 Added support for inserting links using the format bar button (no highlight support)
1824cf6 Updated onSelectionStyleChanged to recognize links and toggle the link button highlighting accordingly
70c2ac0 Moved EditLinkActivity out of legacy folder
dca254f Changed EditLinkActivity to a modal dialog (replicating its appearance within WPAndroid)
0cdabf4 Merge pull request #209 from wordpress-mobile/issue/203-fix-legacy-format-bar
e8c7d2c Merge pull request #211 from wordpress-mobile/issue/208-html-mode-content-placeholder
34e32fa Set the content placeholder in HTML mode, wrapped in p tags
c39031e Defined a separate dimen for the legacy format bar height and set it back to 40dp

git-subtree-dir: libs/editor
git-subtree-split: 244a51315e24eddc0510b422a75e6483c6c0f6f3
  • Loading branch information
aforcier committed Aug 18, 2015
1 parent f9336b1 commit 33111c4
Show file tree
Hide file tree
Showing 32 changed files with 1,063 additions and 751 deletions.
4 changes: 2 additions & 2 deletions WordPressEditor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ android {
buildToolsVersion "22.0.1"

defaultConfig {
versionCode 2
versionName "0.2"
versionCode 3
versionName "0.3"
minSdkVersion 14
targetSdkVersion 22
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
Expand All @@ -27,6 +28,7 @@
import org.wordpress.android.util.helpers.MediaFile;
import org.wordpress.android.util.helpers.MediaGallery;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
Expand All @@ -53,13 +55,19 @@ public class EditorFragment extends EditorFragmentAbstract implements View.OnCli
private SourceViewEditText mSourceViewTitle;
private SourceViewEditText mSourceViewContent;

private int mSelectionStart;
private int mSelectionEnd;

private String mTitlePlaceholder = "";
private String mContentPlaceholder = "";

private boolean mHideActionBarOnSoftKeyboardUp;

private String mJavaScriptResult = "";

private CountDownLatch mGetTitleCountDownLatch;
private CountDownLatch mGetContentCountDownLatch;
private CountDownLatch mGetSelectedTextCountDownLatch;

private final Map<String, ToggleButton> mTagToggleButtonMap = new HashMap<>();

Expand Down Expand Up @@ -138,42 +146,11 @@ public void onFocusChange(View v, boolean hasFocus) {
mSourceViewContent.addTextChangedListener(new HtmlStyleTextWatcher());

mSourceViewTitle.setHint(mTitlePlaceholder);
mSourceViewContent.setHint("<p>" + mContentPlaceholder + "</p>");

// -- Format bar configuration

ToggleButton boldButton = (ToggleButton) view.findViewById(R.id.format_bar_button_bold);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_bold), boldButton);

ToggleButton italicButton = (ToggleButton) view.findViewById(R.id.format_bar_button_italic);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_italic), italicButton);

ToggleButton quoteButton = (ToggleButton) view.findViewById(R.id.format_bar_button_quote);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_blockquote), quoteButton);

ToggleButton ulButton = (ToggleButton) view.findViewById(R.id.format_bar_button_ul);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_unorderedList), ulButton);

ToggleButton olButton = (ToggleButton) view.findViewById(R.id.format_bar_button_ol);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_orderedList), olButton);

// Tablet-only
ToggleButton strikethroughButton = (ToggleButton) view.findViewById(R.id.format_bar_button_strikethrough);
if (strikethroughButton != null) {
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_strikethrough), strikethroughButton);
}

ToggleButton mediaButton = (ToggleButton) view.findViewById(R.id.format_bar_button_media);
mTagToggleButtonMap.put(TAG_FORMAT_BAR_BUTTON_MEDIA, mediaButton);

ToggleButton linkButton = (ToggleButton) view.findViewById(R.id.format_bar_button_link);
mTagToggleButtonMap.put(TAG_FORMAT_BAR_BUTTON_LINK, linkButton);

ToggleButton htmlButton = (ToggleButton) view.findViewById(R.id.format_bar_button_html);
htmlButton.setOnClickListener(this);

for (ToggleButton button : mTagToggleButtonMap.values()) {
button.setOnClickListener(this);
}
setupFormatBarButtonMap(view);

return view;
}
Expand All @@ -199,6 +176,56 @@ private ActionBar getActionBar() {
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);

if (getView() != null) {
// Reload the format bar to make sure the correct one for the new screen width is being used
View formatBar = getView().findViewById(R.id.format_bar);

if (formatBar != null) {
// Remember the currently active format bar buttons so they can be re-activated after the reload
ArrayList<String> activeTags = new ArrayList<>();
for (Map.Entry<String, ToggleButton> entry : mTagToggleButtonMap.entrySet()) {
if (entry.getValue().isChecked()) {
activeTags.add(entry.getKey());
}
}

ViewGroup parent = (ViewGroup) formatBar.getParent();
parent.removeView(formatBar);

formatBar = getActivity().getLayoutInflater().inflate(R.layout.format_bar, parent, false);
formatBar.setId(R.id.format_bar);
parent.addView(formatBar);

setupFormatBarButtonMap(formatBar);

// Restore the active format bar buttons
for (String tag : activeTags) {
mTagToggleButtonMap.get(tag).setChecked(true);
}

if (mSourceView.getVisibility() == View.VISIBLE) {
ToggleButton htmlButton = (ToggleButton) formatBar.findViewById(R.id.format_bar_button_html);
htmlButton.setChecked(true);
}
}

// Reload HTML mode margins
View sourceViewTitle = getView().findViewById(R.id.sourceview_title);
View sourceViewContent = getView().findViewById(R.id.sourceview_content);

if (sourceViewTitle != null && sourceViewContent != null) {
int sideMargin = (int) getActivity().getResources().getDimension(R.dimen.sourceview_side_margin);

ViewGroup.MarginLayoutParams titleParams =
(ViewGroup.MarginLayoutParams) sourceViewTitle.getLayoutParams();
ViewGroup.MarginLayoutParams contentParams =
(ViewGroup.MarginLayoutParams) sourceViewContent.getLayoutParams();

titleParams.setMargins(sideMargin, titleParams.topMargin, sideMargin, titleParams.bottomMargin);
contentParams.setMargins(sideMargin, contentParams.topMargin, sideMargin, contentParams.bottomMargin);
}
}

// Toggle action bar auto-hiding for the new orientation
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
&& !getResources().getBoolean(R.bool.is_large_tablet_landscape)) {
Expand All @@ -210,6 +237,42 @@ public void onConfigurationChanged(Configuration newConfig) {
}
}

private void setupFormatBarButtonMap(View view) {
ToggleButton boldButton = (ToggleButton) view.findViewById(R.id.format_bar_button_bold);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_bold), boldButton);

ToggleButton italicButton = (ToggleButton) view.findViewById(R.id.format_bar_button_italic);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_italic), italicButton);

ToggleButton quoteButton = (ToggleButton) view.findViewById(R.id.format_bar_button_quote);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_blockquote), quoteButton);

ToggleButton ulButton = (ToggleButton) view.findViewById(R.id.format_bar_button_ul);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_unorderedList), ulButton);

ToggleButton olButton = (ToggleButton) view.findViewById(R.id.format_bar_button_ol);
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_orderedList), olButton);

// Tablet-only
ToggleButton strikethroughButton = (ToggleButton) view.findViewById(R.id.format_bar_button_strikethrough);
if (strikethroughButton != null) {
mTagToggleButtonMap.put(getString(R.string.format_bar_tag_strikethrough), strikethroughButton);
}

ToggleButton mediaButton = (ToggleButton) view.findViewById(R.id.format_bar_button_media);
mTagToggleButtonMap.put(TAG_FORMAT_BAR_BUTTON_MEDIA, mediaButton);

ToggleButton linkButton = (ToggleButton) view.findViewById(R.id.format_bar_button_link);
mTagToggleButtonMap.put(TAG_FORMAT_BAR_BUTTON_LINK, linkButton);

ToggleButton htmlButton = (ToggleButton) view.findViewById(R.id.format_bar_button_html);
htmlButton.setOnClickListener(this);

for (ToggleButton button : mTagToggleButtonMap.values()) {
button.setOnClickListener(this);
}
}

protected void initJsEditor() {
if(!isAdded()) {
return;
Expand Down Expand Up @@ -261,8 +324,42 @@ public void onClick(View v) {
// TODO: Handle inserting media
((ToggleButton) v).setChecked(false);
} else if (id == R.id.format_bar_button_link) {
// TODO: Handle inserting a link
if (!((ToggleButton) v).isChecked()) {
// The link button was checked when it was pressed; remove the current link
mWebView.execJavaScriptFromString("ZSSEditor.unlink();");
return;
}

((ToggleButton) v).setChecked(false);

LinkDialogFragment linkDialogFragment = new LinkDialogFragment();
linkDialogFragment.setTargetFragment(this, LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_ADD);

Bundle dialogBundle = new Bundle();

// Pass selected text to dialog
if (mSourceView.getVisibility() == View.VISIBLE) {
// HTML mode
mSelectionStart = mSourceViewContent.getSelectionStart();
mSelectionEnd = mSourceViewContent.getSelectionEnd();

String selectedText = mSourceViewContent.getText().toString().substring(mSelectionStart, mSelectionEnd);
dialogBundle.putString("linkText", selectedText);
} else {
// Visual mode
mGetSelectedTextCountDownLatch = new CountDownLatch(1);
mWebView.execJavaScriptFromString("ZSSEditor.execFunctionForResult('getSelectedText');");
try {
if (mGetSelectedTextCountDownLatch.await(1, TimeUnit.SECONDS)) {
dialogBundle.putString("linkText", mJavaScriptResult);
}
} catch (InterruptedException e) {
AppLog.d(T.EDITOR, "Failed to obtain selected text from JS editor.");
}
}

linkDialogFragment.setArguments(dialogBundle);
linkDialogFragment.show(getFragmentManager(), "LinkDialogFragment");
} else {
if (v instanceof ToggleButton) {
onFormattingButtonClicked((ToggleButton) v);
Expand All @@ -288,6 +385,61 @@ public void onImeBack() {
showActionBarIfNeeded();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if ((requestCode == LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_ADD ||
requestCode == LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_UPDATE)) {

if (resultCode == LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_DELETE) {
mWebView.execJavaScriptFromString("ZSSEditor.unlink();");
return;
}

if (data == null) {
return;
}

Bundle extras = data.getExtras();
if (extras == null) {
return;
}

String linkUrl = extras.getString("linkURL");
String linkText = extras.getString("linkText");

if (linkText == null || linkText.equals("")) {
linkText = linkUrl;
}

if (mSourceView.getVisibility() == View.VISIBLE) {
Editable content = mSourceViewContent.getText();
if (content == null) {
return;
}

if (mSelectionStart < mSelectionEnd) {
content.delete(mSelectionStart, mSelectionEnd);
}

String urlHtml = "<a href=\"" + linkUrl + "\">" + linkText + "</a>";

content.insert(mSelectionStart, urlHtml);
mSourceViewContent.setSelection(mSelectionStart + urlHtml.length());
} else {
String jsMethod;
if (requestCode == LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_ADD) {
jsMethod = "ZSSEditor.insertLink";
} else {
jsMethod = "ZSSEditor.updateLink";
}
mWebView.execJavaScriptFromString(jsMethod + "('" + Utils.escapeHtml(linkUrl) + "', '" +
Utils.escapeHtml(linkText) + "');");
}
}
}

@SuppressLint("NewApi")
private void enableWebDebugging(boolean enable) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Expand Down Expand Up @@ -467,20 +619,47 @@ public void run() {
});
}

public void onLinkTapped(String url, String title) {
LinkDialogFragment linkDialogFragment = new LinkDialogFragment();
linkDialogFragment.setTargetFragment(this, LinkDialogFragment.LINK_DIALOG_REQUEST_CODE_UPDATE);

Bundle dialogBundle = new Bundle();

dialogBundle.putString("linkURL", url);
dialogBundle.putString("linkText", title);

linkDialogFragment.setArguments(dialogBundle);
linkDialogFragment.show(getFragmentManager(), "LinkDialogFragment");
}

public void onGetHtmlResponse(Map<String, String> inputArgs) {
String fieldId = inputArgs.get("id");
String fieldContents = inputArgs.get("contents");
if (!fieldId.isEmpty()) {
switch (fieldId) {
case "zss_field_title":
mTitle = fieldContents;
mGetTitleCountDownLatch.countDown();
break;
case "zss_field_content":
mContentHtml = fieldContents;
mGetContentCountDownLatch.countDown();
break;
}
String functionId = inputArgs.get("function");

if (functionId.isEmpty()) {
return;
}

switch (functionId) {
case "getHTMLForCallback":
String fieldId = inputArgs.get("id");
String fieldContents = inputArgs.get("contents");
if (!fieldId.isEmpty()) {
switch (fieldId) {
case "zss_field_title":
mTitle = fieldContents;
mGetTitleCountDownLatch.countDown();
break;
case "zss_field_content":
mContentHtml = fieldContents;
mGetContentCountDownLatch.countDown();
break;
}
}
break;
case "getSelectedText":
mJavaScriptResult = inputArgs.get("result");
mGetSelectedTextCountDownLatch.countDown();
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ private void configureWebView() {
webSettings.setDefaultTextEncodingName("utf-8");

this.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return true;
}

@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
AppLog.e(AppLog.T.EDITOR, description);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.Spannable;
import android.text.style.CharacterStyle;
Expand Down Expand Up @@ -77,6 +78,12 @@ public static void styleHtmlForDisplay(@NonNull Spannable content) {
* @param end the index in {@code content} to style until
*/
public static void styleHtmlForDisplay(@NonNull Spannable content, int start, int end) {
if (Build.VERSION.RELEASE.equals("4.1") || Build.VERSION.RELEASE.equals("4.1.1")) {
// Avoids crashing bug in Android 4.1 and 4.1.1 triggered when spanned text is line-wrapped
// AOSP issue: https://code.google.com/p/android/issues/detail?id=35466
return;
}

applySpansByRegex(content, start, end, REGEX_HTML_TAGS);
applySpansByRegex(content, start, end, REGEX_HTML_ATTRIBUTES);
applySpansByRegex(content, start, end, REGEX_HTML_COMMENTS);
Expand Down
Loading

0 comments on commit 33111c4

Please sign in to comment.