зеркало из https://github.com/mozilla/gecko-dev.git
SRC and HREF attributes turned into clickable links in view source. p=cbartley r+sr=mrbkap a=beltzner b=17612
This commit is contained in:
Родитель
505c7e907d
Коммит
a20f5060d4
|
@ -75,6 +75,7 @@
|
|||
#include "nsIPrefBranch.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
|
@ -254,10 +255,10 @@ CViewSourceHTML::~CViewSourceHTML(){
|
|||
* The parser uses a code sandwich to wrap the parsing process. Before
|
||||
* the process begins, WillBuildModel() is called. Afterwards the parser
|
||||
* calls DidBuildModel().
|
||||
* @update rickg 03.20.2000
|
||||
* @param aParserContext
|
||||
* @param aSink
|
||||
* @return error code (almost always 0)
|
||||
* @update rickg 03.20.2000
|
||||
* @param aParserContext
|
||||
* @param aSink
|
||||
* @return error code (almost always 0)
|
||||
*/
|
||||
nsresult CViewSourceHTML::WillBuildModel(const CParserContext& aParserContext,
|
||||
nsITokenizer* aTokenizer,
|
||||
|
@ -332,9 +333,9 @@ nsresult CViewSourceHTML::WillBuildModel(const CParserContext& aParserContext,
|
|||
* The parser uses a code sandwich to wrap the parsing process. Before
|
||||
* the process begins, WillBuildModel() is called. Afterwards the parser
|
||||
* calls DidBuildModel().
|
||||
* @update gess5/18/98
|
||||
* @param aFilename is the name of the file being parsed.
|
||||
* @return error code (almost always 0)
|
||||
* @update gess5/18/98
|
||||
* @param aFilename is the name of the file being parsed.
|
||||
* @return error code (almost always 0)
|
||||
*/
|
||||
NS_IMETHODIMP CViewSourceHTML::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsITokenObserver* anObserver,nsIContentSink* aSink) {
|
||||
nsresult result=NS_OK;
|
||||
|
@ -541,7 +542,7 @@ void CViewSourceHTML::AddAttrToNode(nsCParserStartNode& aNode,
|
|||
|
||||
/**
|
||||
*
|
||||
* @update gess5/18/98
|
||||
* @update gess5/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -596,7 +597,7 @@ NS_IMETHODIMP CViewSourceHTML::DidBuildModel(nsresult anErrorCode,PRBool aNotify
|
|||
* It's recommended to use this method in accordance with
|
||||
* the parser's terminate() method.
|
||||
*
|
||||
* @update harishd 07/22/99
|
||||
* @update harishd 07/22/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -611,7 +612,7 @@ CViewSourceHTML::GetType() {
|
|||
|
||||
/**
|
||||
*
|
||||
* @update gess5/18/98
|
||||
* @update gess5/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -625,7 +626,7 @@ NS_IMETHODIMP CViewSourceHTML::WillResumeParse(nsIContentSink* aSink){
|
|||
|
||||
/**
|
||||
*
|
||||
* @update gess5/18/98
|
||||
* @update gess5/18/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -640,7 +641,7 @@ NS_IMETHODIMP CViewSourceHTML::WillInterruptParse(nsIContentSink* aSink){
|
|||
/**
|
||||
* Called by the parser to enable/disable dtd verification of the
|
||||
* internal context stack.
|
||||
* @update gess 7/23/98
|
||||
* @update gess 7/23/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -682,7 +683,9 @@ PRBool CViewSourceHTML::IsContainer(PRInt32 aTag) const{
|
|||
* @param
|
||||
* @return result status
|
||||
*/
|
||||
nsresult CViewSourceHTML::WriteAttributes(PRInt32 attrCount, PRBool aOwnerInError) {
|
||||
nsresult CViewSourceHTML::WriteAttributes(const nsAString& tagName,
|
||||
nsTokenAllocator* allocator,
|
||||
PRInt32 attrCount, PRBool aOwnerInError) {
|
||||
nsresult result=NS_OK;
|
||||
|
||||
if(attrCount){ //go collect the attributes...
|
||||
|
@ -706,7 +709,11 @@ nsresult CViewSourceHTML::WriteAttributes(PRInt32 attrCount, PRBool aOwnerInErro
|
|||
const nsSubstring& theValue = theAttrToken->GetValue();
|
||||
|
||||
if(!theValue.IsEmpty() || theAttrToken->mHasEqualWithoutValue){
|
||||
result = WriteTag(kAttributeValue,theValue,0,attributeInError);
|
||||
if (IsUrlAttribute(tagName, theKey, theValue)) {
|
||||
WriteHrefAttribute(allocator, theValue);
|
||||
} else {
|
||||
WriteTag(kAttributeValue,theValue,0,attributeInError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -816,7 +823,7 @@ nsresult CViewSourceHTML::WriteTag(PRInt32 aTagType,const nsSubstring & aText,PR
|
|||
}
|
||||
|
||||
if(attrCount){
|
||||
result=WriteAttributes(attrCount, aTagInError);
|
||||
result=WriteAttributes(aText, theAllocator, attrCount, aTagInError);
|
||||
}
|
||||
|
||||
// Tokens are set in error if their ending > is not there, so don't output
|
||||
|
@ -981,3 +988,209 @@ NS_IMETHODIMP CViewSourceHTML::HandleToken(CToken* aToken,nsIParser* aParser)
|
|||
return result;
|
||||
}
|
||||
|
||||
PRBool CViewSourceHTML::IsUrlAttribute(const nsAString& tagName,
|
||||
const nsAString& attrName,
|
||||
const nsAString& attrValue) {
|
||||
const nsSubstring &trimmedAttrName = TrimTokenValue(attrName);
|
||||
|
||||
PRBool isHref = trimmedAttrName.LowerCaseEqualsLiteral("href");
|
||||
PRBool isSrc = !isHref && trimmedAttrName.LowerCaseEqualsLiteral("src");
|
||||
|
||||
// If this is the HREF attribute of a BASE element, then update the base URI.
|
||||
// This doesn't feel like the ideal place for this, but the alternatives don't
|
||||
// seem all that nice either.
|
||||
if (isHref && tagName.LowerCaseEqualsLiteral("base")) {
|
||||
const nsSubstring& baseSpec = TrimTokenValue(attrValue);
|
||||
SetBaseURI(baseSpec);
|
||||
}
|
||||
|
||||
return isHref || isSrc;
|
||||
}
|
||||
|
||||
void CViewSourceHTML::WriteHrefAttribute(nsTokenAllocator* allocator,
|
||||
const nsAString& href) {
|
||||
// The "href" will typically contain not only the href proper, but the single
|
||||
// or double quotes and often some surrounding whitespace as well. Find the
|
||||
// location of the href proper inside the string.
|
||||
nsAString::const_iterator startProper, endProper;
|
||||
href.BeginReading(startProper);
|
||||
href.EndReading(endProper);
|
||||
TrimTokenValue(startProper, endProper);
|
||||
|
||||
// Break the href into three parts, the preceding text, the href proper, and
|
||||
// the succeeding text.
|
||||
nsAString::const_iterator start, end;
|
||||
href.BeginReading(start);
|
||||
href.EndReading(end);
|
||||
const nsAString &precedingText = Substring(start, startProper);
|
||||
const nsAString &hrefProper = Substring(startProper, endProper);
|
||||
const nsAString &succeedingText = Substring(endProper, end);
|
||||
|
||||
nsAutoString fullPrecedingText;
|
||||
fullPrecedingText.Assign(kEqual);
|
||||
fullPrecedingText.Append(precedingText);
|
||||
|
||||
// Regular URLs and view-source URLs work the same way for .js and .css files.
|
||||
// However, if the user follows a link in the view source window to a .html
|
||||
// file (i.e. the HREF in an A tag), then presumably they will expect to see
|
||||
// the *source* of that new page, not the rendered version. So for now we
|
||||
// just slap a "view-source:" at the beginning of each URL. There are two
|
||||
// big downsides to doing it this way -- we must make relative URLs into
|
||||
// absolute URLs before we can turn them into view-source URLs, and links
|
||||
// to images don't work right -- nobody wants to see the bytes constituting a
|
||||
// PNG rendered as text. A smarter view-source handler might be able to deal
|
||||
// with the latter problem.
|
||||
|
||||
// Construct a "view-source" URL for the HREF.
|
||||
nsAutoString viewSourceUrl;
|
||||
CreateViewSourceURL(hrefProper, viewSourceUrl);
|
||||
|
||||
// Construct the HTML that will represent the HREF.
|
||||
NS_NAMED_LITERAL_STRING(HREF, "href");
|
||||
if (fullPrecedingText.Length() > 0) {
|
||||
WriteTextInSpan(fullPrecedingText, allocator, EmptyString(), EmptyString());
|
||||
}
|
||||
WriteTextInAnchor(hrefProper, allocator, HREF, viewSourceUrl);
|
||||
if (succeedingText.Length() > 0) {
|
||||
WriteTextInSpan(succeedingText, allocator, EmptyString(), EmptyString());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult CViewSourceHTML::CreateViewSourceURL(const nsAString& linkUrl,
|
||||
nsString& viewSourceUrl) {
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsCOMPtr<nsIURI> hrefURI;
|
||||
nsresult rv;
|
||||
|
||||
// Default the view source URL to the empty string in case we fail. Links
|
||||
// with empty HREFs are essentially non-functional, at least as of Firefox
|
||||
// 3.03. This is preferrable behavior to links that look good but then 404.
|
||||
viewSourceUrl.Truncate();
|
||||
|
||||
// Get the character set.
|
||||
nsCString charset;
|
||||
PRInt32 source;
|
||||
mParser->GetDocumentCharset(charset, source);
|
||||
|
||||
// Get the BaseURI.
|
||||
rv = GetBaseURI(getter_AddRefs(baseURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Use the link URL and the base URI to build a URI for the link.
|
||||
rv = NS_NewURI(getter_AddRefs(hrefURI), linkUrl, charset.get(), baseURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the absolute URL from the link URI.
|
||||
nsCString absoluteLinkUrl;
|
||||
hrefURI->GetSpec(absoluteLinkUrl);
|
||||
|
||||
// Prepend "view-source:" onto the absolute URL and store it in the out param.
|
||||
viewSourceUrl.AssignLiteral("view-source:");
|
||||
viewSourceUrl.AppendWithConversion(absoluteLinkUrl);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void CViewSourceHTML::WriteTextInSpan(const nsAString& text,
|
||||
nsTokenAllocator* allocator,
|
||||
const nsAString& attrName,
|
||||
const nsAString& attrValue) {
|
||||
NS_NAMED_LITERAL_STRING(SPAN, "SPAN");
|
||||
WriteTextInElement(SPAN, eHTMLTag_span, text, allocator, attrName, attrValue);
|
||||
}
|
||||
|
||||
void CViewSourceHTML::WriteTextInAnchor(const nsAString& text,
|
||||
nsTokenAllocator* allocator,
|
||||
const nsAString& attrName,
|
||||
const nsAString& attrValue) {
|
||||
NS_NAMED_LITERAL_STRING(ANCHOR, "A");
|
||||
WriteTextInElement(ANCHOR, eHTMLTag_a, text, allocator, attrName, attrValue);
|
||||
}
|
||||
|
||||
void CViewSourceHTML::WriteTextInElement(const nsAString& tagName,
|
||||
eHTMLTags tagType, const nsAString& text,
|
||||
nsTokenAllocator* allocator,
|
||||
const nsAString& attrName,
|
||||
const nsAString& attrValue) {
|
||||
// Open the element, supplying the attribute, if any.
|
||||
CStartToken startToken(tagName, tagType);
|
||||
nsCParserStartNode startNode(&startToken, 0/*stack token*/);
|
||||
if (!attrName.IsEmpty()) {
|
||||
AddAttrToNode(startNode, allocator, attrName, attrValue);
|
||||
}
|
||||
mSink->OpenContainer(startNode);
|
||||
|
||||
// Add the text node.
|
||||
CTextToken textToken(text);
|
||||
nsCParserNode textNode(&textToken, 0/*stack token*/);
|
||||
mSink->AddLeaf(textNode);
|
||||
|
||||
// Close the element.
|
||||
mSink->CloseContainer(tagType);
|
||||
}
|
||||
|
||||
const nsDependentSubstring CViewSourceHTML::TrimTokenValue(const nsAString& tokenValue) {
|
||||
nsAString::const_iterator start, end;
|
||||
tokenValue.BeginReading(start);
|
||||
tokenValue.EndReading(end);
|
||||
TrimTokenValue(start, end);
|
||||
return Substring(start, end);
|
||||
}
|
||||
|
||||
void CViewSourceHTML::TrimTokenValue(nsAString::const_iterator& start,
|
||||
nsAString::const_iterator& end) {
|
||||
// Token values -- tag names, attribute names, and attribute values --
|
||||
// generally contain adjacent whitespace and, in the case of attribute values,
|
||||
// the surrounding double or single quotes. Return a new string with this
|
||||
// adjacent text stripped off, so only the value proper remains.
|
||||
|
||||
// Skip past any whitespace or quotes on the left.
|
||||
while (start != end) {
|
||||
if (!IsTokenValueTrimmableCharacter(*start)) break;
|
||||
++start;
|
||||
}
|
||||
|
||||
// Skip past any whitespace or quotes on the right. Note that the interval
|
||||
// start..end is half-open. That means the last character of the interval is
|
||||
// at *(end - 1).
|
||||
while (end != start) {
|
||||
--end;
|
||||
if (!IsTokenValueTrimmableCharacter(*end)) {
|
||||
++end; // we've actually gone one too far at this point, so adjust.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool CViewSourceHTML::IsTokenValueTrimmableCharacter(char ch) {
|
||||
if (ch == ' ') return PR_TRUE;
|
||||
if (ch == '\t') return PR_TRUE;
|
||||
if (ch == '\r') return PR_TRUE;
|
||||
if (ch == '\t') return PR_TRUE;
|
||||
if (ch == '\'') return PR_TRUE;
|
||||
if (ch == '"') return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult CViewSourceHTML::GetBaseURI(nsIURI **result) {
|
||||
nsresult rv = NS_OK;
|
||||
if (!mBaseURI) {
|
||||
rv = SetBaseURI(mFilename);
|
||||
}
|
||||
NS_IF_ADDREF(*result = mBaseURI);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult CViewSourceHTML::SetBaseURI(const nsAString& baseSpec) {
|
||||
// Get the character set.
|
||||
nsCString charset;
|
||||
PRInt32 source;
|
||||
mParser->GetDocumentCharset(charset, source);
|
||||
|
||||
// Create a new base URI and store it in mBaseURI.
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), baseSpec, charset.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mBaseURI = baseURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
/**
|
||||
* Set this to TRUE if you want the DTD to verify its
|
||||
* context stack.
|
||||
* @update gess 7/23/98
|
||||
* @update gess 7/23/98
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
@ -100,7 +100,8 @@ private:
|
|||
PRInt32 attrCount,
|
||||
PRBool aTagInError);
|
||||
|
||||
nsresult WriteAttributes(PRInt32 attrCount, PRBool aOwnerInError);
|
||||
nsresult WriteAttributes(const nsAString& tagName,
|
||||
nsTokenAllocator* allocator, PRInt32 attrCount, PRBool aOwnerInError);
|
||||
void StartNewPreBlock(void);
|
||||
// Utility method for adding attributes to the nodes we generate
|
||||
void AddAttrToNode(nsCParserStartNode& aNode,
|
||||
|
@ -108,6 +109,24 @@ private:
|
|||
const nsAString& aAttrName,
|
||||
const nsAString& aAttrValue);
|
||||
|
||||
PRBool IsUrlAttribute(const nsAString& tagName,
|
||||
const nsAString& attrName, const nsAString& attrValue);
|
||||
void WriteHrefAttribute(nsTokenAllocator* allocator, const nsAString& href);
|
||||
nsresult CreateViewSourceURL(const nsAString& linkUrl, nsString& viewSourceUrl);
|
||||
void WriteTextInSpan(const nsAString& text, nsTokenAllocator* allocator,
|
||||
const nsAString& attrName, const nsAString& attrValue);
|
||||
void WriteTextInAnchor(const nsAString& text, nsTokenAllocator* allocator,
|
||||
const nsAString& attrName, const nsAString &attrValue);
|
||||
void WriteTextInElement(const nsAString& tagName, eHTMLTags tagType,
|
||||
const nsAString& text, nsTokenAllocator* allocator,
|
||||
const nsAString& attrName, const nsAString& attrValue);
|
||||
const nsDependentSubstring TrimTokenValue(const nsAString& tokenValue);
|
||||
void TrimTokenValue(nsAString::const_iterator& start,
|
||||
nsAString::const_iterator& end);
|
||||
PRBool IsTokenValueTrimmableCharacter(char ch);
|
||||
nsresult GetBaseURI(nsIURI **result);
|
||||
nsresult SetBaseURI(const nsAString& baseSpec);
|
||||
|
||||
protected:
|
||||
|
||||
nsParser* mParser;
|
||||
|
@ -126,6 +145,7 @@ protected:
|
|||
nsCString mMimeType;
|
||||
|
||||
nsString mFilename;
|
||||
nsCOMPtr<nsIURI> mBaseURI; // lazy -- always use GetBaseURI().
|
||||
|
||||
PRUint32 mTokenCount;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче