Skip to content
Snippets Groups Projects
Commit a25748e1 authored by maksymsproductengine's avatar maksymsproductengine
Browse files

MAINT-4119 FIXED Uniquely decorate links on Second Life or Linden Lab domains

parent d95feec8
No related branches found
No related tags found
No related merge requests found
......@@ -44,8 +44,6 @@
#include "llwindow.h"
#include <boost/bind.hpp>
#include "uriparser/Uri.h"
const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
const S32 CURSOR_THICKNESS = 2;
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click.
......@@ -2021,60 +2019,7 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML");
S32 LLTextBase::normalizeUri(std::string& uri_string)
{
UriParserStateA state;
UriUriA uri;
state.uri = &uri;
S32 res = uriParseUriA(&state, uri_string.c_str());
if (!res)
{
if (uri.scheme.afterLast - uri.scheme.first > 0)
{
res = uriNormalizeSyntaxExA(&uri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST);
if (!res)
{
S32 chars_required;
res = uriToStringCharsRequiredA(&uri, &chars_required);
if (!res)
{
chars_required++;
std::vector<char> label_buf(chars_required);
res = uriToStringA(&label_buf[0], &uri, chars_required, NULL);
if (!res)
{
uri_string = &label_buf[0];
}
}
}
}
else if (uri_string.find_first_of('.') != std::string::npos)
{
static bool recursive_call = false;
// allow only single level recursive call
if (!recursive_call)
{
recursive_call = true;
// force uri to be with scheme and try to normalize
std::string uri_with_scheme = "http://";
uri_with_scheme += uri_string;
normalizeUri(uri_with_scheme);
uri_string = uri_with_scheme.substr(7);
recursive_call = false;
}
}
}
uriFreeUriMembersA(&uri);
return res;
}
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
......@@ -2113,8 +2058,11 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
appendAndHighlightText(subtext, part, style_params);
}
// add icon before url if need
LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted());
std::string label = match.getLabel();
normalizeUri(label);
LLTextUtil::normalizeUri(label);
// output the styled Url
appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly());
......@@ -2130,8 +2078,6 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
}
}
LLTextUtil::processUrlMatch(&match,this,isContentTrusted());
// move on to the rest of the text after the Url
if (end < (S32)text.length())
{
......
......@@ -30,6 +30,8 @@
#include "lltextbox.h"
#include "llurlmatch.h"
#include "uriparser/Uri.h"
boost::function<bool(LLUrlMatch*,LLTextBase*)> LLTextUtil::TextHelpers::iconCallbackCreationFunction = 0;
void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& hl)
......@@ -104,4 +106,93 @@ bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool i
return false;
}
static void textRangeToString(UriTextRangeA& textRange, std::string& str)
{
S32 len = textRange.afterLast - textRange.first;
if (len)
{
str = textRange.first;
str = str.substr(0, len);
}
}
S32 LLTextUtil::normalizeUri(std::string& uri_string, Uri * urip/* = NULL*/)
{
UriParserStateA state;
UriUriA uri;
state.uri = &uri;
S32 res = uriParseUriA(&state, uri_string.c_str());
if (!res)
{
S32 len = uri.scheme.afterLast - uri.scheme.first;
if (len > 0)
{
res = uriNormalizeSyntaxExA(&uri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST);
if (!res)
{
S32 chars_required;
res = uriToStringCharsRequiredA(&uri, &chars_required);
if (!res)
{
chars_required++;
std::vector<char> label_buf(chars_required);
res = uriToStringA(&label_buf[0], &uri, chars_required, NULL);
if (!res)
{
uri_string = &label_buf[0];
}
}
}
// fill urip if requested
if (urip)
{
textRangeToString(uri.scheme, urip->scheme);
textRangeToString(uri.hostText, urip->host);
textRangeToString(uri.portText, urip->port);
textRangeToString(uri.query, urip->query);
textRangeToString(uri.fragment, urip->fragment);
UriPathSegmentA * pathHead = uri.pathHead;
while (pathHead)
{
std::string partOfPath;
textRangeToString(pathHead->text, partOfPath);
urip->path += '/';
urip->path += partOfPath;
pathHead = pathHead->next;
}
}
}
else if (uri_string.find_first_of('.') != std::string::npos)
{
static bool recursive_call = false;
// allow only single level recursive call
if (!recursive_call)
{
recursive_call = true;
// force uri to be with scheme and try to normalize
std::string uri_with_scheme = "http://";
uri_with_scheme += uri_string;
normalizeUri(uri_with_scheme, urip);
uri_string = uri_with_scheme.substr(7);
recursive_call = false;
}
}
}
uriFreeUriMembersA(&uri);
return res;
}
// EOF
......@@ -64,8 +64,35 @@ namespace LLTextUtil
*/
const std::string& formatPhoneNumber(const std::string& phone_str);
/**
* Adds icon before url if need.
*
* @param[in] match an object with results of matching
* @param[in] text_base pointer to UI text object
* @param[in] is_content_trusted true if context is trusted
* @return reference to string with formatted phone number
*/
bool processUrlMatch(LLUrlMatch* match, LLTextBase* text_base, bool is_content_trusted);
typedef struct
{
std::string scheme;
std::string host;
std::string port;
std::string path;
std::string query;
std::string fragment;
} Uri;
/**
* Translates uri's host name and scheme to lowercase
*
* @param[in, out] uri_string string with original uri
* @param[out] uri receives parts of uri
* @return 0 on success, error code otherwise
*/
S32 normalizeUri(std::string& uri_string, Uri * uri = NULL);
class TextHelpers
{
......
......@@ -35,6 +35,7 @@
#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lltrans.h"
#include "lltextutil.h"
#include "lluicolortable.h"
#include "message.h"
......@@ -341,6 +342,35 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
return url.substr(pos, url.size() - pos);
}
//
// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link
//
LLUrlEntrySeconlifeURL::LLUrlEntrySeconlifeURL()
{
mPattern = boost::regex("\\b(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com\\S*",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
mMenuName = "menu_url_http.xml";
}
std::string LLUrlEntrySeconlifeURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
std::string local_url(url);
LLTextUtil::Uri uri;
LLTextUtil::normalizeUri(local_url, &uri);
return uri.host;
}
std::string LLUrlEntrySeconlifeURL::getTooltip(const std::string &url) const
{
std::string local_url(url);
LLTextUtil::normalizeUri(local_url);
return local_url;
}
//
// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
......
......@@ -96,6 +96,8 @@ class LLUrlEntryBase
/// Should this link text be underlined only when mouse is hovered over it?
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
virtual bool isTrusted() const { return false; }
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
bool isLinkDisabled() const;
......@@ -167,6 +169,21 @@ class LLUrlEntrySLURL : public LLUrlEntryBase
/*virtual*/ std::string getLocation(const std::string &url) const;
};
///
/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls
///
class LLUrlEntrySeconlifeURL : public LLUrlEntryBase
{
public:
LLUrlEntrySeconlifeURL();
virtual bool isTrusted() const { return true; }
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
virtual std::string getTooltip(const std::string &url) const;
private:
std::string mLabel;
};
///
/// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
......
......@@ -37,7 +37,8 @@ LLUrlMatch::LLUrlMatch() :
mIcon(""),
mMenuName(""),
mLocation(""),
mUnderlineOnHoverOnly(false)
mUnderlineOnHoverOnly(false),
mTrusted(false)
{
}
......@@ -45,7 +46,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
const std::string &label, const std::string &tooltip,
const std::string &icon, const LLStyle::Params& style,
const std::string &menu, const std::string &location,
const LLUUID& id, bool underline_on_hover_only)
const LLUUID& id, bool underline_on_hover_only, bool trusted)
{
mStart = start;
mEnd = end;
......@@ -59,4 +60,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mLocation = location;
mID = id;
mUnderlineOnHoverOnly = underline_on_hover_only;
mTrusted = trusted;
}
......@@ -80,12 +80,15 @@ class LLUrlMatch
/// Should this link text be underlined only when mouse is hovered over it?
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
/// Return true if Url is trusted.
bool isTrusted() const { return mTrusted; }
/// Change the contents of this match object (used by LLUrlRegistry)
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
const std::string &tooltip, const std::string &icon,
const LLStyle::Params& style, const std::string &menu,
const std::string &location, const LLUUID& id,
bool underline_on_hover_only = false );
bool underline_on_hover_only = false, bool trusted = false );
const LLUUID& getID() const { return mID; }
private:
......@@ -100,6 +103,7 @@ class LLUrlMatch
LLUUID mID;
LLStyle::Params mStyle;
bool mUnderlineOnHoverOnly;
bool mTrusted;
};
#endif
......@@ -44,6 +44,10 @@ LLUrlRegistry::LLUrlRegistry()
mUrlEntryIcon = new LLUrlEntryIcon();
registerUrl(mUrlEntryIcon);
registerUrl(new LLUrlEntrySLURL());
// decorated links for host names like: secondlife.com and lindenlab.com
registerUrl(new LLUrlEntrySeconlifeURL());
registerUrl(new LLUrlEntryHTTP());
mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel();
registerUrl(mUrlEntryHTTPLabel);
......@@ -212,7 +216,8 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
match_entry->getMenuName(),
match_entry->getLocation(url),
match_entry->getID(url),
match_entry->underlineOnHoverOnly(url));
match_entry->underlineOnHoverOnly(url),
match_entry->isTrusted());
return true;
}
......
indra/newview/skins/default/textures/icons/hand.png

957 B

......@@ -229,6 +229,8 @@ with the same filename but different name
<texture name="Generic_Person" file_name="icons/Generic_Person.png" preload="false" />
<texture name="Generic_Person_Large" file_name="icons/Generic_Person_Large.png" preload="false" />
<texture name="Hand" file_name="icons/hand.png" preload="false" />
<texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" />
<texture name="Hierarchy_View_Disabled" file_name="icons/Hierarchy_View_Disabled.png" preload="false" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment