{
* UAnchors.pas
*
* Defines a static class that gets information about and manipulates HTML
* anchor element.
*
* $Rev$
* $Date$
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is UAnchors.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2007-2011 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s)
* NONE
*
* ***** END LICENSE BLOCK *****
}
unit UAnchors;
interface
uses
// Project
UBaseObjects, UDispatchList;
type
/// <summary>
/// Enumeration of various kinds of anchor displayed in browser controls.
/// </summary>
/// <remarks>
/// Anchor kinds are specified by CSS class.
/// </remarks>
TAnchorKind = (
akExternal, // external link: class name = 'external-link'
akSnippet, // link to a snippet: class name = 'snippet-link'
akCategory, // link to a category: class name = 'category-link'
akCommand, // link to a JS command: class name = 'command-link'
akHelp, // link to help topic: class name = 'help-link'
akUnknown, // unknown link kind
akError // error finding link kind (element may not be a link)
);
type
/// <summary>
/// Static class that gets information about and manipulates HTML anchor
/// element.
/// </summary>
TAnchors = class(TNoConstructObject)
strict private
/// <summary>Checks if a HTML element Elem is an anchor element.</summary>
class function IsAnchor(const Elem: IDispatch): Boolean;
public
/// <summary>Gets kind of given anchor from CSS class associated with it.
/// </summary>
/// <remarks>
/// <para>akUnknown returned if no recognised CSS class associated with
/// anchor.</para>
/// <para>akError returned if parameter is not an anchor.</para>
/// </remarks>
class function AnchorKind(const Anchor: IDispatch): TAnchorKind;
/// <summary>Returns a list of IDispatch interfaces to all anchors in given
/// HTML document Doc.</summary>
class function GetAllAnchors(const Doc: IDispatch): IDispatchList;
/// <summary>Simulates a click on given anchor element and returns True
/// if anchor element is valid, False if not.</summary>
/// <remarks>Does nothing if anchor is not valid.</remarks>
class function Click(const Anchor: IDispatch): Boolean;
/// <summary>Returns URL of given anchor.</summary>
/// <remarks>Empty string returned if anchor is not valid.</remarks>
class function GetURL(const Anchor: IDispatch): string;
/// <summary>Returns inner text of given anchor.</summary>
class function GetInnerText(const Anchor: IDispatch): string;
/// <summary>Returns any anchor element that encloses, or is, the given
/// HTML element.</summary>
/// <remarks>nil is returned if there is no enclosing anchor element.
/// </remarks>
class function FindEnclosingAnchor(const Elem: IDispatch): IDispatch;
end;
implementation
uses
// Delphi
SysUtils, Variants, MSHTML,
// Project
UHTMLDocHelper, UIStringList;
{ TAnchors }
class function TAnchors.AnchorKind(const Anchor: IDispatch): TAnchorKind;
var
ClassNames: IStringList; // list of Anchor's CSS classes
begin
if not IsAnchor(Anchor) then
Exit(akError);
ClassNames := THTMLDocHelper.GetElemClasses(Anchor);
if ClassNames.Contains('command-link') then
Result := akCommand
else if ClassNames.Contains('help-link') then
Result := akHelp
else if ClassNames.Contains('external-link') then
Result := akExternal
else if ClassNames.Contains('snippet-link') then
Result := akSnippet
else if ClassNames.Contains('category-link') then
Result := akCategory
else
Result := akUnknown;
end;
class function TAnchors.Click(const Anchor: IDispatch): Boolean;
var
Elem: IHTMLElement; // IHTMLElement interface to Anchor
begin
Result := IsAnchor(Anchor) and Supports(Anchor, IHTMLElement, Elem);
if Result then
Elem.click;
end;
class function TAnchors.FindEnclosingAnchor(const Elem: IDispatch): IDispatch;
var
Element: IHTMLElement; // IHTMLElement interface to Elem
begin
if not Supports(Elem, IHTMLElement, Element) then
Exit(nil);
// Search up tree of elements looking for ALink element
Result := Element;
while Assigned(Result) and not Supports(Result, IHTMLAnchorElement) do
Result := (Result as IHTMLElement).parentElement;
end;
class function TAnchors.GetAllAnchors(const Doc: IDispatch): IDispatchList;
var
Document: IHTMLDocument2; // IHTMLDocument2 interface to document
Idx: Integer; // loops through all elements in document
Elem: IHTMLElement; // reference to an element in document
begin
Result := TDispatchList.Create;
if not Supports(Doc, IHTMLDocument2, Document) then
Exit;
for Idx := 0 to Pred(Document.all.length) do
begin
Elem := Document.all.item(Idx, EmptyParam) as IHTMLElement;
if Supports(Elem, IHTMLAnchorElement) then
Result.Add(Elem);
end;
end;
class function TAnchors.GetInnerText(const Anchor: IDispatch): string;
var
Elem: IHTMLElement; // IHTMLElement inteface to Anchor
begin
if not IsAnchor(Anchor) then
Exit('');
if not Supports(Anchor, IHTMLElement, Elem) then
Exit('');
Result := Elem.innerText
end;
class function TAnchors.GetURL(const Anchor: IDispatch): string;
var
AnchorElem: IHTMLAnchorElement; // IHTMLAnchorElement interface to Anchor
begin
if not Supports(Anchor, IHTMLAnchorElement, AnchorElem) then
Exit('');
Result := AnchorElem.href;
end;
class function TAnchors.IsAnchor(const Elem: IDispatch): Boolean;
begin
Result := Supports(Elem, IHTMLAnchorElement);
end;
end.