unit TMGHTML;
(*
NOTES: By Kevin Toppenberg, MD 5/27/09
Code heavily modified from original code found at www.supermemo.com/source/
Their notes (below) indicate that the code may be freely used.
This unit encapsulates SHDocVw.dll and MSHTML.dll functionality by subclassing
THtmlEditorBrowser object as THtmlEditor object
THtmlEditor was designed for easy use of HTML display and editing capacity in
SuperMemo 2002 for Windows developed by SuperMemo R&D in Fall 2001.
SuperMemo 2002 implements HTML-based incremental reading in which extensive HTML
support is vital.
Pieces of this units can be used by anyone in other Delphi applications that make
use of HTML WYSIWYG interfaces made open by Microsoft.
*)
interface
uses SysUtils, WinTypes, Dialogs, StdCtrls, Menus,
EmbeddedED,
ActiveX, MSHTMLEvents, SHDocVw, {MSHTML,} MSHTML_EWB,
AppEvnts,
IeConst,Messages,Classes,Forms,Graphics;
const
CGID_MSHTML:TGUID='{DE4BA900-59CA-11CF-9592-444553540000}';
IID_IOleCommandTarget:TGUID='{B722BCCB-4E68-101B-A2BC-00AA00404770}';
CGID_WebBrowser:TGUID='{ED016940-BD5B-11cf-BA4E-00C04FD70816}';
FontScale=3;
type
TSetFontMode = (sfAll,sfSize,sfColor,sfName,sfStyle,sfCharset);
TRGBColor = record
R : byte;
G : byte;
B : byte;
end; {record}
TMGColor = record
case boolean of
True: (Color : TColor);
False: (RGBColor : TRGBColor);
end; {record}
type
// THtmlObj=class(TWebBrowser)
THtmlObj=class(TEmbeddedED)
private
FEditable: boolean;
Modified: boolean;
DocEvents: TMSHTMLHTMLDocumentEvents; //elh
WinEvents: TMSHTMLHTMLWindowEvents2;
CtrlReturnToBeProcessed: boolean;
CtrlToBeProcessed : boolean;
ShiftToBeProcessed : boolean;
ColorDialog: TColorDialog;
FOrigAppOnMessage : TMessageEvent;
FCustKeyboardHandlerOn: boolean;
FActive : boolean;
FApplication : TApplication;
procedure WaitLoad(peek:boolean);
function GetEditableState : boolean;
procedure SetEditableState (EditOn : boolean);
procedure SetBackgroundColor(Color:TColor);
function GetBackgroundColor : TColor;
procedure SetTextBackgroundColor(Color:TColor);
function GetTextBackgroundColor : TColor;
procedure SetTextForegroundColor(Color:TColor);
function GetTextForegroundColor : TColor;
function GetFontSize : integer;
procedure SetFontSize (Size : integer);
function GetFontName : string;
procedure SetFontName (Name : string);
procedure SetActive (Active : boolean);
function GetHTMLText:string;
procedure SetHTMLText(HTML:String);
function GetText:string;
procedure SetText(HTML:string);
function GetSelText:string;
procedure SetSelText (HTMLText : string);
procedure DefineDocEvents; //elh
procedure DefineWinEvents;
procedure OnDocFocusOut(Sender:TObject); //elh
procedure SetDefaultFont;
function ColorToMSHTMLStr(color : TColor) : string;
function MSHTMLStrToColor(MSHTMLColor : string) : TColor;
//Events ------------------
procedure NavigateComplete2(Sender: TObject;const pDisp: IDispatch; var URL: OleVariant);
procedure LocalMessageHandler(var Msg: TMsg; var Handled: Boolean);
procedure CompleteLoading;
procedure ProcessLoadMessages;
function SpecialCommand(Cmd : Cardinal; PromptUser : boolean;
editModeOnly : boolean; bTriEditCommandGroup : boolean;
InputArgs : OleVariant) : HRESULT;
function HrExecCommand(ucmdID: cardinal;
const pVarIn: OleVariant; var pVarOut: OleVariant; bPromptUser,
bTriEditCmdGroup: boolean): HResult;
procedure ReassignKeyboardHandler(TurnOn : boolean);
{end private}
public
TheDoc: IHTMLDocument2; //MSHTML HTML Document 2 interface
// HTMLEvents: HTMLWindowsEvents2;
TheWind: IHTMLWindow2;
DocCmd,WebCmd: IOleCommandTarget; //MSHTML IOLECommandTarget interface
PopupMenu: TPopupMenu;
DefaultFontSize : Integer;
DefaultFontName : string;
constructor Create(Owner:TComponent; Application : TApplication);
destructor Destroy; override;
//Properties ---
property Editable : boolean read GetEditableState write SetEditableState;
property BackgroundColor : TColor read GetBackgroundColor write SetBackgroundColor;
property TextBackgroundColor : TColor read GetTextBackgroundColor write SetTextBackgroundColor;
property TextForegroundColor : TColor read GetTextForegroundColor write SetTextForegroundColor;
property FontSize : integer read GetFontSize write SetFontSize;
property FontName : string read GetFontName write SetFontName;
property HTMLText:string read GetHTMLText write SetHTMLText;
property Text:string read GetText write SetText;
property Active : boolean read FActive write SetActive;
property SelText : string read GetSelText write SetSelText;
//Methods -------
function GetTextLen : integer;
procedure Clear;
procedure LoadFile(FileName:string);
procedure ToggleBullet;
procedure ToggleItalic;
procedure ToggleBold;
procedure ToggleNumbering;
procedure ToggleUnderline;
procedure ToggleSubscript;
procedure ToggleSuperscript;
procedure Indent;
procedure Outdent;
procedure AlignLeft;
procedure AlignRight;
procedure AlignCenter;
procedure FontDialog;
procedure TextForeColorDialog;
procedure TextBackColorDialog;
procedure SetSelection(Start,Length:integer);
function GetTextRange:IHtmlTxtRange;
function SelStart:integer;
function SelEnd:integer;
function SelLength:integer;
procedure ClearSelection;
procedure ReplaceSelection(HTML:string);
{end public}
end;
type THtmlEditor=class(THtmlObj);
implementation
uses
WinProcs,Controls,Variants,Clipbrd, StrUtils;
const
MaxTextLength = 100;
nl = #13#10;
procedure EError(EText : string; E : Exception);
begin
MessageDlg(EText,mtError,[mbOK],0);
end;
constructor THtmlObj.Create(Owner:TComponent; Application : TApplication);
begin
inherited Create(Owner);
TheDoc:=nil;
DocCmd:=nil;
WebCmd:=nil;
ColorDialog := nil;
FApplication := Application;
FOrigAppOnMessage := Application.OnMessage;
FEditable := false;
DefaultFontSize := 10;
OnBlur := OnDocFocusOut;
DefaultFontName := 'Times New Roman';
FCustKeyboardHandlerOn := false;
OnNavigateComplete2 := NavigateComplete2;
end;
destructor THtmlObj.Destroy;
begin
SetActive(false); // ReassignKeyboardHandler(false);
ColorDialog.Free;
inherited Destroy;
end;
procedure THtmlObj.LoadFile(FileName:string);
var OldWidth,OldHeight:integer;
begin
try
self.Cursor := crHourGlass;
OldHeight:=Height;
OldWidth:=Width;
Navigate(FileName);
Width:=OldWidth; {due to a bug that sizes down HTML components on start}{Oct 15, 2001}
Height:=OldHeight;
TheDoc:=nil;
if DocCmd<>nil then begin
DocCmd._Release;
DocCmd:=nil;
end;
WaitLoad(true); //kt
self.Cursor := crDefault; //kt
except
on E:Exception do begin
EError('Cannot load '+Filename,E);
end;
end;
end;
procedure THtmlObj.WaitLoad(peek:boolean);
begin
try
TheDoc:=Document as IHTMLDocument2;
while TheDoc=nil do begin
if peek then ProcessLoadMessages
else exit;
TheDoc:=Document as IHTMLDocument2;
end;
repeat
ControlInterface.QueryInterface(IID_IOleCommandTarget,WebCmd);
until WebCmd<>nil;
repeat
TheDoc.QueryInterface(IOleCommandTarget,DocCmd);
until DocCmd<>nil;
repeat
TheWind:=TheDoc.parentWindow;
until TheWind<>nil;
while (TheDoc=nil)or((theDoc.ReadyState<>'complete')and(theDoc.ReadyState<>'interactive')) do begin
{remove messages that should not be processed while the element is loading}
{TheDoc can become nil when switching applications!}
if TheDoc=nil then
MessageBeep(0); {this beep is sounded while page is loading while control is no longer in forefront}
if peek then
ProcessLoadMessages
else
exit;
end;
except
on E:Exception do EError('Error loading the document',E);
end;
end;
procedure THtmlObj.ProcessLoadMessages;
var msg:TMsg;
MessageQueue:array of TMsg;
m:integer;
begin
while PeekMessage(msg,0,wm_KeyFirst,wm_KeyLast,pm_Remove) do; {remove keyboard input first}
while PeekMessage(msg,0,wm_MouseFirst,wm_MouseLast,pm_Remove) do; {remove mouse input}
while PeekMessage(msg,0,wm_Close,wm_Close,pm_Remove) do; {disallow closing the application}
while PeekMessage(msg,0,wm_ActivateApp,wm_ActivateApp,pm_Remove) do; {disallow activating the application}
//ktwhile PeekMessage(msg,0,wm_User,cm_LastUserMessage,pm_Remove) do begin
while PeekMessage(msg,0,wm_User,wm_User+$200,pm_Remove) do begin
SetLength(MessageQueue,length(MessageQueue)+1);
MessageQueue[length(MessageQueue)-1]:=msg;
end;
forms.Application.ProcessMessages; {process messages needed to complete navigation}
for m:=1 to length(MessageQueue) do begin
msg:=MessageQueue[m-1];
PostMessage(msg.hwnd,msg.message,msg.WParam,msg.lParam);
end;
end;
function THtmlObj.SpecialCommand(Cmd:Cardinal;PromptUser:boolean;
editModeOnly:boolean;bTriEditCommandGroup:boolean;
InputArgs:OleVariant):HRESULT;
begin
Result:=HrExecCommand(Cmd,null,InputArgs,promptUser,bTriEditCommandGroup);
end;
function THtmlObj.HrExecCommand(ucmdID: cardinal; const pVarIn: OleVariant;
var pVarOut: OleVariant; bPromptUser,
bTriEditCmdGroup: boolean): HResult;
var dwCmdOpt:DWORD;
begin
result := S_OK;
if DocCmd = nil then Exit;
if (bPromptUser) then dwCmdOpt := MSOCMDEXECOPT_PROMPTUSER
else dwCmdOpt := MSOCMDEXECOPT_DONTPROMPTUSER;
if (bTriEditCmdGroup) then
result := DocCmd.Exec(@GUID_TriEditCommandGroup,ucmdID,dwCmdOpt,pVarIn,pVarOut)
else
result := DocCmd.Exec(@CMDSETID_Forms3,ucmdID,dwCmdOpt,pVarIn,pVarOut);
end;
procedure THtmlObj.SetDefaultFont;
begin
if DefaultFontName <> '' then SetFontName(DefaultFontName);
if DefaultFontSize <> 0 then SetFontSize(DefaultFontSize);
end;
function THtmlObj.GetEditableState : boolean;
var mode : string;
begin
mode := TheDoc.designMode;
result := (mode = 'On');
end;
procedure THtmlObj.SetEditableState(EditOn : boolean);
var LastMode : string;
count : integer;
begin
LastMode := 'Inherit';
try
count := 0;
repeat
inc (count);
if TheDoc = nil then begin
FApplication.ProcessMessages;
Sleep (100);
continue;
end else if TheDoc.body = nil then begin
FApplication.ProcessMessages;
Sleep (100);
continue;
end;
if EditOn then begin
TheDoc.body.setAttribute('contentEditable','true',0);
TheDoc.designMode := 'On'; //kt
FEditable:=true;
//SetFocus;
end else begin
TheDoc.body.setAttribute('contentEditable','false',0);
TheDoc.designMode := 'Off'; //kt
FEditable:=false;
end;
LastMode := TheDoc.designMode;
until (LastMode <> 'Inherit') or (count > 20);
except
on E:Exception do EError('Error switching into HTML editing state',E);
end;
end;
procedure THtmlObj.ToggleBullet;
begin
if TheDoc=nil then exit;
//SpecialCommand(IDM_UnORDERLIST,false,true,false,Null);
TheDoc.execCommand('InsertUnorderedList',false,null);
Modified:=true;
end;
procedure THtmlObj.ToggleItalic;
begin
if TheDoc=nil then exit;
//SpecialCommand(IDM_UnORDERLIST,false,true,false,Null);
TheDoc.execCommand('Italic',false,null);
Modified:=true;
end;
procedure THtmlObj.ToggleBold;
begin
if TheDoc=nil then exit;
TheDoc.execCommand('Bold',false,null);
Modified:=true;
end;
procedure THtmlObj.ToggleNumbering;
begin
if TheDoc=nil then exit;
TheDoc.execCommand('InsertOrderedList',false,null);
// SpecialCommand(IDM_ORDERLIST,false,true,false,Null);
Modified:=true;
end;
procedure THtmlObj.ToggleUnderline;
begin
if TheDoc=nil then exit;
TheDoc.execCommand('Underline',false,null);
Modified:=true;
end;
procedure THtmlObj.ToggleSubscript;
begin
if TheDoc=nil then exit;
TheDoc.execCommand('Subscript',False,0);
Modified:=true;
end;
procedure THtmlObj.ToggleSuperscript;
begin
if TheDoc=nil then exit;
TheDoc.execCommand('Superscript',False,0);
Modified:=true;
end;
procedure THtmlObj.Indent;
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('Indent',false,0);
Modified:=true;
end;
procedure THtmlObj.Outdent;
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('Outdent',false,0);
Modified:=true;
end;
procedure THtmlObj.AlignLeft;
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('JustifyLeft',false,0);
Modified:=true;
end;
procedure THtmlObj.AlignRight;
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('JustifyRight',false,0);
Modified:=true;
end;
procedure THtmlObj.AlignCenter;
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('JustifyCenter',false,0);
Modified:=true;
end;
procedure THtmlObj.SetBackgroundColor(Color:TColor);
begin
if TheDoc=nil then exit;
WaitLoad(true); //kt
if TheDoc.body=nil then exit;
TheDoc.body.style.backgroundColor := ColorToMSHTMLStr(Color);
end;
function THtmlObj.GetBackgroundColor : TColor;
begin
Result := clBlack; //default;
if TheDoc=nil then exit;
if TheDoc.body=nil then exit;
Result := MSHTMLStrToColor(TheDoc.body.style.backgroundColor);
end;
procedure THtmlObj.TextForeColorDialog;
begin
if ColorDialog = nil then begin
ColorDialog := TColorDialog.Create(self);
end;
if ColorDialog.Execute then begin
SetTextForegroundColor(ColorDialog.Color);
end;
Modified:=true;
end;
procedure THtmlObj.TextBackColorDialog;
begin
if ColorDialog = nil then begin
ColorDialog := TColorDialog.Create(self);
end;
if ColorDialog.Execute then begin
SetTextBackgroundColor(ColorDialog.Color);
end;
Modified:=true;
end;
procedure THtmlObj.SetTextBackgroundColor(Color:TColor);
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('BackColor',false,Color);
Modified:=true;
end;
function THtmlObj.GetTextBackgroundColor:TColor;
var Background : OleVariant;
vt : TVarType;
begin
Result:=clWindow;
try
if TheDoc=nil then exit;
Background:=TheDoc.queryCommandValue('BackColor');
vt:=varType(Background);
if vt<>varNull then Result:=Background;
except
on E:Exception do EError('Error retrieving background color',E);
end;
end;
procedure THtmlObj.SetTextForegroundColor(Color:TColor);
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('ForeColor',false,Color);
Modified:=true;
end;
function THtmlObj.GetTextForegroundColor:TColor;
var Background : OleVariant;
vt : TVarType;
begin
Result:=clWindow;
try
if TheDoc=nil then exit;
Background:=TheDoc.queryCommandValue('ForeColor');
vt:=varType(Background);
if vt<>varNull then Result:=Background;
except
on E:Exception do EError('Error retrieving foreground color',E);
end;
end;
procedure THtmlObj.FontDialog;
begin
SpecialCommand(IDM_FONT,True,True,False,Null);
Modified:=true;
end;
function THtmlObj.GetFontSize : integer;
var FontSize : OleVariant;
vt : TVarType;
begin
FontSize:=TheDoc.queryCommandValue('FontSize');
vt:=varType(FontSize);
if vt<>varNull then Result := FontSize*FontScale
else Result :=12*FontScale; //kt
end;
procedure THtmlObj.SetFontSize (Size : integer);
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('FontSize', false, Size div FontScale);
end;
function THtmlObj.GetFontName : string;
var FontName :OleVariant;
vt : TVarType;
begin
if TheDoc=nil then exit;
FontName:=TheDoc.queryCommandValue('FontName');
vt:=varType(FontName);
if vt<>varNull then Result := FontName
else Result :='Times New Roman'; //kt
end;
procedure THtmlObj.SetFontName (Name : string);
begin
if TheDoc=nil then exit;
TheDoc.ExecCommand('FontName', false, Name);
end;
procedure THtmlObj.SetActive (Active : boolean);
//NOTE: This object grabs the OnMessage for the entire application, so that
// it can intercept the right-click. As a result, the object needs a
// way that it can turn off this feature when it is covered up by other
// windows application subwindows etc. This function provides this.
begin
FActive := Active;
ReassignKeyboardHandler(FActive);
end;
procedure THtmlObj.NavigateComplete2(Sender: TObject;const pDisp: IDispatch; var URL: OleVariant);
begin
CompleteLoading;
end;
procedure THtmlObj.CompleteLoading;
begin
Waitload(false); {used only to set up interface variables}
SetActive(true); // ReassignKeyboardHandler(true);
//DefineDocEvents; //elh
end;
procedure THtmlObj.DefineDocEvents;
//NOTE: When this function is called, keyboard strokes fire this event, but then
// the characters never show up in the editor window as having been typed.
begin
// if DocEvents<>nil then Events.Free;
// DocEvents := TMSHTMLHTMLDocumentEvents.Create(Self);
// DocEvents.Connect(IUnknown(Document));
// DocEvents.OnFocusOut:=OnDocFocusOut;
end;
procedure THtmlObj.DefineWinEvents;
//NOTE: When this function is called, keyboard strokes fire this event, but then
// the characters never show up in the editor window as having been typed.
begin
//if DocEvents<>nil then Events.Free;
//WinEvents := TMSHTMLHTMLWindowEvents2.Create(Self);
//DocEvents.Connect(IUnknown(Document));
//DocEvents.OnFocusOut:=OnDocFocusOut;
end;
procedure THtmlObj.OnDocFocusOut(Sender:TObject);
begin
messagedlg('This is the new one', mtWarning,mbOKCancel,0);
end;
procedure THtmlObj.ReassignKeyboardHandler(TurnOn : boolean);
{assign HTML keyboard handler to HTML component; restore standard if TurnOn=false}
begin
if TurnOn then begin
FApplication.OnMessage := LocalMessageHandler;
FCustKeyboardHandlerOn := true;
end else begin
FApplication.OnMessage := FOrigAppOnMessage;
FCustKeyboardHandlerOn := false;
end;
end;
procedure THtmlObj.LocalMessageHandler(var Msg: TMsg; var Handled: Boolean);
var
Cursor : TPoint;
i : Integer;
begin
Handled:=false; //default to not handled
exit;
if not FCustKeyboardHandlerOn then exit;
if not ((Msg.Message=WM_KEYDOWN) or
(Msg.Message=WM_KEYUP) or
(Msg.Message=WM_RBUTTONUP) ) then exit; //Speedy exit of non-handled messages
case Msg.Message of
WM_RBUTTONUP : begin
Cursor := ScreenToClient(Msg.pt);
//Ignore message if mouse not over this HTML control
if (Cursor.X<0) or (Cursor.X>Width) or
(Cursor.Y<0) or (Cursor.Y>Height) then exit;
if CtrlToBeProcessed then begin
CtrlToBeProcessed := false;
exit; //Ctrl-right click is ignored
end;
if assigned(PopupMenu) then PopupMenu.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
Handled:=true;
exit;
end;
WM_KEYDOWN : begin
case Msg.WParam of
VK_CONTROL : begin
CtrlToBeProcessed:=true;
Handled:=true;
exit;
end;
VK_SHIFT : begin
ShiftToBeProcessed:=true;
Handled:=true;
exit;
end;
VK_TAB : begin
//kt if not FEditable then exit;
if ShiftToBeProcessed then begin
for i := 0 to 5 do begin
PostMessage(Msg.hwnd, WM_KEYDOWN, VK_LEFT, 0);
end;
end else begin
for i := 0 to 5 do begin
PostMessage(Msg.hwnd, WM_KEYDOWN, VK_SPACE, 0);
end;
end;
Handled:=true;
end;
VK_RETURN : if CtrlReturnToBeProcessed then begin
Handled:=false;
CtrlReturnToBeProcessed := false;
end else if CtrlToBeProcessed then begin
Handled:=true;
CtrlToBeProcessed := False;
CtrlReturnToBeProcessed := true;
//PostMessage(Msg.hwnd, WM_KEYUP, VK_CONTROL, 0);
end else if ShiftToBeProcessed=false then begin
//kt if not FEditable then exit;
keybd_event(VK_SHIFT,0,0,0);
keybd_event(VK_RETURN,0,0,0);
keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0);
Handled:=true;
end;
Ord('B') : if CtrlToBeProcessed then begin
//kt if not FEditable then exit;
ToggleBold;
Handled:=true;
exit;
end;
Ord('U') : if CtrlToBeProcessed then begin
//kt if not FEditable then exit;
ToggleUnderline;
Handled:=true;
exit;
end;
Ord('I') : if CtrlToBeProcessed then begin
//kt if not FEditable then exit;
ToggleItalic;
Handled:=true;
end;
end; {case}
end;
WM_KEYUP : begin
case Msg.WParam of
VK_CONTROL : begin
CtrlToBeProcessed:=false;
Handled:=true;
if CtrlReturnToBeProcessed then begin
PostMessage(Msg.hwnd, WM_KEYDOWN, VK_RETURN, 0);
end;
exit;
end;
VK_SHIFT : begin
ShiftToBeProcessed:=false;
Handled:=true;
exit;
end;
end; {case}
//messagedlg('I''m Am Not Active', mtWarning,mbOKCancel,0);
exit;
end;
end; {case}
end;
procedure THtmlObj.SetHTMLText(Html : String);
//After this command, Copy and Paste will not work -- ?? why? Still true??
var V : OleVariant;
V2 : variant;
body : IHTMLElement;
status : string;
temp : string;
begin
try
Stop;
TheDoc:=Document as IHTMLDocument2;
if TheDoc=nil then exit;
body := TheDoc.body;
if UpperCase(TheDoc.designMode) <> 'ON' then begin
TheDoc.designMode := 'on';
repeat //NOTE: potential endless loop. Perhaps loop only status='loading'?
status := TheDoc.readyState;
{Possible status values:
uninitialized -- Object is not initialized with data.
loading -- Object is loading its data.
loaded -- Object has finished loading its data.
interactive -- User can interact with the object even though it is not fully loaded.
complete -- Object is completely initialized. }
if status <> 'complete' then FApplication.ProcessMessages;
until (status = 'complete') or (status='interactive') or (status='loaded');
end;
body := TheDoc.body;
if (body = nil) then begin //Do so stuff to get IE to make a 'body'.
V2 := VarArrayCreate([0, 0], VarVariant);
V2[0] := ' '; //Html;
TheDoc.Write(PSafeArray(System.TVarData(V2).VArray));
body := TheDoc.body;
TheDoc.close;
repeat
status := TheDoc.readyState; //For possible status values, see above)
if status <> 'complete' then FApplication.ProcessMessages;
until (status = 'complete') or (status='interactive') or (status='loaded');
body := TheDoc.body;
end;
body.innerHTML := Html;
temp := body.innerHTML; //to test if it was set or not...
Modified:=true;
except
on E:Exception do EError('Error setting HTML text',E);
end;
end;
(*
procedure THtmlObj.SetHTMLText(Html : String);
//After this command, Copy and Paste will not work -- ?? why? Still true??
var V : OleVariant;
V2 : variant;
status : string;
begin
try
if (TheDoc=nil) or (TheDoc.body=nil) then begin
Stop;
V := Document;// as IHTMLDocument2;
V.Open;
V.Clear;
V.Write(Html);
V.Close;
//Fix: Need a way to set font and size in this operation...
end else begin
TheDoc.body.innerHTML := Html;
end;
Modified:=true;
except
on E:Exception do EError('Error setting HTML text',E);
end;
end;
*)
function THtmlObj.GetHTMLText:string;
var WS:WideString;
ch:WideChar;
n:integer;
w:word;
s:string;
begin
Result:='';
if TheDoc=nil then exit;
WS:=TheDoc.body.innerHTML;
for n:=1 to length(WS) do begin
ch:=WS[n];
w:=word(ch);
if w>255 then begin
s:=IntToStr(w);
s:=''+s+';';
end else s:=ch;
Result:=Result+s;
end;
end;
function THtmlObj.GetText:string;
var WS:WideString;
ch:WideChar;
n:integer;
w:word;
s:string;
begin
Result:='';
if TheDoc=nil then exit;
WS:=TheDoc.body.innerText;
for n:=1 to length(WS) do begin
ch:=WS[n];
w:=word(ch);
if w>255 then begin
w:=(w mod 256)+48;
s:=IntToStr(w);
s:=char(w);
end else s:=ch;
Result:=Result+s;
end;
end;
procedure THtmlObj.SetText(HTML:string);
begin
if (TheDoc=nil)or(TheDoc.body=nil) then SetHTMLText(HTML)
else TheDoc.body.innerHTML:=HTML;
end;
function THtmlObj.GetTextLen : integer;
begin
Result := Length(GetText);
end;
procedure THtmlObj.Clear;
begin
SetHTMLText('');
SetDefaultFont;
end;
function THtmlObj.SelStart:integer;
var TextRange:IHtmlTxtRange;
begin
Result:=0;
TextRange:=GetTextRange;
if TextRange=nil then exit;
Result:=Abs(Integer(TextRange.move('character',-MaxTextLength)));
end;
function THtmlObj.SelEnd:integer;
var TextRange:IHtmlTxtRange;
begin
Result:=0;
TextRange:=GetTextRange;
if TextRange=nil then exit;
Result:=Abs(Integer(TextRange.MoveEnd('character',-MaxTextLength)));
end;
function THtmlObj.SelLength:integer;
begin
Result:=SelEnd-SelStart;
end;
function THtmlObj.GetTextRange:IHtmlTxtRange;
begin
Result:=nil;
try
if TheDoc=nil then exit;
while TheDoc.body=nil do begin
WaitLoad(true);
if TheDoc.body=nil then begin
if MessageDlg('Wait for document loading?',mtConfirmation,
[mbOK,mbCancel],0) <> mrOK then begin
exit;
end;
end;
end;
if (TheDoc.Selection.type_='Text') or (TheDoc.Selection.type_='None') then begin
Result:=TheDoc.Selection.CreateRange as IHtmlTxtRange;
end;
except
on E:Exception do EError('This type of selection cannot be processed',E);
end;
end;
procedure THtmlObj.SetSelection(Start,Length:integer);
var TextRange:IHtmlTxtRange;
l : integer ; //kt
begin
try
if TheDoc=nil then exit;
TheDoc.Selection.Empty;
TextRange:=GetTextRange;
if TextRange=nil then exit;
TextRange.collapse(true);
l:=TextRange.moveEnd('character',Start+Length);
l:=TextRange.moveStart('character',Start);
TextRange.select;
except
on E:Exception do EError('Error setting HTML selection'+nl+
'Start='+IntToStr(Start)+nl+
'Length='+IntToStr(Length),E);
end;
end;
procedure THtmlObj.ClearSelection;
begin
if TheDoc=nil then exit;
TheDoc.Selection.Clear;
Modified:=true;
end;
procedure THtmlObj.ReplaceSelection(HTML:string);
var TextRange:IHtmlTxtRange;
begin
try
TextRange:=GetTextRange;
if TextRange=nil then exit;
TextRange.PasteHTML(HTML);
Modified:=true;
except
on E:Exception do begin
// implement later... ShortenString(HTML,80);
EError('Error pasting HTML'+nl+
'Microsoft HTML refuses to paste this string:'+nl+
HTML+nl,E);
end;
end;
end;
function THtmlObj.GetSelText:string;
var TextRange:IHtmlTxtRange;
begin
Result:='';
TextRange:=GetTextRange;
if TextRange=nil then
exit;
Result:=TextRange.text;
end;
procedure THtmlObj.SetSelText (HTMLText : string);
begin
ReplaceSelection(HTMLText);
end;
function THtmlObj.ColorToMSHTMLStr(color : TColor) : string;
//Note: TColor stores colors lo-byte --> hi-byte as RGB
//Function returns '#RRGGBB'
var tempColor : TMGColor;
begin
tempColor.Color := color;
Result := '#'+
IntToHex(tempColor.RGBColor.R,2)+
IntToHex(tempColor.RGBColor.G,2)+
IntToHex(tempColor.RGBColor.B,2);
end;
function THtmlObj.MSHTMLStrToColor(MSHTMLColor : string) : TColor;
//Function converts '#RRGGBB' -- TColor
//Note: TColor stores colors lo-byte --> hi-byte as RGB
var tempColor : TMGColor;
strHexRed,strHexGreen,strHexBlue : string[2];
begin
Result := clBlack; //FIX!!!! IMPLEMENT LATER...
if Pos('#',MSHTMLColor)=1 then begin
// MSHTMLColor := MidStr(MSHTMLColor,2,99);
strHexRed := MidStr(MSHTMLColor,2,2);
strHexGreen := MidStr(MSHTMLColor,4,2);
strHexBlue := MidStr(MSHTMLColor,6,2);
tempColor.RGBColor.R := StrToIntDef('$'+StrHexRed,0);
tempColor.RGBColor.G := StrToIntDef('$'+StrHexGreen,0);
tempColor.RGBColor.B := StrToIntDef('$'+StrHexBlue,0);
Result := tempColor.Color;
//NOTE: This function has not yet been tested....
end;
end;
(*
procedure THtmlObj.SetBorder(Border:boolean);
begin
if TheDoc=nil then exit;
if TheDoc.body=nil then exit;
if not Border then begin
if not FEditable then begin
TheDoc.body.style.backgroundColor := clYellow; //kt
TheDoc.body.style.borderStyle:='none';
TheDoc.body.style.borderWidth:='thin';
TheDoc.body.style.borderColor:='white';
end;
if FEditable then begin
TheDoc.body.style.backgroundColor := clRed; //kt
TheDoc.body.style.borderStyle:='none';
// TheDoc.body.filters.
TheDoc.body.style.borderWidth:='thin';
TheDoc.body.style.borderColor:='blue';
end;
end;
if Border then begin
if not FEditable then begin
TheDoc.body.style.borderStyle:='solid';
TheDoc.body.style.borderWidth:='thin';
TheDoc.body.style.borderColor:='silver';
end;
if FEditable then begin
//TheDoc.body.style.backgroundColor := ColorToStr(clLime);
TheDoc.body.style.backgroundColor := 'BtnFace';
TheDoc.body.style.borderStyle:='solid';
TheDoc.body.style.borderWidth:='thin';
TheDoc.body.style.borderColor:='green';
end;
end;
end;
*)
initialization
finalization
end.