/** * In HTML mode, applies formatting to selected text, or inserts formatting tag at current cursor * position * * @param toggleButton format bar button which was clicked * @param tag identifier tag */ private void applyFormattingHtmlMode(ToggleButton toggleButton, String tag) { if (mSourceViewContent == null) { return; } // Replace style tags with their proper HTML tags String htmlTag; if (tag.equals(getString(R.string.format_bar_tag_bold))) { htmlTag = "b"; } else if (tag.equals(getString(R.string.format_bar_tag_italic))) { htmlTag = "i"; } else if (tag.equals(getString(R.string.format_bar_tag_strikethrough))) { htmlTag = "del"; } else if (tag.equals(getString(R.string.format_bar_tag_unorderedList))) { htmlTag = "ul"; } else if (tag.equals(getString(R.string.format_bar_tag_orderedList))) { htmlTag = "ol"; } else { htmlTag = tag; } int selectionStart = mSourceViewContent.getSelectionStart(); int selectionEnd = mSourceViewContent.getSelectionEnd(); if (selectionStart > selectionEnd) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } boolean textIsSelected = selectionEnd > selectionStart; String startTag = "<" + htmlTag + ">"; String endTag = "</" + htmlTag + ">"; // Add li tags together with ul and ol tags if (htmlTag.equals("ul") || htmlTag.equals("ol")) { startTag = startTag + "\n\t<li>"; endTag = "</li>\n" + endTag; } Editable content = mSourceViewContent.getText(); if (textIsSelected) { // Surround selected text with opening and closing tags content.insert(selectionStart, startTag); content.insert(selectionEnd + startTag.length(), endTag); toggleButton.setChecked(false); mSourceViewContent.setSelection(selectionEnd + startTag.length() + endTag.length()); } else if (toggleButton.isChecked()) { // Insert opening tag content.insert(selectionStart, startTag); mSourceViewContent.setSelection(selectionEnd + startTag.length()); } else { // Insert closing tag content.insert(selectionEnd, endTag); mSourceViewContent.setSelection(selectionEnd + endTag.length()); } }
/** * Returns the contents of the content field from the JavaScript editor. Should be called from a * background thread where possible. */ @Override public CharSequence getContent() { if (!isAdded()) { return ""; } if (mSourceView != null && mSourceView.getVisibility() == View.VISIBLE) { mContentHtml = mSourceViewContent.getText().toString(); return StringUtils.notNullStr(mContentHtml); } if (Looper.myLooper() == Looper.getMainLooper()) { AppLog.d(T.EDITOR, "getContent() called from UI thread"); } mGetContentCountDownLatch = new CountDownLatch(1); // All WebView methods must be called from the UI thread getActivity() .runOnUiThread( new Runnable() { @Override public void run() { mWebView.execJavaScriptFromString( "ZSSEditor.getField('zss_field_content').getHTMLForCallback();"); } }); try { mGetContentCountDownLatch.await(1, TimeUnit.SECONDS); } catch (InterruptedException e) { AppLog.e(T.EDITOR, e); Thread.currentThread().interrupt(); } return StringUtils.notNullStr(mContentHtml); }
@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) + "');"); } } else if (requestCode == ImageSettingsDialogFragment.IMAGE_SETTINGS_DIALOG_REQUEST_CODE) { if (data == null) { return; } Bundle extras = data.getExtras(); if (extras == null) { return; } final String imageMeta = extras.getString("imageMeta"); final int imageRemoteId = extras.getInt("imageRemoteId"); final boolean isFeaturedImage = extras.getBoolean("isFeatured"); mWebView.post( new Runnable() { @Override public void run() { mWebView.execJavaScriptFromString( "ZSSEditor.updateCurrentImageMeta('" + imageMeta + "');"); } }); if (imageRemoteId != 0) { if (isFeaturedImage) { mFeaturedImageId = imageRemoteId; mEditorFragmentListener.onFeaturedImageChanged(mFeaturedImageId); } else { // If this image was unset as featured, clear the featured image id if (mFeaturedImageId == imageRemoteId) { mFeaturedImageId = 0; mEditorFragmentListener.onFeaturedImageChanged(mFeaturedImageId); } } } } }
@Override public void onClick(View v) { int id = v.getId(); if (id == R.id.format_bar_button_html) { // Don't switch to HTML mode if currently uploading media // if (!mUploadingMediaIds.isEmpty()) { // ((ToggleButton) v).setChecked(false); // // if (isAdded()) { // ToastUtils.showToast(getActivity(), // R.string.alert_html_toggle_uploading, ToastUtils.Duration.LONG); // } // return; // } clearFormatBarButtons(); updateFormatBarEnabledState(true); if (((ToggleButton) v).isChecked()) { mSourceViewTitle.setText(getTitle()); SpannableString spannableContent = new SpannableString(getContent()); HtmlStyleUtils.styleHtmlForDisplay(spannableContent); mSourceViewContent.setText(spannableContent); mWebView.setVisibility(View.GONE); mSourceView.setVisibility(View.VISIBLE); mSourceViewContent.requestFocus(); mSourceViewContent.setSelection(0); InputMethodManager imm = ((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)); imm.showSoftInput(mSourceViewContent, InputMethodManager.SHOW_IMPLICIT); } else { mWebView.setVisibility(View.VISIBLE); mSourceView.setVisibility(View.GONE); mTitle = mSourceViewTitle.getText().toString(); mContentHtml = mSourceViewContent.getText().toString(); updateVisualEditorFields(); mWebView.execJavaScriptFromString("ZSSEditor.getField('zss_field_content').focus();"); } } else if (id == R.id.format_bar_button_media) { ((ToggleButton) v).setChecked(false); if (mSourceView.getVisibility() == View.VISIBLE) { ToastUtils.showToast( getActivity(), R.string.alert_insert_image_html_mode, ToastUtils.Duration.LONG); } else { mEditorFragmentListener.onAddMediaClicked(); if (isAdded()) { getActivity().openContextMenu(mTagToggleButtonMap.get(TAG_FORMAT_BAR_BUTTON_MEDIA)); } } } else if (id == R.id.format_bar_button_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(AppLog.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); } } }
@Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_editor, container, false); Log.i("enter...", "new editor"); // Setup hiding the action bar when the soft keyboard is displayed for narrow viewports if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE && !getResources().getBoolean(R.bool.is_large_tablet_landscape)) { mHideActionBarOnSoftKeyboardUp = true; } mWaitingMediaFiles = new ConcurrentHashMap<>(); // mUploadingMediaIds = new HashSet<>(); mFailedMediaIds = new HashSet<>(); // -- WebView configuration mWebView = (EditorWebViewAbstract) view.findViewById(R.id.webview); mWebView.setOnTouchListener(this); mWebView.setOnImeBackListener(this); LeaWebViewClient webViewClient = new LeaWebViewClient(); webViewClient.setImageLoadListener(this); // mWebView.setWebViewClient(webViewClient); // Ensure that the content field is always filling the remaining screen space mWebView.addOnLayoutChangeListener( new View.OnLayoutChangeListener() { @Override public void onLayoutChange( View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { mWebView.post( new Runnable() { @Override public void run() { // mWebView.execJavaScriptFromString("ZSSEditor.init()"); mWebView.execJavaScriptFromString("ZSSEditor.refreshVisibleViewportSize();"); } }); } }); mEditorFragmentListener.onEditorFragmentInitialized(); initJsEditor(); if (savedInstanceState != null) { setTitle(savedInstanceState.getCharSequence(KEY_TITLE)); setContent(savedInstanceState.getCharSequence(KEY_CONTENT)); } // -- HTML mode configuration mSourceView = view.findViewById(R.id.sourceview); mSourceViewTitle = (SourceViewEditText) view.findViewById(R.id.sourceview_title); mSourceViewContent = (SourceViewEditText) view.findViewById(R.id.sourceview_content); // Toggle format bar on/off as user changes focus between title and content in HTML mode mSourceViewTitle.setOnFocusChangeListener( new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { updateFormatBarEnabledState(!hasFocus); } }); mSourceViewTitle.setOnTouchListener(this); mSourceViewContent.setOnTouchListener(this); mSourceViewTitle.setOnImeBackListener(this); mSourceViewContent.setOnImeBackListener(this); mSourceViewContent.addTextChangedListener(new HtmlStyleTextWatcher()); mSourceViewTitle.setHint(mTitlePlaceholder); mSourceViewContent.setHint("<p>" + mContentPlaceholder + "</p>"); // -- Format bar configuration setupFormatBarButtonMap(view); return view; }