mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 03:49:30 +02:00
wiki test: open page
git-svn-id: trunk@35749 -
This commit is contained in:
parent
e1b2c61f10
commit
64fc77e75d
@ -96,7 +96,7 @@ type
|
|||||||
CurNode: TDOMElement; // current fpdoc node
|
CurNode: TDOMElement; // current fpdoc node
|
||||||
public
|
public
|
||||||
FPDoc: TXMLDocument;
|
FPDoc: TXMLDocument;
|
||||||
destructor Destroy; override;
|
procedure ClearConversion; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TWiki2FPDocConverter }
|
{ TWiki2FPDocConverter }
|
||||||
@ -122,10 +122,9 @@ implementation
|
|||||||
|
|
||||||
{ TW2FPDocPage }
|
{ TW2FPDocPage }
|
||||||
|
|
||||||
destructor TW2FPDocPage.Destroy;
|
procedure TW2FPDocPage.ClearConversion;
|
||||||
begin
|
begin
|
||||||
FreeAndNil(FPDoc);
|
FreeAndNil(FPDoc);
|
||||||
inherited Destroy;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TWiki2FPDocConverter }
|
{ TWiki2FPDocConverter }
|
||||||
|
@ -40,7 +40,7 @@ type
|
|||||||
public
|
public
|
||||||
XHTML: TXMLDocument;
|
XHTML: TXMLDocument;
|
||||||
Filename: string;
|
Filename: string;
|
||||||
destructor Destroy; override;
|
procedure ClearConversion; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TWiki2XHTMLConverter }
|
{ TWiki2XHTMLConverter }
|
||||||
@ -59,7 +59,7 @@ type
|
|||||||
procedure OnWikiToken(Token: TWPToken); virtual;
|
procedure OnWikiToken(Token: TWPToken); virtual;
|
||||||
function GetImageLink(ImgFilename: string): string; virtual;
|
function GetImageLink(ImgFilename: string): string; virtual;
|
||||||
function FindImage(const ImgFilename: string): string; virtual;
|
function FindImage(const ImgFilename: string): string; virtual;
|
||||||
procedure MarkImageAsUsed(const ImgFilename: string; Page: TW2XHTMLPage);
|
procedure MarkImageAsUsed(const ImgFilename: string; Page: TW2XHTMLPage); virtual;
|
||||||
function GetPageLink(Page: TW2XHTMLPage): string; virtual;
|
function GetPageLink(Page: TW2XHTMLPage): string; virtual;
|
||||||
function InsertLink(const LinkToken: TWPLinkToken): boolean;
|
function InsertLink(const LinkToken: TWPLinkToken): boolean;
|
||||||
procedure InsertText(Token: TWPToken; Txt: string); virtual;
|
procedure InsertText(Token: TWPToken; Txt: string); virtual;
|
||||||
@ -254,7 +254,7 @@ var
|
|||||||
Node: TDOMElement;
|
Node: TDOMElement;
|
||||||
CurCSSFilename: String;
|
CurCSSFilename: String;
|
||||||
begin
|
begin
|
||||||
FreeAndNil(Page.XHTML);
|
Page.ClearConversion;
|
||||||
if Page.WikiPage=nil then exit;
|
if Page.WikiPage=nil then exit;
|
||||||
Page.XHTML:=TXMLDocument.Create;
|
Page.XHTML:=TXMLDocument.Create;
|
||||||
doc:=Page.XHTML;
|
doc:=Page.XHTML;
|
||||||
@ -774,10 +774,12 @@ end;
|
|||||||
|
|
||||||
{ TW2XHTMLPage }
|
{ TW2XHTMLPage }
|
||||||
|
|
||||||
destructor TW2XHTMLPage.Destroy;
|
procedure TW2XHTMLPage.ClearConversion;
|
||||||
begin
|
begin
|
||||||
|
BodyNode:=nil;
|
||||||
|
CurNode:=nil;
|
||||||
|
SectionLevel:=0;
|
||||||
FreeAndNil(XHTML);
|
FreeAndNil(XHTML);
|
||||||
inherited Destroy;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -44,6 +44,7 @@ type
|
|||||||
constructor Create(TheConverter: TWiki2FormatConverter); virtual;
|
constructor Create(TheConverter: TWiki2FormatConverter); virtual;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
procedure ParseWikiDoc(KeepWikiDoc: boolean);
|
procedure ParseWikiDoc(KeepWikiDoc: boolean);
|
||||||
|
procedure ClearConversion; virtual;
|
||||||
end;
|
end;
|
||||||
TW2FormatPageClass = class of TW2FormatPage;
|
TW2FormatPageClass = class of TW2FormatPage;
|
||||||
|
|
||||||
@ -61,7 +62,8 @@ type
|
|||||||
FImagesDir: string;
|
FImagesDir: string;
|
||||||
FOutputDir: string;
|
FOutputDir: string;
|
||||||
fPages: TFPList; // list of TW2FormatPage
|
fPages: TFPList; // list of TW2FormatPage
|
||||||
fPageTree: TAvgLvlTree; // TW2FormatPage sorted for filename
|
fPagesSortFilename: TAvgLvlTree; // TW2FormatPage sorted for WikiFilename
|
||||||
|
fPagesSortDocumentName: TAvgLvlTree; // TW2FormatPage sorted for WikiDocumentName
|
||||||
FPageClass: TW2FormatPageClass;
|
FPageClass: TW2FormatPageClass;
|
||||||
function GetPages(Index: integer): TW2FormatPage;
|
function GetPages(Index: integer): TW2FormatPage;
|
||||||
procedure SetOutputDir(AValue: string);
|
procedure SetOutputDir(AValue: string);
|
||||||
@ -71,6 +73,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
procedure Clear; virtual;
|
procedure Clear; virtual;
|
||||||
function GetPageWithFilename(Filename: string): TW2FormatPage; virtual;
|
function GetPageWithFilename(Filename: string): TW2FormatPage; virtual;
|
||||||
|
function GetPageWithDocumentName(DocumentName: string): TW2FormatPage; virtual;
|
||||||
function AddWikiPage(Filename: string; ParseNow: boolean = true): TW2FormatPage;
|
function AddWikiPage(Filename: string; ParseNow: boolean = true): TW2FormatPage;
|
||||||
procedure Convert; virtual;
|
procedure Convert; virtual;
|
||||||
procedure Log(Msg: string);
|
procedure Log(Msg: string);
|
||||||
@ -97,6 +100,8 @@ function WikiPageHasLanguage(const Page, Languages: string): boolean;
|
|||||||
|
|
||||||
function ComparePagesWithFilenames(Page1, Page2: Pointer): integer;
|
function ComparePagesWithFilenames(Page1, Page2: Pointer): integer;
|
||||||
function CompareFilenameWithPage(Filename, Page: Pointer): integer;
|
function CompareFilenameWithPage(Filename, Page: Pointer): integer;
|
||||||
|
function ComparePagesWithDocumentNames(Page1, Page2: Pointer): integer;
|
||||||
|
function CompareDocumentNameWithPage(DocumentName, Page: Pointer): integer;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -135,7 +140,8 @@ constructor TWiki2FormatConverter.Create;
|
|||||||
begin
|
begin
|
||||||
FPageClass:=TW2FormatPage;
|
FPageClass:=TW2FormatPage;
|
||||||
fPages:=TFPList.Create;
|
fPages:=TFPList.Create;
|
||||||
fPageTree:=TAvgLvlTree.Create(@ComparePagesWithFilenames);
|
fPagesSortFilename:=TAvgLvlTree.Create(@ComparePagesWithFilenames);
|
||||||
|
fPagesSortDocumentName:=TAvgLvlTree.Create(@ComparePagesWithDocumentNames);
|
||||||
FTitle:='FPC/Lazarus Wiki (offline, generated '+DatetoStr(Now)+')';
|
FTitle:='FPC/Lazarus Wiki (offline, generated '+DatetoStr(Now)+')';
|
||||||
FImagesDir:='images';
|
FImagesDir:='images';
|
||||||
FNoWarnBaseURLs:=TStringToStringTree.Create(true);
|
FNoWarnBaseURLs:=TStringToStringTree.Create(true);
|
||||||
@ -145,7 +151,8 @@ destructor TWiki2FormatConverter.Destroy;
|
|||||||
begin
|
begin
|
||||||
Clear;
|
Clear;
|
||||||
FreeAndNil(FNoWarnBaseURLs);
|
FreeAndNil(FNoWarnBaseURLs);
|
||||||
FreeAndNil(fPageTree);
|
FreeAndNil(fPagesSortFilename);
|
||||||
|
FreeAndNil(fPagesSortDocumentName);
|
||||||
FreeAndNil(fPages);
|
FreeAndNil(fPages);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
@ -154,7 +161,8 @@ procedure TWiki2FormatConverter.Clear;
|
|||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
fPageTree.Clear;
|
fPagesSortFilename.Clear;
|
||||||
|
fPagesSortDocumentName.Clear;
|
||||||
for i:=0 to Count-1 do
|
for i:=0 to Count-1 do
|
||||||
Pages[i].Free;
|
Pages[i].Free;
|
||||||
fPages.Clear;
|
fPages.Clear;
|
||||||
@ -167,7 +175,20 @@ var
|
|||||||
Node: TAvgLvlTreeNode;
|
Node: TAvgLvlTreeNode;
|
||||||
begin
|
begin
|
||||||
if Filename='' then exit(nil);
|
if Filename='' then exit(nil);
|
||||||
Node:=fPageTree.FindKey(Pointer(Filename),@CompareFilenameWithPage);
|
Node:=fPagesSortFilename.FindKey(Pointer(Filename),@CompareFilenameWithPage);
|
||||||
|
if Node<>nil then
|
||||||
|
Result:=TW2FormatPage(Node.Data)
|
||||||
|
else
|
||||||
|
Result:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TWiki2FormatConverter.GetPageWithDocumentName(DocumentName: string
|
||||||
|
): TW2FormatPage;
|
||||||
|
var
|
||||||
|
Node: TAvgLvlTreeNode;
|
||||||
|
begin
|
||||||
|
if DocumentName='' then exit(nil);
|
||||||
|
Node:=fPagesSortDocumentName.FindKey(Pointer(DocumentName),@CompareDocumentNameWithPage);
|
||||||
if Node<>nil then
|
if Node<>nil then
|
||||||
Result:=TW2FormatPage(Node.Data)
|
Result:=TW2FormatPage(Node.Data)
|
||||||
else
|
else
|
||||||
@ -183,7 +204,8 @@ begin
|
|||||||
Result.WikiFilename:=Filename;
|
Result.WikiFilename:=Filename;
|
||||||
Result.WikiDocumentName:=WikiFilenameToPage(Filename);
|
Result.WikiDocumentName:=WikiFilenameToPage(Filename);
|
||||||
fPages.Add(Result);
|
fPages.Add(Result);
|
||||||
fPageTree.Add(Result);
|
fPagesSortFilename.Add(Result);
|
||||||
|
fPagesSortDocumentName.Add(Result);
|
||||||
end;
|
end;
|
||||||
if ParseNow then
|
if ParseNow then
|
||||||
Result.ParseWikiDoc(false);
|
Result.ParseWikiDoc(false);
|
||||||
@ -227,6 +249,7 @@ end;
|
|||||||
|
|
||||||
destructor TW2FormatPage.Destroy;
|
destructor TW2FormatPage.Destroy;
|
||||||
begin
|
begin
|
||||||
|
ClearConversion;
|
||||||
FreeAndNil(WikiDoc);
|
FreeAndNil(WikiDoc);
|
||||||
FreeAndNil(WikiPage);
|
FreeAndNil(WikiPage);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
@ -264,6 +287,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TW2FormatPage.ClearConversion;
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
function WikiPageToFilename(Page: string; IsInternalLink, AppendCaseID: boolean): string;
|
function WikiPageToFilename(Page: string; IsInternalLink, AppendCaseID: boolean): string;
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
@ -472,5 +500,20 @@ begin
|
|||||||
Result:=CompareFilenames(AnsiString(Filename),p.WikiFilename);
|
Result:=CompareFilenames(AnsiString(Filename),p.WikiFilename);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ComparePagesWithDocumentNames(Page1, Page2: Pointer): integer;
|
||||||
|
var
|
||||||
|
p1: TW2FormatPage absolute Page1;
|
||||||
|
p2: TW2FormatPage absolute Page2;
|
||||||
|
begin
|
||||||
|
Result:=CompareStr(p1.WikiDocumentName,p2.WikiDocumentName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CompareDocumentNameWithPage(DocumentName, Page: Pointer): integer;
|
||||||
|
var
|
||||||
|
p: TW2FormatPage absolute Page;
|
||||||
|
begin
|
||||||
|
Result:=CompareStr(AnsiString(DocumentName),p.WikiDocumentName);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ type
|
|||||||
procedure ExtractAllTexts;
|
procedure ExtractAllTexts;
|
||||||
procedure Search(Query: TWikiHelpQuery; Scoring: TWHScoring;
|
procedure Search(Query: TWikiHelpQuery; Scoring: TWHScoring;
|
||||||
var FoundPages: TFPList);
|
var FoundPages: TFPList);
|
||||||
|
procedure SavePageAsHTMLToStream(Page: TW2HelpPage; aStream: TStream);
|
||||||
property Help: TWikiHelp read FHelp;
|
property Help: TWikiHelp read FHelp;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -236,6 +237,9 @@ type
|
|||||||
property Scoring: TWHScoring read FScoring;
|
property Scoring: TWHScoring read FScoring;
|
||||||
property MaxResults: integer read FMaxResults write SetMaxResults;
|
property MaxResults: integer read FMaxResults write SetMaxResults;
|
||||||
property ResultsHTML: string read FResultsHTML;
|
property ResultsHTML: string read FResultsHTML;
|
||||||
|
|
||||||
|
// get page
|
||||||
|
procedure SavePageToStream(DocumentName: string; aStream: TStream);
|
||||||
public
|
public
|
||||||
property XMLDirectory: string read FXMLDirectory write SetXMLDirectory; // directory where the wiki xml files are
|
property XMLDirectory: string read FXMLDirectory write SetXMLDirectory; // directory where the wiki xml files are
|
||||||
property ImagesDirectory: string read GetImagesDirectory write SetImagesDirectory; // directory where the wiki image files are
|
property ImagesDirectory: string read GetImagesDirectory write SetImagesDirectory; // directory where the wiki image files are
|
||||||
@ -1094,6 +1098,14 @@ begin
|
|||||||
FoundPages.Sort(@CompareW2HPageForScore);
|
FoundPages.Sort(@CompareW2HPageForScore);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWiki2HelpConverter.SavePageAsHTMLToStream(Page: TW2HelpPage;
|
||||||
|
aStream: TStream);
|
||||||
|
begin
|
||||||
|
ConvertPage(Page);
|
||||||
|
SavePageToStream(Page,aStream);
|
||||||
|
Page.ClearConversion;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TWiki2HelpConverter.LoadPages;
|
procedure TWiki2HelpConverter.LoadPages;
|
||||||
begin
|
begin
|
||||||
Help.EnterCritSect;
|
Help.EnterCritSect;
|
||||||
@ -1507,5 +1519,15 @@ begin
|
|||||||
DoSearch;
|
DoSearch;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWikiHelp.SavePageToStream(DocumentName: string; aStream: TStream);
|
||||||
|
var
|
||||||
|
Page: TW2HelpPage;
|
||||||
|
begin
|
||||||
|
Page:=TW2HelpPage(Converter.GetPageWithDocumentName(DocumentName));
|
||||||
|
if Page=nil then
|
||||||
|
raise Exception.Create('document "'+DocumentName+'" not found in wiki');
|
||||||
|
Converter.SavePageAsHTMLToStream(Page,aStream);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ unit WikiSearchMain;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, FileUtil, LazLogger, LazUTF8, LazFileUtils, IpHtml,
|
Classes, SysUtils, FileUtil, LazLogger, LazUTF8, LazFileUtils, laz2_DOM,
|
||||||
Ipfilebroker, IpMsg, CodeToolManager, CodeCache, Forms, Controls, Graphics,
|
IpHtml, Ipfilebroker, IpMsg, CodeToolManager, CodeCache, Forms, Controls,
|
||||||
Dialogs, StdCtrls, ExtCtrls, WikiHelpManager;
|
Graphics, Dialogs, StdCtrls, ExtCtrls, WikiHelpManager;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -60,7 +60,8 @@ type
|
|||||||
procedure SearchParamsChanged;
|
procedure SearchParamsChanged;
|
||||||
procedure SetIdleConnected(AValue: boolean);
|
procedure SetIdleConnected(AValue: boolean);
|
||||||
procedure UpdateProgress;
|
procedure UpdateProgress;
|
||||||
procedure LoadHTML(Target: TIpHtmlPanel; HTML: string);
|
procedure LoadHTML(Target: TIpHtmlPanel; HTML: string); overload;
|
||||||
|
procedure LoadHTML(Target: TIpHtmlPanel; aStream: TStream); overload;
|
||||||
public
|
public
|
||||||
property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
|
property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
|
||||||
end;
|
end;
|
||||||
@ -137,7 +138,7 @@ end;
|
|||||||
function TWikiSearchDemoForm.DataProviderCanHandle(Sender: TObject;
|
function TWikiSearchDemoForm.DataProviderCanHandle(Sender: TObject;
|
||||||
const URL: string): Boolean;
|
const URL: string): Boolean;
|
||||||
begin
|
begin
|
||||||
debugln(['TWikiSearchDemoForm.DataProviderCanHandle URL=',URL]);
|
//debugln(['TWikiSearchDemoForm.DataProviderCanHandle URL=',URL]);
|
||||||
Result:=false;
|
Result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -204,6 +205,8 @@ var
|
|||||||
HotNode: TIpHtmlNode;
|
HotNode: TIpHtmlNode;
|
||||||
HRef: String;
|
HRef: String;
|
||||||
Panel: TIpHtmlPanel;
|
Panel: TIpHtmlPanel;
|
||||||
|
ms: TMemoryStream;
|
||||||
|
Src: String;
|
||||||
begin
|
begin
|
||||||
Panel:=Sender as TIpHtmlPanel;
|
Panel:=Sender as TIpHtmlPanel;
|
||||||
HotNode:=Panel.HotNode;
|
HotNode:=Panel.HotNode;
|
||||||
@ -215,6 +218,22 @@ begin
|
|||||||
//Target := TIpHtmlNodeAREA(HotNode).Target;
|
//Target := TIpHtmlNodeAREA(HotNode).Target;
|
||||||
end;
|
end;
|
||||||
debugln(['TWikiSearchDemoForm.ResultsIpHtmlPanelHotClick href=',href]);
|
debugln(['TWikiSearchDemoForm.ResultsIpHtmlPanelHotClick href=',href]);
|
||||||
|
// open page in PageIpHtmlPanel
|
||||||
|
ms:=TMemoryStream.Create;
|
||||||
|
try
|
||||||
|
try
|
||||||
|
WikiHelp.SavePageToStream(href,ms);
|
||||||
|
ms.Position:=0;
|
||||||
|
LoadHTML(PageIpHtmlPanel,ms);
|
||||||
|
except
|
||||||
|
on E: Exception do begin
|
||||||
|
Src:='<html><body>Error: '+EncodeLesserAndGreaterThan(E.Message)+'</body></html>';
|
||||||
|
LoadHTML(PageIpHtmlPanel,Src);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
ms.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TWikiSearchDemoForm.SearchEditChange(Sender: TObject);
|
procedure TWikiSearchDemoForm.SearchEditChange(Sender: TObject);
|
||||||
@ -279,7 +298,6 @@ end;
|
|||||||
procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; HTML: string);
|
procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; HTML: string);
|
||||||
var
|
var
|
||||||
ms: TMemoryStream;
|
ms: TMemoryStream;
|
||||||
NewHTML: TIpHtml;
|
|
||||||
begin
|
begin
|
||||||
if HTML='' then
|
if HTML='' then
|
||||||
HTML:='<html><body></body></html>';
|
HTML:='<html><body></body></html>';
|
||||||
@ -288,10 +306,7 @@ begin
|
|||||||
try
|
try
|
||||||
ms.Write(HTML[1],length(HTML));
|
ms.Write(HTML[1],length(HTML));
|
||||||
ms.Position:=0;
|
ms.Position:=0;
|
||||||
NewHTML:=TIpHtml.Create; // Beware: Will be freed automatically by IpHtmlPanel
|
LoadHTML(Target,ms);
|
||||||
//NewHTML.OnGetImageX:=@HTMLGetImageX;
|
|
||||||
Target.SetHtml(NewHTML);
|
|
||||||
NewHTML.LoadFromStream(ms);
|
|
||||||
except
|
except
|
||||||
on E: Exception do begin
|
on E: Exception do begin
|
||||||
debugln(['TWikiSearchDemoForm.LoadHTML ',E.Message]);
|
debugln(['TWikiSearchDemoForm.LoadHTML ',E.Message]);
|
||||||
@ -302,5 +317,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; aStream: TStream);
|
||||||
|
var
|
||||||
|
NewHTML: TIpHtml;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
NewHTML:=TIpHtml.Create; // Beware: Will be freed automatically by IpHtmlPanel
|
||||||
|
//NewHTML.OnGetImageX:=@HTMLGetImageX;
|
||||||
|
Target.SetHtml(NewHTML);
|
||||||
|
NewHTML.LoadFromStream(aStream);
|
||||||
|
except
|
||||||
|
on E: Exception do begin
|
||||||
|
debugln(['TWikiSearchDemoForm.LoadHTML ',E.Message]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user