Skip to content
This repository was archived by the owner on Mar 7, 2025. It is now read-only.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.wordpress.mobile.ReactNativeAztec;

import android.text.TextUtils;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;

/**
* Event emitted by Aztec native view when attributes detected.
*/

public class ReactAztecFormattingAttributesChange extends Event<ReactAztecFormattingChangeEvent> {

private static final String EVENT_NAME = "topFormatAttributeChanges";

private static final String KEY_EVENT_DATA_ATTRIBUTES = "attributes";

private static final String KEY_ATTRIBUTES_DATA_LINK = "link";

private static final String KEY_LINK_DATA_IS_ACTIVE = "isActive";
private static final String KEY_LINK_DATA_IS_URL = "url";

private String mUrl;

public ReactAztecFormattingAttributesChange(int viewId) {
super(viewId);
}

public void setLinkData(String url) {
mUrl = url;
}

@Override
public String getEventName() {
return EVENT_NAME;
}

@Override
public boolean canCoalesce() {
return false;
}

@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}

private WritableMap serializeEventData() {

WritableMap attributesData = Arguments.createMap();
attributesData.putMap(KEY_ATTRIBUTES_DATA_LINK, getLinkData());

WritableMap eventData = Arguments.createMap();
eventData.putMap(KEY_EVENT_DATA_ATTRIBUTES, attributesData);

return eventData;
}

private WritableMap getLinkData() {
WritableMap linkData = Arguments.createMap();
if (!TextUtils.isEmpty(mUrl)) {
linkData.putBoolean(KEY_LINK_DATA_IS_ACTIVE, true);
linkData.putString(KEY_LINK_DATA_IS_URL, mUrl);
}
else {
linkData.putBoolean(KEY_LINK_DATA_IS_ACTIVE, false);
}
return linkData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public class ReactAztecManager extends SimpleViewManager<ReactAztecText> {
private static final int FOCUS_TEXT_INPUT = 1;
private static final int BLUR_TEXT_INPUT = 2;
private static final int COMMAND_NOTIFY_APPLY_FORMAT = 100;
private static final int COMMAND_NOTIFY_SET_LINK = 101;
private static final int COMMAND_NOTIFY_REMOVE_LINK = 102;


// we define the same codes in ReactAztecText as they have for ReactNative's TextInput, so
// it's easier to handle focus between Aztec and TextInput instances on the same screen.
Expand Down Expand Up @@ -104,6 +107,11 @@ public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onActiveFormatsChange")))
.put(
"topFormatAttributeChanges",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onActiveFormatAttributesChange")))
.put(
"topEndEditing",
MapBuilder.of(
Expand Down Expand Up @@ -259,6 +267,11 @@ public void setOnActiveFormatsChange(final ReactAztecText view, boolean onActive
view.shouldHandleActiveFormatsChange = onActiveFormatsChange;
}

@ReactProp(name = "onActiveFormatAttributesChange", defaultBoolean = false)
public void setOnActiveFormatAttributesChange(final ReactAztecText view, boolean onActiveFormatAttributesChange) {
view.shouldHandleActiveFormatAttributesChange = onActiveFormatAttributesChange;
}

@ReactProp(name = "onSelectionChange", defaultBoolean = false)
public void setOnSelectionChange(final ReactAztecText view, boolean onSelectionChange) {
view.shouldHandleOnSelectionChange = onSelectionChange;
Expand Down Expand Up @@ -289,6 +302,8 @@ public Map<String, Integer> getCommandsMap() {
.put("applyFormat", COMMAND_NOTIFY_APPLY_FORMAT)
.put("focusTextInput", mFocusTextInputCommandCode)
.put("blurTextInput", mBlurTextInputCommandCode)
.put("setLink", COMMAND_NOTIFY_SET_LINK)
.put("removeLink", COMMAND_NOTIFY_REMOVE_LINK)
.build();
}

Expand All @@ -307,6 +322,16 @@ public void receiveCommand(final ReactAztecText parent, int commandType, @Nullab
parent.clearFocusFromJS();
return;
}
else if (commandType == COMMAND_NOTIFY_SET_LINK) {
final String url = args.getString(0);
final String title = args.getString(1);
parent.link(url, title);
return;
}
else if (commandType == COMMAND_NOTIFY_REMOVE_LINK) {
parent.removeLink();
return;
}
super.receiveCommand(parent, commandType, args);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.inputmethod.InputMethodManager;
Expand Down Expand Up @@ -51,6 +52,7 @@ public class ReactAztecText extends AztecText {
boolean shouldHandleOnBackspace = false;
boolean shouldHandleOnSelectionChange = false;
boolean shouldHandleActiveFormatsChange = false;
boolean shouldHandleActiveFormatAttributesChange = false;

public ReactAztecText(ThemedReactContext reactContext) {
super(reactContext);
Expand All @@ -77,6 +79,7 @@ public boolean onBackspaceKey() {
public void onSelectionChanged(int selStart, int selEnd) {
ReactAztecText.this.updateToolbarButtons(selStart, selEnd);
ReactAztecText.this.propagateSelectionChanges(selStart, selEnd);
ReactAztecText.this.propagateAttributesChange();
}
});
this.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
Expand Down Expand Up @@ -154,6 +157,8 @@ protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {

public void setContentSizeWatcher(ContentSizeWatcher contentSizeWatcher) {
mContentSizeWatcher = contentSizeWatcher;


}

private void onContentSizeChange() {
Expand Down Expand Up @@ -194,6 +199,9 @@ private void updateToolbarButtons(ArrayList<ITextFormat> appliedStyles) {
if (currentStyle == AztecTextFormat.FORMAT_STRIKETHROUGH) {
formattingOptions.add("strikethrough");
}
if (currentStyle == AztecTextFormat.FORMAT_LINK) {
formattingOptions.add("link");
}
}

// Check if the same formatting event was already sent
Expand All @@ -205,6 +213,7 @@ private void updateToolbarButtons(ArrayList<ITextFormat> appliedStyles) {
// no need to send any event now
return;
}

lastSentFormattingOptionsEventString = newOptionsAsString;

if (shouldHandleActiveFormatsChange) {
Expand All @@ -231,6 +240,17 @@ private void propagateSelectionChanges(int selStart, int selEnd) {
);
}

private void propagateAttributesChange() {
if (shouldHandleActiveFormatAttributesChange) {
ReactContext reactContext = (ReactContext) getContext();
EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
ReactAztecFormattingAttributesChange reactAztecFormattingAttributesChange =
new ReactAztecFormattingAttributesChange(getId());
reactAztecFormattingAttributesChange.setLinkData(linkFormatter.getSelectedUrlWithAnchor().getFirst());
eventDispatcher.dispatchEvent(reactAztecFormattingAttributesChange);
}
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
onContentSizeChange();
Expand Down Expand Up @@ -331,6 +351,9 @@ public void applyFormat(String format) {
case ("strikethrough"):
newFormats.add(AztecTextFormat.FORMAT_STRIKETHROUGH);
break;
case ("link") :
newFormats.add(AztecTextFormat.FORMAT_LINK);
break;
}

if (newFormats.size() == 0) {
Expand Down Expand Up @@ -378,6 +401,14 @@ private ArrayList<ITextFormat> getNewStylesList(ArrayList<ITextFormat> newFormat
return textFormats;
}

public void link (String url, String title) {
if (TextUtils.isEmpty(title)) {
title = getSelectedText();
}
link(url, title, false);
applyFormat("link");
}

/**
* This class will redirect *TextChanged calls to the listeners only in the case where the text
* is changed by the user, and not explicitly set by JS.
Expand Down