|
@@ -191,8 +191,17 @@ type
|
|
accessible via fields using specialized properties of descendant classes,
|
|
accessible via fields using specialized properties of descendant classes,
|
|
e.g. TDOMElement.TagName, TDOMCharacterData.Data etc.}
|
|
e.g. TDOMElement.TagName, TDOMCharacterData.Data etc.}
|
|
|
|
|
|
|
|
+ TNodeFlagEnum = (
|
|
|
|
+ nfReadonly,
|
|
|
|
+ nfRecycled,
|
|
|
|
+ nfIgnorableWS,
|
|
|
|
+ nfSpecified
|
|
|
|
+ );
|
|
|
|
+ TNodeFlags = set of TNodeFlagEnum;
|
|
|
|
+
|
|
TDOMNode = class
|
|
TDOMNode = class
|
|
protected
|
|
protected
|
|
|
|
+ FFlags: TNodeFlags;
|
|
FParentNode: TDOMNode;
|
|
FParentNode: TDOMNode;
|
|
FPreviousSibling, FNextSibling: TDOMNode;
|
|
FPreviousSibling, FNextSibling: TDOMNode;
|
|
FOwnerDocument: TDOMDocument;
|
|
FOwnerDocument: TDOMDocument;
|
|
@@ -211,6 +220,7 @@ type
|
|
function GetNamespaceURI: DOMString; virtual;
|
|
function GetNamespaceURI: DOMString; virtual;
|
|
function GetPrefix: DOMString; virtual;
|
|
function GetPrefix: DOMString; virtual;
|
|
procedure SetPrefix(const Value: DOMString); virtual;
|
|
procedure SetPrefix(const Value: DOMString); virtual;
|
|
|
|
+ function GetOwnerDocument: TDOMDocument; virtual;
|
|
public
|
|
public
|
|
constructor Create(AOwner: TDOMDocument);
|
|
constructor Create(AOwner: TDOMDocument);
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
@@ -228,21 +238,18 @@ type
|
|
property PreviousSibling: TDOMNode read FPreviousSibling;
|
|
property PreviousSibling: TDOMNode read FPreviousSibling;
|
|
property NextSibling: TDOMNode read FNextSibling;
|
|
property NextSibling: TDOMNode read FNextSibling;
|
|
property Attributes: TDOMNamedNodeMap read GetAttributes;
|
|
property Attributes: TDOMNamedNodeMap read GetAttributes;
|
|
- // DOM 2: is now nil for documents and unused DocTypes
|
|
|
|
- property OwnerDocument: TDOMDocument read FOwnerDocument;
|
|
|
|
|
|
+ property OwnerDocument: TDOMDocument read GetOwnerDocument;
|
|
|
|
|
|
function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; virtual;
|
|
function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; virtual;
|
|
function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; virtual;
|
|
function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; virtual;
|
|
function DetachChild(OldChild: TDOMNode): TDOMNode; virtual;
|
|
function DetachChild(OldChild: TDOMNode): TDOMNode; virtual;
|
|
function RemoveChild(OldChild: TDOMNode): TDOMNode;
|
|
function RemoveChild(OldChild: TDOMNode): TDOMNode;
|
|
- function AppendChild(NewChild: TDOMNode): TDOMNode; virtual;
|
|
|
|
|
|
+ function AppendChild(NewChild: TDOMNode): TDOMNode;
|
|
function HasChildNodes: Boolean; virtual;
|
|
function HasChildNodes: Boolean; virtual;
|
|
function CloneNode(deep: Boolean): TDOMNode; overload;
|
|
function CloneNode(deep: Boolean): TDOMNode; overload;
|
|
|
|
|
|
// DOM level 2
|
|
// DOM level 2
|
|
- (*
|
|
|
|
- function Supports(const Feature, Version: DOMString): Boolean;
|
|
|
|
- *)
|
|
|
|
|
|
+ function IsSupported(const Feature, Version: DOMString): Boolean;
|
|
function HasAttributes: Boolean; virtual;
|
|
function HasAttributes: Boolean; virtual;
|
|
procedure Normalize; virtual;
|
|
procedure Normalize; virtual;
|
|
|
|
|
|
@@ -279,7 +286,6 @@ type
|
|
function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; override;
|
|
function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; override;
|
|
function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; override;
|
|
function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; override;
|
|
function DetachChild(OldChild: TDOMNode): TDOMNode; override;
|
|
function DetachChild(OldChild: TDOMNode): TDOMNode; override;
|
|
- function AppendChild(NewChild: TDOMNode): TDOMNode; override;
|
|
|
|
function HasChildNodes: Boolean; override;
|
|
function HasChildNodes: Boolean; override;
|
|
function FindNode(const ANodeName: DOMString): TDOMNode; override;
|
|
function FindNode(const ANodeName: DOMString): TDOMNode; override;
|
|
end;
|
|
end;
|
|
@@ -302,6 +308,7 @@ type
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
property Item[index: LongWord]: TDOMNode read GetItem; default;
|
|
property Item[index: LongWord]: TDOMNode read GetItem; default;
|
|
property Count: LongWord read GetCount;
|
|
property Count: LongWord read GetCount;
|
|
|
|
+ property Length: LongWord read GetCount;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ an extension to DOM interface, used to build recursive lists of elements }
|
|
{ an extension to DOM interface, used to build recursive lists of elements }
|
|
@@ -362,7 +369,7 @@ type
|
|
function GetNodeValue: DOMString; override;
|
|
function GetNodeValue: DOMString; override;
|
|
procedure SetNodeValue(const AValue: DOMString); override;
|
|
procedure SetNodeValue(const AValue: DOMString); override;
|
|
public
|
|
public
|
|
- property Data: DOMString read FNodeValue write FNodeValue;
|
|
|
|
|
|
+ property Data: DOMString read FNodeValue write SetNodeValue;
|
|
property Length: LongWord read GetLength;
|
|
property Length: LongWord read GetLength;
|
|
function SubstringData(offset, count: LongWord): DOMString;
|
|
function SubstringData(offset, count: LongWord): DOMString;
|
|
procedure AppendData(const arg: DOMString);
|
|
procedure AppendData(const arg: DOMString);
|
|
@@ -416,6 +423,9 @@ type
|
|
function GetDocType: TDOMDocumentType;
|
|
function GetDocType: TDOMDocumentType;
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeName: DOMString; override;
|
|
function GetNodeName: DOMString; override;
|
|
|
|
+ function GetTextContent: DOMString; override;
|
|
|
|
+ function GetOwnerDocument: TDOMDocument; override;
|
|
|
|
+ procedure SetTextContent(const value: DOMString); override;
|
|
function IndexOfNS(const nsURI: DOMString): Integer;
|
|
function IndexOfNS(const nsURI: DOMString): Integer;
|
|
function FindID(const aID: DOMString; out Index: LongWord): Boolean;
|
|
function FindID(const aID: DOMString; out Index: LongWord): Boolean;
|
|
procedure ClearIDList;
|
|
procedure ClearIDList;
|
|
@@ -429,7 +439,7 @@ type
|
|
function CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
|
|
function CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
|
|
function CreateDocumentFragment: TDOMDocumentFragment;
|
|
function CreateDocumentFragment: TDOMDocumentFragment;
|
|
function CreateTextNode(const data: DOMString): TDOMText;
|
|
function CreateTextNode(const data: DOMString): TDOMText;
|
|
- function CreateTextNodeBuf(Buf: DOMPChar; Length: Integer): TDOMText;
|
|
|
|
|
|
+ function CreateTextNodeBuf(Buf: DOMPChar; Length: Integer; IgnWS: Boolean): TDOMText;
|
|
function CreateComment(const data: DOMString): TDOMComment;
|
|
function CreateComment(const data: DOMString): TDOMComment;
|
|
function CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
|
|
function CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
|
|
function CreateCDATASection(const data: DOMString): TDOMCDATASection;
|
|
function CreateCDATASection(const data: DOMString): TDOMCDATASection;
|
|
@@ -491,18 +501,18 @@ type
|
|
protected
|
|
protected
|
|
FName: DOMString;
|
|
FName: DOMString;
|
|
FOwnerElement: TDOMElement;
|
|
FOwnerElement: TDOMElement;
|
|
- FSpecified: Boolean;
|
|
|
|
// TODO: following 2 - replace with a link to AttDecl ??
|
|
// TODO: following 2 - replace with a link to AttDecl ??
|
|
FDeclared: Boolean;
|
|
FDeclared: Boolean;
|
|
FDataType: TAttrDataType;
|
|
FDataType: TAttrDataType;
|
|
function GetNodeValue: DOMString; override;
|
|
function GetNodeValue: DOMString; override;
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeName: DOMString; override;
|
|
function GetNodeName: DOMString; override;
|
|
|
|
+ function GetSpecified: Boolean;
|
|
procedure SetNodeValue(const AValue: DOMString); override;
|
|
procedure SetNodeValue(const AValue: DOMString); override;
|
|
public
|
|
public
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
property Name: DOMString read FName;
|
|
property Name: DOMString read FName;
|
|
- property Specified: Boolean read FSpecified;
|
|
|
|
|
|
+ property Specified: Boolean read GetSpecified;
|
|
property Value: DOMString read GetNodeValue write SetNodeValue;
|
|
property Value: DOMString read GetNodeValue write SetNodeValue;
|
|
property OwnerElement: TDOMElement read FOwnerElement;
|
|
property OwnerElement: TDOMElement read FOwnerElement;
|
|
// extensions
|
|
// extensions
|
|
@@ -560,16 +570,13 @@ type
|
|
|
|
|
|
TDOMText = class(TDOMCharacterData)
|
|
TDOMText = class(TDOMCharacterData)
|
|
protected
|
|
protected
|
|
- // set by parser if text contains only literal whitespace (i.e. not coming from CharRefs)
|
|
|
|
- FMayBeIgnorable: Boolean;
|
|
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeType: Integer; override;
|
|
function GetNodeName: DOMString; override;
|
|
function GetNodeName: DOMString; override;
|
|
procedure SetNodeValue(const aValue: DOMString); override;
|
|
procedure SetNodeValue(const aValue: DOMString); override;
|
|
public
|
|
public
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
function SplitText(offset: LongWord): TDOMText;
|
|
function SplitText(offset: LongWord): TDOMText;
|
|
- // Extension
|
|
|
|
- property MayBeIgnorable: Boolean read FMayBeIgnorable write FMayBeIgnorable;
|
|
|
|
|
|
+ function IsElementContentWhitespace: Boolean;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
@@ -695,7 +702,7 @@ type
|
|
public
|
|
public
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
|
|
property Target: DOMString read FTarget;
|
|
property Target: DOMString read FTarget;
|
|
- property Data: DOMString read FNodeValue write FNodeValue;
|
|
|
|
|
|
+ property Data: DOMString read FNodeValue write SetNodeValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
@@ -877,8 +884,7 @@ end;
|
|
|
|
|
|
function TDOMNode.AppendChild(NewChild: TDOMNode): TDOMNode;
|
|
function TDOMNode.AppendChild(NewChild: TDOMNode): TDOMNode;
|
|
begin
|
|
begin
|
|
- raise EDOMHierarchyRequest.Create('Node.AppendChild');
|
|
|
|
- Result:=nil;
|
|
|
|
|
|
+ Result := InsertBefore(NewChild, nil);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMNode.HasChildNodes: Boolean;
|
|
function TDOMNode.HasChildNodes: Boolean;
|
|
@@ -909,6 +915,11 @@ begin
|
|
Result := FOwnerDocument.FRevision;
|
|
Result := FOwnerDocument.FRevision;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TDOMNode.IsSupported(const Feature, Version: DOMString): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwnerDocument.Impl.HasFeature(Feature, Version);
|
|
|
|
+end;
|
|
|
|
+
|
|
function TDOMNode.HasAttributes: Boolean;
|
|
function TDOMNode.HasAttributes: Boolean;
|
|
begin
|
|
begin
|
|
Result := False;
|
|
Result := False;
|
|
@@ -932,7 +943,8 @@ begin
|
|
if Assigned(Txt) then
|
|
if Assigned(Txt) then
|
|
begin
|
|
begin
|
|
Txt.AppendData(TDOMText(Child).Data);
|
|
Txt.AppendData(TDOMText(Child).Data);
|
|
- Txt.FMayBeIgnorable := Txt.FMayBeIgnorable and TDOMText(Child).FMayBeIgnorable;
|
|
|
|
|
|
+ // TODO: maybe should be smarter
|
|
|
|
+ Exclude(Txt.FFlags, nfIgnorableWS);
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
@@ -960,7 +972,7 @@ end;
|
|
|
|
|
|
procedure TDOMNode.SetTextContent(const AValue: DOMString);
|
|
procedure TDOMNode.SetTextContent(const AValue: DOMString);
|
|
begin
|
|
begin
|
|
- NodeValue := AValue;
|
|
|
|
|
|
+ SetNodeValue(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMNode.GetNamespaceURI: DOMString;
|
|
function TDOMNode.GetNamespaceURI: DOMString;
|
|
@@ -983,6 +995,11 @@ begin
|
|
// do nothing, override for Elements and Attributes
|
|
// do nothing, override for Elements and Attributes
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TDOMNode.GetOwnerDocument: TDOMDocument;
|
|
|
|
+begin
|
|
|
|
+ Result := FOwnerDocument;
|
|
|
|
+end;
|
|
|
|
+
|
|
function CompareDOMStrings(const s1, s2: DOMPChar; l1, l2: integer): integer;
|
|
function CompareDOMStrings(const s1, s2: DOMPChar; l1, l2: integer): integer;
|
|
var i: integer;
|
|
var i: integer;
|
|
begin
|
|
begin
|
|
@@ -1063,20 +1080,19 @@ var
|
|
NewChildType: Integer;
|
|
NewChildType: Integer;
|
|
begin
|
|
begin
|
|
Result := NewChild;
|
|
Result := NewChild;
|
|
|
|
+ NewChildType := NewChild.NodeType;
|
|
|
|
|
|
- if not Assigned(RefChild) then
|
|
|
|
|
|
+ if NewChild.FOwnerDocument <> FOwnerDocument then
|
|
begin
|
|
begin
|
|
- AppendChild(NewChild);
|
|
|
|
- exit;
|
|
|
|
|
|
+ if (NewChildType <> DOCUMENT_TYPE_NODE) or
|
|
|
|
+ (NewChild.FOwnerDocument <> nil) then
|
|
|
|
+ raise EDOMWrongDocument.Create('NodeWC.InsertBefore');
|
|
end;
|
|
end;
|
|
|
|
|
|
- if NewChild.FOwnerDocument <> FOwnerDocument then
|
|
|
|
- raise EDOMWrongDocument.Create('NodeWC.InsertBefore');
|
|
|
|
-
|
|
|
|
- if RefChild.ParentNode <> Self then
|
|
|
|
|
|
+ if Assigned(RefChild) and (RefChild.ParentNode <> Self) then
|
|
raise EDOMNotFound.Create('NodeWC.InsertBefore');
|
|
raise EDOMNotFound.Create('NodeWC.InsertBefore');
|
|
|
|
|
|
- NewChildType := NewChild.NodeType;
|
|
|
|
|
|
+ // TODO: skip checking Fragments as well? (Fragment itself cannot be in the tree)
|
|
if not (NewChildType in [TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE]) and (NewChild.FirstChild <> nil) then
|
|
if not (NewChildType in [TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE]) and (NewChild.FirstChild <> nil) then
|
|
begin
|
|
begin
|
|
Tmp := Self;
|
|
Tmp := Self;
|
|
@@ -1087,45 +1103,26 @@ begin
|
|
Tmp := Tmp.ParentNode;
|
|
Tmp := Tmp.ParentNode;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
+ if NewChild = RefChild then // inserting node before itself is a no-op
|
|
|
|
+ Exit;
|
|
|
|
|
|
Inc(FOwnerDocument.FRevision); // invalidate nodelists
|
|
Inc(FOwnerDocument.FRevision); // invalidate nodelists
|
|
|
|
|
|
- // DONE: Implemented InsertBefore for DocumentFragments (except ChildNodeTree)
|
|
|
|
if NewChildType = DOCUMENT_FRAGMENT_NODE then
|
|
if NewChildType = DOCUMENT_FRAGMENT_NODE then
|
|
begin
|
|
begin
|
|
- // Is fragment empty?
|
|
|
|
Tmp := NewChild.FirstChild;
|
|
Tmp := NewChild.FirstChild;
|
|
- if not Assigned(Tmp) then
|
|
|
|
- Exit;
|
|
|
|
- // reparent nodes
|
|
|
|
- while Assigned(Tmp) do
|
|
|
|
- begin
|
|
|
|
- Tmp.FParentNode := Self;
|
|
|
|
- Tmp := Tmp.NextSibling;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- // won't get here if RefChild = nil...
|
|
|
|
- if (RefChild = nil) or (RefChild.FPreviousSibling = nil) then
|
|
|
|
- begin // insert at the beginning <- AppendChild ??? ->
|
|
|
|
- // no, AppendChild will insert after RefChild and we need it before
|
|
|
|
- if Assigned(FFirstChild) then
|
|
|
|
- FFirstChild.FPreviousSibling := NewChild.LastChild;
|
|
|
|
- NewChild.LastChild.FNextSibling := FirstChild;
|
|
|
|
- if not Assigned(FLastChild) then
|
|
|
|
- FLastChild := NewChild.LastChild;
|
|
|
|
- FFirstChild := NewChild.FirstChild;
|
|
|
|
- end
|
|
|
|
- else // insert to the middle
|
|
|
|
|
|
+ if Assigned(Tmp) then
|
|
begin
|
|
begin
|
|
- NewChild.LastChild.FNextSibling := RefChild;
|
|
|
|
- NewChild.FirstChild.FPreviousSibling := RefChild.FPreviousSibling;
|
|
|
|
- RefChild.FPreviousSibling.FNextSibling := NewChild.FirstChild;
|
|
|
|
- RefChild.FPreviousSibling := NewChild.LastChild;
|
|
|
|
|
|
+ while Assigned(Tmp) do
|
|
|
|
+ begin
|
|
|
|
+ if not (Tmp.NodeType in ValidChildren[NodeType]) then
|
|
|
|
+ raise EDOMHierarchyRequest.Create('NodeWC.InsertBefore');
|
|
|
|
+ Tmp := Tmp.NextSibling;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ while Assigned(TDOMDocumentFragment(NewChild).FFirstChild) do
|
|
|
|
+ InsertBefore(TDOMDocumentFragment(NewChild).FFirstChild, RefChild);
|
|
end;
|
|
end;
|
|
- // finally, detach nodes from the fragment
|
|
|
|
- TDOMDocumentFragment(NewChild).FFirstChild := nil;
|
|
|
|
- TDOMDocumentFragment(NewChild).FLastChild := nil;
|
|
|
|
- // TODO: ChildNodeTree...
|
|
|
|
Exit;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -1136,15 +1133,27 @@ begin
|
|
NewChild.FParentNode.DetachChild(NewChild);
|
|
NewChild.FParentNode.DetachChild(NewChild);
|
|
|
|
|
|
NewChild.FNextSibling := RefChild;
|
|
NewChild.FNextSibling := RefChild;
|
|
- if RefChild = FFirstChild then
|
|
|
|
- FFirstChild := NewChild
|
|
|
|
- else
|
|
|
|
|
|
+ if RefChild = nil then // append to the end
|
|
|
|
+ begin
|
|
|
|
+ if Assigned(FFirstChild) then
|
|
|
|
+ begin
|
|
|
|
+ FLastChild.FNextSibling := NewChild;
|
|
|
|
+ NewChild.FPreviousSibling := FLastChild;
|
|
|
|
+ end else
|
|
|
|
+ FFirstChild := NewChild;
|
|
|
|
+ FLastChild := NewChild;
|
|
|
|
+ end
|
|
|
|
+ else // insert before RefChild
|
|
begin
|
|
begin
|
|
- RefChild.FPreviousSibling.FNextSibling := NewChild;
|
|
|
|
- NewChild.FPreviousSibling := RefChild.FPreviousSibling;
|
|
|
|
|
|
+ if RefChild = FFirstChild then
|
|
|
|
+ FFirstChild := NewChild
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ RefChild.FPreviousSibling.FNextSibling := NewChild;
|
|
|
|
+ NewChild.FPreviousSibling := RefChild.FPreviousSibling;
|
|
|
|
+ end;
|
|
|
|
+ RefChild.FPreviousSibling := NewChild;
|
|
end;
|
|
end;
|
|
-
|
|
|
|
- RefChild.FPreviousSibling := NewChild;
|
|
|
|
NewChild.FParentNode := Self;
|
|
NewChild.FParentNode := Self;
|
|
AddToChildNodeTree(NewChild);
|
|
AddToChildNodeTree(NewChild);
|
|
end;
|
|
end;
|
|
@@ -1185,76 +1194,6 @@ begin
|
|
Result := OldChild;
|
|
Result := OldChild;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TDOMNode_WithChildren.AppendChild(NewChild: TDOMNode): TDOMNode;
|
|
|
|
-var
|
|
|
|
- Tmp: TDOMNode;
|
|
|
|
- NewChildType: Integer;
|
|
|
|
-begin
|
|
|
|
- if NewChild.FOwnerDocument <> FOwnerDocument then
|
|
|
|
- raise EDOMWrongDocument.Create('NodeWC.AppendChild');
|
|
|
|
-
|
|
|
|
- // Don't walk the tree if NewChild apriori cannot be our parent.
|
|
|
|
- // This saves a lot of CPU cache misses.
|
|
|
|
- NewChildType := NewChild.NodeType;
|
|
|
|
- if not (NewChildType in [TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE]) and (NewChild.FirstChild <> nil) then
|
|
|
|
- begin
|
|
|
|
- Tmp := Self;
|
|
|
|
- while Assigned(Tmp) do
|
|
|
|
- begin
|
|
|
|
- if Tmp = NewChild then
|
|
|
|
- raise EDOMHierarchyRequest.Create('NodeWC.AppendChild (cycle in tree)');
|
|
|
|
- Tmp := Tmp.ParentNode;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- Inc(FOwnerDocument.FRevision); // invalidate nodelists
|
|
|
|
-
|
|
|
|
- // DONE: supported AppendChild for DocumentFragments (except ChildNodeTree)
|
|
|
|
- if NewChildType = DOCUMENT_FRAGMENT_NODE then
|
|
|
|
- begin
|
|
|
|
- Tmp := NewChild.FirstChild;
|
|
|
|
- // Is fragment empty?
|
|
|
|
- if Assigned(Tmp) then
|
|
|
|
- begin
|
|
|
|
- // reparent nodes
|
|
|
|
- while Assigned(Tmp) do
|
|
|
|
- begin
|
|
|
|
- Tmp.FParentNode := Self;
|
|
|
|
- Tmp := Tmp.NextSibling;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- if Assigned(FLastChild) then
|
|
|
|
- FLastChild.FNextSibling := NewChild.FirstChild;
|
|
|
|
- NewChild.FirstChild.FPreviousSibling := LastChild;
|
|
|
|
- if not Assigned(FFirstChild) then
|
|
|
|
- FFirstChild := NewChild.FirstChild;
|
|
|
|
- FLastChild := NewChild.LastChild;
|
|
|
|
- // detach nodes from fragment
|
|
|
|
- TDOMDocumentFragment(NewChild).FFirstChild := nil;
|
|
|
|
- TDOMDocumentFragment(NewChild).FLastChild := nil;
|
|
|
|
- // TODO: ChildNodeTree...
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- if not (NewChildType in ValidChildren[NodeType]) then
|
|
|
|
- raise EDOMHierarchyRequest.Create('NodeWC.AppendChild');
|
|
|
|
-
|
|
|
|
- if Assigned(NewChild.FParentNode) then
|
|
|
|
- NewChild.FParentNode.DetachChild(NewChild);
|
|
|
|
-
|
|
|
|
- if Assigned(FFirstChild) then
|
|
|
|
- begin
|
|
|
|
- FLastChild.FNextSibling := NewChild;
|
|
|
|
- NewChild.FPreviousSibling := FLastChild;
|
|
|
|
- end else
|
|
|
|
- FFirstChild := NewChild;
|
|
|
|
- FLastChild := NewChild;
|
|
|
|
- NewChild.FParentNode := Self;
|
|
|
|
- AddToChildNodeTree(NewChild);
|
|
|
|
- end;
|
|
|
|
- Result := NewChild;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
function TDOMNode_WithChildren.HasChildNodes: Boolean;
|
|
function TDOMNode_WithChildren.HasChildNodes: Boolean;
|
|
begin
|
|
begin
|
|
Result := Assigned(FFirstChild);
|
|
Result := Assigned(FFirstChild);
|
|
@@ -1312,11 +1251,15 @@ begin
|
|
Result := '';
|
|
Result := '';
|
|
child := FFirstChild;
|
|
child := FFirstChild;
|
|
// TODO: probably very slow, optimization needed
|
|
// TODO: probably very slow, optimization needed
|
|
- // TODO: must ignore whitespace nodes
|
|
|
|
while Assigned(child) do
|
|
while Assigned(child) do
|
|
begin
|
|
begin
|
|
- if not (child.NodeType in [COMMENT_NODE, PROCESSING_INSTRUCTION_NODE]) then
|
|
|
|
|
|
+ case child.NodeType of
|
|
|
|
+ TEXT_NODE: if not (nfIgnorableWS in child.FFlags) then
|
|
|
|
+ Result := Result + TDOMText(child).Data;
|
|
|
|
+ COMMENT_NODE, PROCESSING_INSTRUCTION_NODE: ; // ignored
|
|
|
|
+ else
|
|
Result := Result + child.TextContent;
|
|
Result := Result + child.TextContent;
|
|
|
|
+ end;
|
|
child := child.NextSibling;
|
|
child := child.NextSibling;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -1557,6 +1500,8 @@ begin
|
|
if Exists then
|
|
if Exists then
|
|
begin
|
|
begin
|
|
Result := TDOMNode(FList.List^[i]);
|
|
Result := TDOMNode(FList.List^[i]);
|
|
|
|
+ if FNodeType = ATTRIBUTE_NODE then
|
|
|
|
+ TDOMAttr(Result).FOwnerElement := nil;
|
|
FList.List^[i] := arg;
|
|
FList.List^[i] := arg;
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
@@ -1625,7 +1570,7 @@ end;
|
|
|
|
|
|
function TDOMCharacterData.SubstringData(offset, count: LongWord): DOMString;
|
|
function TDOMCharacterData.SubstringData(offset, count: LongWord): DOMString;
|
|
begin
|
|
begin
|
|
- if (offset > Length) then
|
|
|
|
|
|
+ if offset > Length then
|
|
raise EDOMIndexSize.Create('CharacterData.SubstringData');
|
|
raise EDOMIndexSize.Create('CharacterData.SubstringData');
|
|
Result := Copy(FNodeValue, offset + 1, count);
|
|
Result := Copy(FNodeValue, offset + 1, count);
|
|
end;
|
|
end;
|
|
@@ -1637,20 +1582,16 @@ end;
|
|
|
|
|
|
procedure TDOMCharacterData.InsertData(offset: LongWord; const arg: DOMString);
|
|
procedure TDOMCharacterData.InsertData(offset: LongWord; const arg: DOMString);
|
|
begin
|
|
begin
|
|
- if (offset > Length) then
|
|
|
|
|
|
+ if offset > Length then
|
|
raise EDOMIndexSize.Create('CharacterData.InsertData');
|
|
raise EDOMIndexSize.Create('CharacterData.InsertData');
|
|
- // TODO: use System.Insert?
|
|
|
|
- FNodeValue := Copy(FNodeValue, 1, offset) + arg +
|
|
|
|
- Copy(FNodeValue, offset + 1, Length);
|
|
|
|
|
|
+ Insert(arg, FNodeValue, offset+1);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TDOMCharacterData.DeleteData(offset, count: LongWord);
|
|
procedure TDOMCharacterData.DeleteData(offset, count: LongWord);
|
|
begin
|
|
begin
|
|
- if (offset > Length) then
|
|
|
|
|
|
+ if offset > Length then
|
|
raise EDOMIndexSize.Create('CharacterData.DeleteData');
|
|
raise EDOMIndexSize.Create('CharacterData.DeleteData');
|
|
- // TODO: use System.Delete?
|
|
|
|
- FNodeValue := Copy(FNodeValue, 1, offset) +
|
|
|
|
- Copy(FNodeValue, offset + count + 1, Length);
|
|
|
|
|
|
+ Delete(FNodeValue, offset+1, count);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TDOMCharacterData.ReplaceData(offset, count: LongWord; const arg: DOMString);
|
|
procedure TDOMCharacterData.ReplaceData(offset, count: LongWord; const arg: DOMString);
|
|
@@ -1687,17 +1628,11 @@ end;
|
|
|
|
|
|
function TDOMImplementation.HasFeature(const feature, version: DOMString):
|
|
function TDOMImplementation.HasFeature(const feature, version: DOMString):
|
|
Boolean;
|
|
Boolean;
|
|
|
|
+var
|
|
|
|
+ s: string;
|
|
begin
|
|
begin
|
|
- // very basic
|
|
|
|
- if (feature = 'XML') then
|
|
|
|
- begin
|
|
|
|
- if (version = '') or (version = '1.0') then
|
|
|
|
- Result := True
|
|
|
|
- else
|
|
|
|
- Result := False;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- Result := False;
|
|
|
|
|
|
+ s := feature; // force Ansi, features do not contain non-ASCII chars
|
|
|
|
+ Result := SameText(s, 'XML') and ((version = '') or (version = '1.0'));
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMImplementation.CreateDocumentType(const QualifiedName, PublicID,
|
|
function TDOMImplementation.CreateDocumentType(const QualifiedName, PublicID,
|
|
@@ -1707,12 +1642,9 @@ begin
|
|
Result := TDOMDocumentType.Create(nil);
|
|
Result := TDOMDocumentType.Create(nil);
|
|
Result.FName := QualifiedName;
|
|
Result.FName := QualifiedName;
|
|
|
|
|
|
- // cannot have PublicID without SystemID
|
|
|
|
- if SystemID <> '' then
|
|
|
|
- begin
|
|
|
|
- Result.FPublicID := PublicID;
|
|
|
|
- Result.FSystemID := SystemID;
|
|
|
|
- end;
|
|
|
|
|
|
+ // DOM does not restrict PublicID without SystemID (unlike XML spec)
|
|
|
|
+ Result.FPublicID := PublicID;
|
|
|
|
+ Result.FSystemID := SystemID;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMImplementation.CreateDocument(const NamespaceURI,
|
|
function TDOMImplementation.CreateDocument(const NamespaceURI,
|
|
@@ -1845,6 +1777,21 @@ begin
|
|
Result := '#document';
|
|
Result := '#document';
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TDOMDocument.GetTextContent: DOMString;
|
|
|
|
+begin
|
|
|
|
+ Result := '';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TDOMDocument.SetTextContent(const value: DOMString);
|
|
|
|
+begin
|
|
|
|
+ // Document ignores setting TextContent
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TDOMDocument.GetOwnerDocument: TDOMDocument;
|
|
|
|
+begin
|
|
|
|
+ Result := nil;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TDOMDocument.GetDocumentElement: TDOMElement;
|
|
function TDOMDocument.GetDocumentElement: TDOMElement;
|
|
var
|
|
var
|
|
node: TDOMNode;
|
|
node: TDOMNode;
|
|
@@ -1892,10 +1839,12 @@ begin
|
|
Result.FNodeValue := data;
|
|
Result.FNodeValue := data;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TDOMDocument.CreateTextNodeBuf(Buf: DOMPChar; Length: Integer): TDOMText;
|
|
|
|
|
|
+function TDOMDocument.CreateTextNodeBuf(Buf: DOMPChar; Length: Integer; IgnWS: Boolean): TDOMText;
|
|
begin
|
|
begin
|
|
Result := TDOMText.Create(Self);
|
|
Result := TDOMText.Create(Self);
|
|
SetString(Result.FNodeValue, Buf, Length);
|
|
SetString(Result.FNodeValue, Buf, Length);
|
|
|
|
+ if IgnWS then
|
|
|
|
+ Include(Result.FFlags, nfIgnorableWS);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
@@ -1931,13 +1880,14 @@ begin
|
|
raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateAttribute');
|
|
raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateAttribute');
|
|
Result := TDOMAttr.Create(Self);
|
|
Result := TDOMAttr.Create(Self);
|
|
Result.FName := name;
|
|
Result.FName := name;
|
|
|
|
+ Include(Result.FFlags, nfSpecified);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMDocument.CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
|
|
function TDOMDocument.CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
|
|
begin
|
|
begin
|
|
Result := TDOMAttr.Create(Self);
|
|
Result := TDOMAttr.Create(Self);
|
|
SetString(Result.FName, Buf, Length);
|
|
SetString(Result.FName, Buf, Length);
|
|
- Result.FSpecified := True;
|
|
|
|
|
|
+ Include(Result.FFlags, nfSpecified);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMDocument.CreateEntityReference(const name: DOMString):
|
|
function TDOMDocument.CreateEntityReference(const name: DOMString):
|
|
@@ -2015,12 +1965,21 @@ end;
|
|
|
|
|
|
function TXMLDocument.CreateEntityReference(const name: DOMString):
|
|
function TXMLDocument.CreateEntityReference(const name: DOMString):
|
|
TDOMEntityReference;
|
|
TDOMEntityReference;
|
|
|
|
+var
|
|
|
|
+ dType: TDOMDocumentType;
|
|
|
|
+ ent: TDOMEntity;
|
|
begin
|
|
begin
|
|
if not IsXmlName(name, FXML11) then
|
|
if not IsXmlName(name, FXML11) then
|
|
raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateEntityReference');
|
|
raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateEntityReference');
|
|
Result := TDOMEntityReference.Create(Self);
|
|
Result := TDOMEntityReference.Create(Self);
|
|
Result.FName := name;
|
|
Result.FName := name;
|
|
- // TODO: if entity is known, its child list must be cloned or so.
|
|
|
|
|
|
+ dType := DocType;
|
|
|
|
+ if Assigned(dType) then
|
|
|
|
+ begin
|
|
|
|
+ TDOMNode(ent) := dType.Entities.GetNamedItem(name);
|
|
|
|
+ if Assigned(ent) then
|
|
|
|
+ ent.CloneChildren(Result, Self);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TXMLDocument.SetXMLVersion(const aValue: DOMString);
|
|
procedure TXMLDocument.SetXMLVersion(const aValue: DOMString);
|
|
@@ -2047,7 +2006,6 @@ function TDOMAttr.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
|
|
begin
|
|
begin
|
|
// Cloned attribute is always specified and carries its children
|
|
// Cloned attribute is always specified and carries its children
|
|
Result := ACloneOwner.CreateAttribute(FName);
|
|
Result := ACloneOwner.CreateAttribute(FName);
|
|
- TDOMAttr(Result).FSpecified := True;
|
|
|
|
TDOMAttr(Result).FDataType := FDataType;
|
|
TDOMAttr(Result).FDataType := FDataType;
|
|
// Declared = ?
|
|
// Declared = ?
|
|
CloneChildren(Result, ACloneOwner);
|
|
CloneChildren(Result, ACloneOwner);
|
|
@@ -2062,8 +2020,8 @@ end;
|
|
|
|
|
|
procedure TDOMAttr.SetNodeValue(const AValue: DOMString);
|
|
procedure TDOMAttr.SetNodeValue(const AValue: DOMString);
|
|
begin
|
|
begin
|
|
- FSpecified := True;
|
|
|
|
SetTextContent(AValue);
|
|
SetTextContent(AValue);
|
|
|
|
+ Include(FFlags, nfSpecified);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMAttr.CompareName(const AName: DOMString): Integer;
|
|
function TDOMAttr.CompareName(const AName: DOMString): Integer;
|
|
@@ -2071,6 +2029,11 @@ begin
|
|
Result := CompareDOMStrings(DOMPChar(AName), DOMPChar(FName), Length(AName), Length(FName));
|
|
Result := CompareDOMStrings(DOMPChar(AName), DOMPChar(FName), Length(AName), Length(FName));
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TDOMAttr.GetSpecified: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := nfSpecified in FFlags;
|
|
|
|
+end;
|
|
|
|
+
|
|
// -------------------------------------------------------
|
|
// -------------------------------------------------------
|
|
// Element
|
|
// Element
|
|
// -------------------------------------------------------
|
|
// -------------------------------------------------------
|
|
@@ -2161,6 +2124,7 @@ begin
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
Attr := FOwnerDocument.CreateAttribute(name);
|
|
Attr := FOwnerDocument.CreateAttribute(name);
|
|
|
|
+ Attr.FOwnerElement := Self;
|
|
FAttributes.FList.Insert(I, Attr);
|
|
FAttributes.FList.Insert(I, Attr);
|
|
end;
|
|
end;
|
|
attr.NodeValue := value;
|
|
attr.NodeValue := value;
|
|
@@ -2197,7 +2161,6 @@ end;
|
|
|
|
|
|
function TDOMElement.GetAttributeNode(const name: DOMString): TDOMAttr;
|
|
function TDOMElement.GetAttributeNode(const name: DOMString): TDOMAttr;
|
|
begin
|
|
begin
|
|
- // DONE: delegated to TNamedNodeMap.GetNamedItem
|
|
|
|
if Assigned(FAttributes) then
|
|
if Assigned(FAttributes) then
|
|
Result := FAttributes.GetNamedItem(name) as TDOMAttr
|
|
Result := FAttributes.GetNamedItem(name) as TDOMAttr
|
|
else
|
|
else
|
|
@@ -2217,8 +2180,11 @@ begin
|
|
Result := Attributes.SetNamedItem(NewAttr) as TDOMAttr;
|
|
Result := Attributes.SetNamedItem(NewAttr) as TDOMAttr;
|
|
|
|
|
|
// TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
|
|
// TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
|
|
- Result.Free;
|
|
|
|
- Result := nil;
|
|
|
|
|
|
+ if Assigned(Result) and (Result <> NewAttr) then
|
|
|
|
+ begin
|
|
|
|
+ Result.Free;
|
|
|
|
+ Result := nil;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMElement.SetAttributeNodeNS(NewAttr: TDOMAttr): TDOMAttr;
|
|
function TDOMElement.SetAttributeNodeNS(NewAttr: TDOMAttr): TDOMAttr;
|
|
@@ -2226,8 +2192,11 @@ begin
|
|
Result := Attributes.SetNamedItemNS(NewAttr) as TDOMAttr;
|
|
Result := Attributes.SetNamedItemNS(NewAttr) as TDOMAttr;
|
|
|
|
|
|
// TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
|
|
// TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
|
|
- Result.Free;
|
|
|
|
- Result := nil;
|
|
|
|
|
|
+ if Assigned(Result) and (Result <> NewAttr) then
|
|
|
|
+ begin
|
|
|
|
+ Result.Free;
|
|
|
|
+ Result := nil;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
@@ -2291,15 +2260,14 @@ end;
|
|
|
|
|
|
procedure TDOMText.SetNodeValue(const aValue: DOMString);
|
|
procedure TDOMText.SetNodeValue(const aValue: DOMString);
|
|
begin
|
|
begin
|
|
|
|
+ inherited SetNodeValue(aValue);
|
|
// TODO: may analyze aValue, but this will slow things down...
|
|
// TODO: may analyze aValue, but this will slow things down...
|
|
- FMayBeIgnorable := False;
|
|
|
|
- FNodeValue := aValue;
|
|
|
|
|
|
+ Exclude(FFlags, nfIgnorableWS);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMText.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
|
|
function TDOMText.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
|
|
begin
|
|
begin
|
|
Result := ACloneOwner.CreateTextNode(FNodeValue);
|
|
Result := ACloneOwner.CreateTextNode(FNodeValue);
|
|
- TDOMText(Result).FMayBeIgnorable := FMayBeIgnorable;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
function TDOMText.SplitText(offset: LongWord): TDOMText;
|
|
function TDOMText.SplitText(offset: LongWord): TDOMText;
|
|
@@ -2309,11 +2277,16 @@ begin
|
|
|
|
|
|
Result := TDOMText.Create(FOwnerDocument);
|
|
Result := TDOMText.Create(FOwnerDocument);
|
|
Result.FNodeValue := Copy(FNodeValue, offset + 1, Length);
|
|
Result.FNodeValue := Copy(FNodeValue, offset + 1, Length);
|
|
- Result.FMayBeIgnorable := FMayBeIgnorable;
|
|
|
|
|
|
+ Result.FFlags := FFlags * [nfIgnorableWS];
|
|
FNodeValue := Copy(FNodeValue, 1, offset);
|
|
FNodeValue := Copy(FNodeValue, 1, offset);
|
|
- FParentNode.InsertBefore(Result, FNextSibling);
|
|
|
|
|
|
+ if Assigned(FParentNode) then
|
|
|
|
+ FParentNode.InsertBefore(Result, FNextSibling);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TDOMText.IsElementContentWhitespace: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := nfIgnorableWS in FFlags;
|
|
|
|
+end;
|
|
|
|
|
|
// -------------------------------------------------------
|
|
// -------------------------------------------------------
|
|
// Comment
|
|
// Comment
|
|
@@ -2442,7 +2415,9 @@ begin
|
|
TDOMEntity(Result).FName := FName;
|
|
TDOMEntity(Result).FName := FName;
|
|
TDOMEntity(Result).FSystemID := FSystemID;
|
|
TDOMEntity(Result).FSystemID := FSystemID;
|
|
TDOMEntity(Result).FPublicID := FPublicID;
|
|
TDOMEntity(Result).FPublicID := FPublicID;
|
|
- TDOMEntity(Result).FNotationName := FNotationName;
|
|
|
|
|
|
+ TDOMEntity(Result).FNotationName := FNotationName;
|
|
|
|
+ if deep then
|
|
|
|
+ CloneChildren(Result, aCloneOwner);
|
|
end;
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------
|
|
// -------------------------------------------------------
|
|
@@ -2462,8 +2437,6 @@ end;
|
|
function TDOMEntityReference.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
|
|
function TDOMEntityReference.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
|
|
begin
|
|
begin
|
|
Result := ACloneOwner.CreateEntityReference(FName);
|
|
Result := ACloneOwner.CreateEntityReference(FName);
|
|
- // TODO -cConformance: this is done in CreateEntityReference?
|
|
|
|
- CloneChildren(Result, ACloneOwner);
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------
|
|
// -------------------------------------------------------
|