/*
* Copyright (C) 2015-2017 Emanuel Moecklin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.onegravity.rteditor;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.onegravity.rteditor.utils.Helper;
import com.onegravity.rteditor.utils.validator.EmailValidator;
import com.onegravity.rteditor.utils.validator.UrlValidator;
import org.greenrobot.eventbus.EventBus;
import java.util.Locale;
/**
* A DialogFragment to add, modify or remove links from Spanned text.
*/
public class LinkFragment extends DialogFragment {
private static final String LINK_ADDRESS = "link_address";
private static final String LINK_TEXT = "link_text";
/**
* The Link class describes a link (link text and an URL).
*/
static class Link {
final private String mLinkText;
final private String mUrl;
private Link(String linkText, String url) {
mLinkText = linkText;
mUrl = url;
}
public String getLinkText() {
return mLinkText;
}
public String getUrl() {
return mUrl;
}
public boolean isValid() {
return mUrl != null && mUrl.length() > 0 && mLinkText != null && mLinkText.length() > 0;
}
}
/**
* This event is broadcast via EventBus when the dialog closes.
* It's received by the RTManager to update the active editor.
*/
static class LinkEvent {
private final String mFragmentTag;
private final Link mLink;
private final boolean mWasCancelled;
public LinkEvent(Fragment fragment, Link link, boolean wasCancelled) {
mFragmentTag = fragment.getTag();
mLink = link;
mWasCancelled = wasCancelled;
}
public String getFragmentTag() {
return mFragmentTag;
}
public Link getLink() {
return mLink;
}
public boolean wasCancelled() {
return mWasCancelled;
}
}
private static final UrlValidator sUrlValidator = new UrlValidator(UrlValidator.ALLOW_2_SLASHES + UrlValidator.ALLOW_ALL_SCHEMES);
private static final EmailValidator sEmailValidator = EmailValidator.getInstance(false);
public static LinkFragment newInstance(String linkText, String url) {
LinkFragment fragment = new LinkFragment();
Bundle args = new Bundle();
args.putString(LINK_TEXT, linkText);
args.putString(LINK_ADDRESS, url);
fragment.setArguments(args);
return fragment;
}
public LinkFragment() {
}
@SuppressLint("InflateParams")
@Override
public final Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
LayoutInflater li = LayoutInflater.from(context);
View view = li.inflate(R.layout.rte_link, null);
Bundle args = getArguments();
// link address
String tmp = "http://";
final String address = args.getString(LINK_ADDRESS);
if (address != null && ! address.isEmpty()) {
try {
Uri uri = Uri.parse( Helper.decodeQuery(address) );
// if we have an email address remove the mailto: part for editing purposes
tmp = startsWithMailto(address) ? uri.getSchemeSpecificPart() : uri.toString();
} catch (Exception ignore) {}
}
final String url = tmp;
final TextView addressView = ((TextView) view.findViewById(R.id.linkURL));
if (url != null) {
addressView.setText(url);
}
// link text
String linkText = args.getString(LINK_TEXT);
final TextView textView = ((TextView) view.findViewById(R.id.linkText));
if (linkText != null) {
textView.setText(linkText);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(R.string.rte_create_a_link)
.setView(view)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// OK button
validate(dialog, addressView, textView);
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Cancel button
EventBus.getDefault().post(new LinkEvent(LinkFragment.this, new Link(null, url), true));
}
});
if (address != null) {
builder.setNeutralButton(R.string.rte_remove_action, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Remove button
EventBus.getDefault().post(new LinkEvent(LinkFragment.this, null, false));
}
});
}
return builder.create();
}
private void validate(DialogInterface dialog, TextView addressView, TextView textView) {
// retrieve link address and do some cleanup
final String address = addressView.getText().toString().trim();
boolean isEmail = sEmailValidator.isValid(address);
boolean isUrl = sUrlValidator.isValid(address);
if (requiredFieldValid(addressView) && (isUrl || isEmail)) {
// valid url or email address
// encode address
String newAddress = Helper.encodeUrl(address);
// add mailto: for email addresses
if (isEmail && !startsWithMailto(newAddress)) {
newAddress = "mailto:" + newAddress;
}
// use the original address text as link text if the user didn't enter anything
String linkText = textView.getText().toString();
if (linkText.length() == 0) {
linkText = address;
}
EventBus.getDefault().post(new LinkEvent(LinkFragment.this, new Link(linkText, newAddress), false));
try { dialog.dismiss(); } catch (Exception ignore) {}
} else {
// invalid address (neither a url nor an email address
String errorMessage = getString(R.string.rte_invalid_link, address);
addressView.setError(errorMessage);
}
}
private boolean startsWithMailto(String address) {
return address != null && address.toLowerCase(Locale.getDefault()).startsWith("mailto:");
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
EventBus.getDefault().post(new LinkEvent(LinkFragment.this, null, true));
}
private boolean requiredFieldValid(TextView view) {
return view.getText() != null && view.getText().length() > 0;
}
}