{*******************************************************************} { } { ExpressWeb Framework by Developer Express } { Designer Module } { } { Copyright (c) 2000-2007 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSWEB FRAMEWORK AND ALL } { ACCOMPANYING VCL CLASSES AS PART OF AN EXECUTABLE WEB } { APPLICATION ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {*******************************************************************} unit cxWebDsgnHTMLConverter; interface uses Types, Classes, SysUtils, cxWebCompProd, cxWebHTMLProd, cxWebUpdateControlPosition, cxWebRender, cxWebIntf, MSHTML_TLB; type TcxEWFStoredTags = class private FRoot: TComponent; FPositioningType: TcxWebPositioningType; FList: TList; function GetObject(const AComponent: TComponent): Pointer; public constructor Create(ARoot: TComponent); destructor Destroy; override; procedure Clear; procedure Add(const AComponent: TComponent; const AEWFTag: string); procedure Remove(const AComponent: TComponent); function GetEWFTag(const AComponent: TComponent): string; function GetOldName(const AComponent: TComponent): string; property PositioningType: TcxWebPositioningType read FPositioningType write FPositioningType; end; function GetTempateHTMLFromDesigner(AModule: TComponent; const AHTML: string; AStoredTags: TcxEWFStoredTags; APositioningType: TcxWebPositioningType): string; function GetDesignHTMLContextFromTemplate(AModule: TComponent; const AHTML: string; AStoredTags: TcxEWFStoredTags; ADeleteComponents: Boolean; APositioningType: TcxWebPositioningType): string; procedure GetHTMLElements(ADOM: IHTMLDocument2; AList: IInterfaceList); procedure GetRegisterEWFTags(AStrings: TStrings); function GetDesignerHTMLClassName(const AComponentClassName: string): string; function GetDesignInnerHTMLByWebControl(AComponent: TComponent): string; function GetDesignStyleByWebControl(AComponent: TComponent): string; function GetDesignInlineStyleByWebControl(AComponent: TComponent): string; function IsHTMLCustomElement(AHTMLElement: IHTMLElement): Boolean; function GetComponentByHTMLElement(ARoot: TComponent; AHTMLElement: IHTMLElement): TComponent; function GetHTMLElementByComponentName(ADOM3: IHTMLDocument3; AComponentName: string): IHTMLElement; function GetDesignerHTMLMainParentElement(ADOM: IHTMLDocument2; ARoot: TComponent): IHTMLElement; procedure UpdateWebDesignerControlsPosition(ARoot: TComponent; ADOM: IHTMLDocument2); implementation uses {$IFDEF MSWINDOWS} Windows, Forms, {$ELSE} Qt, QForms, {$ENDIF} StrUtils, Messages, cxWebUtils, cxWebStrs, cxWebTableBld, Variants, TypInfo, cxWebDsgnUtils, ActiveX, ComObj, cxWebDsgnHTMLFilter; const cxEWFFormName = '<%=Form.Name%>'; //TODO type TcxEWFStoredTagsItem = class Component: TComponent; EWFTag: string; OldName: string; end; {TcxEWFStoredTags} constructor TcxEWFStoredTags.Create(ARoot: TComponent); begin FList := TList.Create; FRoot := ARoot; end; destructor TcxEWFStoredTags.Destroy; begin Clear; FList.Free; inherited Destroy; end; function TcxEWFStoredTags.GetObject(const AComponent: TComponent): Pointer; var I: Integer; begin Result := nil; for I := 0 to FList.Count - 1 do if TcxEWFStoredTagsItem(FList[I]).Component = AComponent then begin Result := FList[I]; break; end; end; procedure TcxEWFStoredTags.Clear; var I: Integer; begin for I := 0 to FList.Count - 1 do TcxEWFStoredTagsItem(FList[I]).Free; FList.Clear; end; procedure TcxEWFStoredTags.Add(const AComponent: TComponent; const AEWFTag: string); var AItem: TcxEWFStoredTagsItem; begin AItem := TcxEWFStoredTagsItem(GetObject(AComponent)); if AItem = nil then begin AItem := TcxEWFStoredTagsItem.Create; AItem.Component := AComponent; FList.Add(AItem); end; AItem.EWFTag := AEWFTag; AItem.OldName := AComponent.Name; end; procedure TcxEWFStoredTags.Remove(const AComponent: TComponent); var AItem: TcxEWFStoredTagsItem; begin AItem := TcxEWFStoredTagsItem(GetObject(AComponent)); if AItem <> nil then begin FList.Remove(AItem); AItem.Free; end; end; function TcxEWFStoredTags.GetEWFTag(const AComponent: TComponent): string; var AItem: TcxEWFStoredTagsItem; begin AItem := TcxEWFStoredTagsItem(GetObject(AComponent)); if AItem <> nil then Result := AItem.EWFTag else Result := ''; end; function TcxEWFStoredTags.GetOldName(const AComponent: TComponent): string; var AItem: TcxEWFStoredTagsItem; begin AItem := TcxEWFStoredTagsItem(GetObject(AComponent)); if AItem <> nil then Result := AItem.OldName else Result := ''; end; function GetDesignerHTMLClassName(const AComponentClassName: string): string; const EWFTagRemoveSt: Array[1..3] of String = ('T', 'CX', 'WEB'); var I: Integer; begin Result := AComponentClassName; for I := Low(EWFTagRemoveSt) to High(EWFTagRemoveSt) do if Pos(EWFTagRemoveSt[I], UpperCase(Result)) = 1 then Result := Copy(Result, Length(EWFTagRemoveSt[I]) + 1, Length(Result)) else break; end; function IsHTMLCustomElement(AHTMLElement: IHTMLElement): Boolean; begin Result := (AHTMLElement <> nil) and (Pos(UpperCase('<' + scxEWF), UpperCase(AHTMLElement.outerHTML)) = 1); end; function IsHTMLCustomFormElement(AHTMLElement: IHTMLElement): Boolean; begin Result := SameText(AHTMLElement.tagName, scxForm); end; function GetComponentByHTMLElement(ARoot: TComponent; AHTMLElement: IHTMLElement): TComponent; begin Result := nil; if IsHTMLCustomElement(AHTMLElement) then Result := ARoot.FindComponent(AHTMLElement.id); end; function GetHTMLElementByComponentName(ADOM3: IHTMLDocument3; AComponentName: string): IHTMLElement; begin if AComponentName <> '' then begin Result := ADOM3.getElementById(AComponentName); if (Result <> nil) and not IsHTMLCustomElement(Result) then Result := nil; end else Result := nil; end; type TcxWebConverterDOMNamespaceFactory = class(TInterfacedObject, IElementNamespaceFactory, IElementNamespaceFactoryCallback, IElementBehaviorFactory) private FStrings: TStrings; public constructor CreateObj(const AStrings: TStrings); destructor Destroy; override; { IElementNamespaceFactory } function create(const pNamespace: IElementNamespace): HResult; stdcall; function Resolve(const bstrNamespace: WideString; const bstrTagName: WideString; const bstrAttrs: WideString; const pNamespace: IElementNamespace): HResult; stdcall; { IElementBehaviorFactory } function FindBehavior(const bstrBehavior: WideString; const bstrBehaviorUrl: WideString; const pSite: IElementBehaviorSite; out ppBehavior: IElementBehavior): HResult; stdcall; end; TcxWebConverterDOM = class(TComponent, IUnknown,IDispatch, IOleClientSite) private FHTMLDocument2: IHTMLDocument2; function GetDocumentHTML: string; procedure SetDocumentHTML(const Value: string); procedure RegisterEWFTags; protected //IDispatch function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; /// IOleClientSite function SaveObject: HResult; stdcall; function GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint; out mk: IMoniker): HResult; stdcall; function GetContainer(out container: IOleContainer): HResult; stdcall; function ShowObject: HResult; stdcall; function OnShowWindow(fShow: BOOL): HResult; stdcall; function RequestNewObjectLayout: HResult; stdcall; public constructor Create(AOwner: TComponent); override; procedure Wait; property DOM: IHTMLDocument2 read FHTMLDocument2; property DocumentHTML: string read GetDocumentHTML write SetDocumentHTML; end; constructor TcxWebConverterDOMNamespaceFactory.CreateObj(const AStrings: TStrings); begin FStrings := TStringList.Create; FStrings.Assign(AStrings); end; destructor TcxWebConverterDOMNamespaceFactory.Destroy; begin FStrings.Free; inherited Destroy; end; function TcxWebConverterDOMNamespaceFactory.create(const pNamespace: IElementNamespace): HResult; var I: Integer; begin for I := 0 to FStrings.Count - 1 do pNamespace.AddTag(FStrings[I], 0); {Creates a normal element behavior} Result := S_OK; end; function TcxWebConverterDOMNamespaceFactory.Resolve(const bstrNamespace: WideString; const bstrTagName: WideString; const bstrAttrs: WideString; const pNamespace: IElementNamespace): HResult; stdcall; begin REsult := S_OK; end; function TcxWebConverterDOMNamespaceFactory.FindBehavior(const bstrBehavior: WideString; const bstrBehaviorUrl: WideString; const pSite: IElementBehaviorSite; out ppBehavior: IElementBehavior): HResult; stdcall; begin ppBehavior := nil; Result := S_OK; end; const CLSID_HTMLDocument: TCLSID = '{25336920-03F9-11cf-8FD0-00AA00686F13}'; constructor TcxWebConverterDOM.Create(AOwner: TComponent); var PersistStream: IPersistStreamInit; AOleObject: IOleObject; begin inherited Create(AOwner); OleCheck(CoCreateInstance(CLSID_HTMLDocument, nil, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, FHTMLDocument2)); if DOM <> nil then begin if Supports(FHTMLDocument2, IOleObject, AOleObject) then AOleObject.SetClientSite(self); DOM.designMode := 'On'; if Supports(DOM, IPersistStreamInit, PersistStream) then OleCheck(PersistStream.InitNew); RegisterEWFTags; end; end; procedure TcxWebConverterDOM.RegisterEWFTags; var AStrings: TStrings; VFactory: OleVariant; SP: IServiceProvider; NST: IElementNamespaceTable; ANamespaceFactory: IElementNamespaceFactory; rs: HRESULT; begin DocumentHTML; Wait; AStrings := TStringList.Create; GetRegisterEWFTags(AStrings); ANamespaceFactory := TcxWebConverterDOMNamespaceFactory.CreateObj(AStrings); AStrings.Free; TVarData(VFactory).VType := VT_UNKNOWN; TVarData(VFactory).VUnknown := Pointer(ANamespaceFactory); ANamespaceFactory._AddRef; if Supports(DOM, IServiceProvider, SP) and (SP.QueryService(IElementNamespaceTable, IElementNamespaceTable, NST) = S_OK) then begin rs := NST.AddNamespace(scxEWF, '', ELEMENTNAMESPACEFLAGS_ALLOWANYTAG, VFactory); {Creates a normal namespace} if rs <> S_OK then Wait; end; end; procedure TcxWebConverterDOM.Wait; var Msg: TMsg; begin if not Assigned(DOM) then exit; while (CompareText(DOM.readyState, 'complete') <> 0) and (CompareText(DOM.readyState, 'uninitialized') <> 0) do if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin if Msg.Message <> WM_QUIT then begin TranslateMessage(Msg); DispatchMessage(Msg); end; end; end; const DISPID_AMBIENT_DLCONTROL = (-5512); DLCTL_NO_SCRIPTS = $00000080; DLCTL_NO_JAVA = $00000100; DLCTL_NO_RUNACTIVEXCTLS = $00000200; DLCTL_NO_DLACTIVEXCTLS = $00000400; DLCTL_DOWNLOADONLY = $00000800; DLCTL_NO_FRAMEDOWNLOAD = $00001000; function TcxWebConverterDOM.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; begin if DISPID_AMBIENT_DLCONTROL = DispId then begin PVariant(VarResult)^ := DLCTL_DOWNLOADONLY + DLCTL_NO_SCRIPTS + DLCTL_NO_JAVA + DLCTL_NO_DLACTIVEXCTLS + DLCTL_NO_RUNACTIVEXCTLS; Result := S_OK; end else Result := DISP_E_MEMBERNOTFOUND; end; function TcxWebConverterDOM.SaveObject: HResult; begin Result := E_NOTIMPL; end; function TcxWebConverterDOM.GetMoniker(dwAssign: Longint; dwWhichMoniker: Longint; out mk: IMoniker): HResult; begin Result := E_NOTIMPL; end; function TcxWebConverterDOM.GetContainer(out container: IOleContainer): HResult; begin Result := E_NOTIMPL; end; function TcxWebConverterDOM.ShowObject: HResult; begin Result := E_NOTIMPL; end; function TcxWebConverterDOM.OnShowWindow(fShow: BOOL): HResult; begin Result := E_NOTIMPL; end; function TcxWebConverterDOM.RequestNewObjectLayout: HResult; begin Result := E_NOTIMPL; end; procedure TcxWebConverterDOM.SetDocumentHTML(const Value: string); var InternalStream: TStringStream; OleStream: IStream; PersistStream: IPersistStreamInit; begin Wait; if Supports(DOM, IPersistStreamInit, PersistStream) then begin OleCheck(PersistStream.InitNew); InternalStream := TStringStream.Create(Value); try InternalStream.Position := 0; OleStream := TStreamAdapter.Create(InternalStream); OleCheck(PersistStream.Load(OleStream)); finally InternalStream.Free; end; end; Wait; end; function TcxWebConverterDOM.GetDocumentHTML: string; var InternalStream: TStringStream; OleStream: IStream; PersistStream: IPersistStreamInit; begin Wait; Result := (DOM as IHTMLDocument3).documentElement.outerHTML; exit; if Supports(DOM, IPersistStreamInit, PersistStream) then begin InternalStream := TStringStream.Create(''); try OleStream := TStreamAdapter.Create(InternalStream); OleCheck(PersistStream.Save(OleStream, True)); Result := InternalStream.DataString; finally InternalStream.Free; end; end; Wait; end; function GetDesignInnerHTMLByWebControl(AComponent: TComponent): string; var ACodeProvider: IcxCodeProvider; ADesignCodeProvider: IcxDesignCodeProvider; AHTMLTextBuilder: TcxHTMLTextBuilder; begin AHTMLTextBuilder := TcxHTMLTextBuilder.Create(TcxWebBrowserIE); if Supports(AComponent, IcxCodeProvider, ACodeProvider) then begin if Supports(AComponent, IcxDesignCodeProvider, ADesignCodeProvider) then ADesignCodeProvider.WriteHTML(AHTMLTextBuilder) else ACodeProvider.WriteHTML(AHTMLTextBuilder); end; Result := AHTMLTextBuilder.Text; AHTMLTextBuilder.Free; end; function GetDesignStyleByWebControl(AComponent: TComponent): string; var AStylesIntf: IcxStylesProvider; ACodeIntf: IcxCodeProvider; ABuilder: TcxHTMLTextBuilder; ARendererClass: TcxWebRendererClass; I: Integer; ProviderList: TList; ProviderIntf: IcxWebProvidersSupport; begin ABuilder := TcxHTMLTextBuilder.Create(TcxWebBrowserIE); ABuilder.DisableValidation := True; try if Supports(AComponent, IcxWebProvidersSupport, ProviderIntf) then begin ProviderList := TList.Create; try ProviderIntf.GetProviders(ProviderList); for I := 0 to ProviderList.Count - 1 do if Supports(TComponent(ProviderList.Items[I]), IcxStylesProvider, AStylesIntf) then AStylesIntf.WriteStyles(ABuilder); finally ProviderList.Free; end; end; if Supports(AComponent, IcxStylesProvider, AStylesIntf) then AStylesIntf.WriteStyles(ABuilder); if Supports(AComponent, IcxCodeProvider, ACodeIntf) then begin ARendererClass := ACodeIntf.GetRendererClass(TcxWebBrowserIE); if (ARendererClass <> nil) then ARendererClass.WriteStyles(ABuilder); end; Result := ABuilder.Text; finally ABuilder.Free; end; end; function GetDesignInlineStyleByWebControl(AComponent: TComponent): string; var WebControl: IcxWebControl; begin if Supports(AComponent, IcxWebControl, WebControl) then Result := Format('z-index: %d', [WebControl.ZIndex]) else Result := ''; end; type TcxDesignerWebControlHTMLItem = class(TcxWebControlHTMLItem) public procedure WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); override; end; TcxDesignerWebContainerControlHTMLItem = class(TcxWebContainerControlHTMLItem) public procedure WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); override; end; TcxCustomWebDesignerHTMLProd = class(TcxWebHTMLProd) private FStoredTags: TcxEWFStoredTags; protected function IsFirstRequest: Boolean; override; function GetComponentHTMLItemClass(AComponentClass: TComponentClass): TcxComponentHTMLItemClass; override; function GetSetComponentProperties: Boolean; override; public constructor Create(AModule: TComponent; AStoredTags: TcxEWFStoredTags); end; TcxWebDesignerHTMLProd = class(TcxCustomWebDesignerHTMLProd) private FDeleteComponents: Boolean; protected procedure DoBeforeHTMLRender; override; public property DeleteComponents: Boolean read FDeleteComponents write FDeleteComponents; end; TcxDesignerWebControlHTMLItemCorrect = class(TcxWebControlHTMLItem) public procedure WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); override; end; TcxDesignerWebContainerControlHTMLItemCorrect = class(TcxWebContainerControlHTMLItem) public procedure WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); override; end; TcxWebDesignerHTMLProdCorrect = class(TcxCustomWebDesignerHTMLProd) protected function GetComponentHTMLItemClass(AComponentClass: TComponentClass): TcxComponentHTMLItemClass; override; end; procedure TcxDesignerWebControlHTMLItem.WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); begin TcxCustomWebDesignerHTMLProd(HTMLProd).FStoredTags.Add(Component, EWFTagFormat); AHTMLTextBuilder.WriteText(EWFTagFormat + Format('%s:%s>', [scxEWF, ComponentClassName]), False, False); end; procedure TcxDesignerWebContainerControlHTMLItem.WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); var I: Integer; begin UpdateExcludeList; TcxCustomWebDesignerHTMLProd(HTMLProd).FStoredTags.Add(Component, EWFTagFormat); AHTMLTextBuilder.WriteText(EWFTagFormat, False, False); for I := 0 to Count - 1 do Items[I].WriteHTML(AHTMLTextBuilder); AHTMLTextBuilder.WriteText(EWFEndTagFormat, False, False); end; {TcxCustomWebDesignerHTMLProd} constructor TcxCustomWebDesignerHTMLProd.Create(AModule: TComponent; AStoredTags: TcxEWFStoredTags); begin inherited Create(AModule); FStoredTags := AStoredTags; end; function TcxCustomWebDesignerHTMLProd.IsFirstRequest: Boolean; begin Result := False; end; function TcxCustomWebDesignerHTMLProd.GetComponentHTMLItemClass(AComponentClass: TComponentClass): TcxComponentHTMLItemClass; begin if Supports(AComponentClass, IcxWebContainerControl) then Result := TcxDesignerWebContainerControlHTMLItem else if Supports(AComponentClass, IcxWebControl) then Result := TcxDesignerWebControlHTMLItem else Result := inherited GetComponentHTMLItemClass(AComponentClass); end; function TcxCustomWebDesignerHTMLProd.GetSetComponentProperties: Boolean; begin Result := False; end; {TcxWebDesignerHTMLProd} procedure TcxWebDesignerHTMLProd.DoBeforeHTMLRender; procedure CheckDuplicatedNames; var I: Integer; AStrings: TStrings; AErrorName: string; begin AStrings := TStringList.Create; AErrorName := ''; try for I := 0 to ComponentItemCount - 1 do if AStrings.IndexOf(ComponentItems[I].ComponentName) = -1 then AStrings.Add(ComponentItems[I].ComponentName) else begin AErrorName := ComponentItems[I].ComponentName; break; end; finally AStrings.Free; end; if AErrorName <> '' then raise Exception.CreateFmt(scxWebDuplicateName, [AErrorName]); end; procedure CheckFormHTMLItem; var ARootName: string; begin if ModuleItem <> nil then ARootName := ModuleItem.Component.Name else ARootName := ''; if (ARootName <> '') and (Module.Name <> ARootName) and (Pos('%', ARootName) < 1) then try Module.Name := ARootName; except end; end; function IsComponentExists(AComponent: TComponent): Boolean; var I: Integer; begin Result := False; for I := 0 to ComponentItemCount - 1 do if (ComponentItems[I].Component = AComponent) then begin Result := True; break; end; end; procedure AddDeletedComponents(AList: TList); var I: Integer; begin for I := 0 to Module.ComponentCount - 1 do if Supports(Module.Components[I], IcxWebControl) and not IsComponentExists(Module.Components[I]) then AList.Add(Module.Components[I]); end; function GetComponentItemByComponent(AComponent: TComponent): TcxComponentHTMLItem; var I: Integer; begin Result := nil; for I := 0 to ComponentItemCount - 1 do if ComponentItems[I].Component = AComponent then begin Result := ComponentItems[I]; break; end; end; procedure CreateControlsFromDeletedList(AList: TList); function GetEWFTag(AComponent: TComponent; AIsClosed: Boolean): string; begin Result := '<'; if AIsClosed then Result := Result + '/'; Result := Result + scxEWF + ':' + GetDesignerHTMLClassName(AComponent.ClassName) + ' ' + scxId + '=' + AComponent.Name + '>'; end; function CreateComponentHTMLItem(AComponent: TComponent): TcxComponentHTMLItem; var AEWFTagRecord: TcxWebHTMLComponent; AWebControl: IcxWebControl; AParentComponent: TComponent; begin AEWFTagRecord.ClassName := GetDesignerHTMLClassName(AComponent.ClassName); AEWFTagRecord.Name := AComponent.Name; if Supports(AComponent, IcxWebControl, AWebControl) and (AWebControl <> nil) and (AWebControl.Parent <> nil) then AParentComponent := GetComponentByInterface(AWebControl.Parent) else AParentComponent := nil; if AParentComponent = nil then AParentComponent := Module; AEWFTagRecord.ParentName := AParentComponent.Name; Result := AddComponentHTMLItem(AComponent, GetComponentItemByComponent(AParentComponent), True, GetEWFTag(AComponent, False), TComponentClass(AComponent.ClassType), @AEWFTagRecord, beginTableRender); end; procedure MoveChildrenComponentInItemList(AHTMLItem: TcxComponentHTMLItem); var I: Integer; AWebControl: IcxWebControl; AWebContainer: IcxWebContainerControl; AWebComponentItem: TcxComponentHTMLItem; begin if not Supports(AHTMLItem.Component, IcxWebContainerControl, AWebContainer) then exit; for I := 0 to ComponentItemCount - 1 do if Supports(ComponentItems[I].Component, IcxWebControl, AWebControl) and (AWebControl.Parent = AWebContainer) then begin AWebComponentItem := ComponentItems[I]; AWebComponentItem.Parent.Remove(AWebComponentItem); AHTMLItem.Insert(AWebComponentItem); end; end; var I: Integer; AComponentHTMLItem: TcxComponentHTMLItem; begin for I := 0 to AList.Count - 1 do begin AComponentHTMLItem := CreateComponentHTMLItem(TComponent(AList[I])); if Supports(TComponent(AList[I]), IcxWebContainerControl) then MoveChildrenComponentInItemList(AComponentHTMLItem); end; AList.Clear; end; procedure AddCreatedControls(AList: TList); var I: Integer; begin for I := 0 to ComponentItemCount - 1 do if (ComponentItems[I].ComponentClass <> nil) and Supports(ComponentItems[I].ComponentClass, IcxWebControl) and (ComponentItems[I].Component = nil) then AList.Add(ComponentItems[I]); end; function GetHTMLItemByComponentClass(AComponentClass: TComponentClass; ACreatedControls: TList): TcxComponentHTMLItem; var I: Integer; begin Result := nil; for I := 0 to ACreatedControls.Count - 1 do if (TcxComponentHTMLItem(ACreatedControls[I]).ComponentClass = AComponentClass) then begin Result := TcxComponentHTMLItem(ACreatedControls[I]); break; end; end; procedure ChangeComponentName(AComponent: TComponent; ANewName: string); begin try if ANewName <> '' then try AComponent.Name := ANewName except raise; end; finally end; end; procedure ChangeNames(ADeletedComponents, ACreatedControls: TList); var I: Integer; AHTMLItem: TcxComponentHTMLItem; AComponent: TComponent; begin I := 0; while I < ADeletedComponents.Count do begin AComponent := TComponent(ADeletedComponents[I]); AHTMLItem := GetHTMLItemByComponentClass( TComponentClass(AComponent.ClassType), ACreatedControls); if AHTMLItem <> nil then begin AHTMLItem.Component := AComponent; ADeletedComponents.Delete(I); ACreatedControls.Remove(AHTMLItem); ChangeComponentName(AComponent, AHTMLItem.ComponentName); end else Inc(I); end; end; procedure ChangeParents(AWebModuleContainer: IcxWebContainerControl); var I: Integer; AWebControl: IcxWebControl; AContainer: IcxWebContainerControl; begin for I := 0 to ComponentItemCount - 1 do if (ComponentItems[I].Component <> nil) and not (csDestroying in ComponentItems[I].Component.ComponentState) and Supports(ComponentItems[I].Component, IcxWebControl, AWebControl) and (ComponentItems[I].Parent <> ComponentItems[I])then begin if (ComponentItems[I].Parent = nil) or (ComponentItems[I].Parent.Component = nil) or not Supports(ComponentItems[I].Parent.Component, IcxWebContainerControl, AContainer) then AContainer := nil; if AContainer = nil then AContainer := AWebModuleContainer; if (AWebControl.Parent <> AContainer) then AWebControl.Parent := AContainer; end; end; procedure DeleteComponents(AList: TList); var I, J: Integer; RemoveList: TInterfaceList; AComponent: TComponent; AContainer: IcxWebContainerControl; begin for I := 0 to AList.Count - 1 do begin AComponent := TComponent(AList[I]); if not (csDestroying in AComponent.ComponentState) then begin if Supports(AComponent, IcxWebContainerControl, AContainer) then begin RemoveList := TInterfaceList.Create; try for J := 0 to AContainer.ControlCount - 1 do if IsComponentExists(GetComponentByInterface(AContainer.Controls[J])) then RemoveList.Add(AContainer.Controls[J]); for J := 0 to RemoveList.Count - 1 do (RemoveList[J] as IcxWebControl).Parent := nil; finally RemoveList.Free; end; end; AComponent.Free; end; end; end; procedure CreateComponents(AList: TList; AWebModuleContainer: IcxWebContainerControl); var I: Integer; AComponent: TComponent; AWebControl: IcxWebControl; AWebContainer: IcxWebContainerControl; begin AComponent := nil; for I := 0 to AList.Count - 1 do with TcxComponentHTMLItem(AList[I]) do begin try try AComponent := ComponentClass.Create(Module); AComponent.Name := ComponentName; if Supports(AComponent, IcxWebControl, AWebControl) then begin if Supports(TcxComponentHTMLItem(AList[I]).Parent.Component, IcxWebContainerControl, AWebContainer) then AWebControl.Parent := AWebContainer else AWebControl.Parent := AWebModuleContainer; TcxComponentHTMLItem(AList[I]).Parent.ExcludeList.Add(AComponent) end; except raise; end; finally Component := AComponent; end; end; end; procedure SetContainersAttributes; procedure CorrectEWFTag(AHTMLItem: TcxWebContainerControlHTMLItem; AAtributeName, AOldAttributeValue, ANewAttributeValue: string); var AStream: TStringStream; AParser: TcxParser; APos: Integer; begin APos := -1; AStream := TStringStream.Create(AHTMLItem.EWFTagFormat); AParser := TcxParser.Create(AStream); try while True do begin while AParser.NextToken <> toEOF do if SameText(AParser.TokenString, AAtributeName) then break; while AParser.NextToken <> toEOF do begin APos := AParser.OutStringLength; if SameText(AParser.TokenString, AOldAttributeValue) then break; end; if (APos > -1) or (AParser.NextToken = toEOF) then break; end; finally AParser.Free; AStream.Free; end; if APos > -1 then AHTMLItem.EWFTagFormat := LeftStr(AHTMLItem.EWFTagFormat, APos - 1) + ANewAttributeValue + Copy(AHTMLItem.EWFTagFormat, APos + Length(AOldAttributeValue), Length(AHTMLItem.EWFTagFormat)) else AHTMLItem.EWFTagFormat := LeftStr(AHTMLItem.EWFTagFormat, Length(AHTMLItem.EWFTagFormat) - 1) + ' ' + AAtributeName + '="' + ANewAttributeValue + '">'; end; var I: Integer; begin for I := 0 to ContainerItemCount - 1 do begin if (ContainerItems[I].RenderChildren <> endRender) then begin CorrectEWFTag(ContainerItems[I], scxRenderChildren, GetEnumName(TypeInfo(TcxRenderChildren), Integer(ContainerItems[I].RenderChildren)), GetEnumName(TypeInfo(TcxRenderChildren), Integer(endRender))); ContainerItems[I].RenderChildren := endRender; end; if not Supports(ContainerItems[I].Component, IcxWebPageModule) then begin CorrectEWFTag(ContainerItems[I], scxLayout, GetEnumName(TypeInfo(TcxWebControlLayout), Integer(ContainerItems[I].WebContainerControl.ControlLayout)), GetEnumName(TypeInfo(TcxWebControlLayout), Integer(wclFlow))); end; end; end; var ADeletedComponents: TList; ACreatedControls: TList; AWebModuleContainer: IcxWebContainerControl; begin CheckDuplicatedNames; CheckFormHTMLItem; ADeletedComponents := TList.Create; ACreatedControls := TList.Create; Supports(Module, IcxWebContainerControl, AWebModuleContainer); try AddDeletedComponents(ADeletedComponents); if not self.DeleteComponents then CreateControlsFromDeletedList(ADeletedComponents); AddCreatedControls(ACreatedControls); ChangeNames(ADeletedComponents, ACreatedControls); DeleteComponents(ADeletedComponents); CreateComponents(ACreatedControls, AWebModuleContainer); ChangeParents(AWebModuleContainer); SetContainersAttributes; finally ADeletedComponents.Free; ACreatedControls.Free; end; end; procedure cxDesignerComponentHTMLItemCorrector(AParser: TcxCustomWebDesignerHTMLProd; AItem: TcxComponentHTMLItem; AHTMLTextBuilder: TcxHTMLTextBuilder); function ReplaceComponentName(const AEWFTag, AOldName, ANewName: string): string; var AStream: TStringStream; AParser: TcxParser; APos: Integer; begin APos := -1; AStream := TStringStream.Create(AEWFTag); AParser := TcxParser.Create(AStream); try while True do begin while AParser.NextToken <> toEOF do if SameText(AParser.TokenString, scxId) then break; while AParser.NextToken <> toEOF do begin APos := AParser.OutStringLength; if SameText(AParser.TokenString, AOldName) then break; end; if AParser.IsEOF then APos := -1; if (APos > -1) or (AParser.NextToken = toEOF) then break; end; finally AParser.Free; AStream.Free; end; if APos > -1 then Result := LeftStr(AEWFTag, APos - 1) + ANewName + Copy(AEWFTag, APos + Length(AOldName), Length(AEWFTag)) else Result := AEWFTag; end; var AOldName, AEWFTag: string; APageModule: IcxWebPageModule; begin AEWFTag := AParser.FStoredTags.GetEWFTag(AItem.Component); if AEWFTag = '' then //Is new? begin // AHTMLTextBuilder.WriteText(' '); //on the next line if Supports(AItem.Component, IcxWebContainerControl) and //add endrender and FlowLayout for Panel not Supports(AItem.Component, IcxWebPageModule) then AHTMLTextBuilder.WriteText(Format('<%s:%s %s="%s" %s="%s" %s="%s">', [scxEWF, AItem.ComponentClassName, scxId, AItem.Component.Name, scxRenderChildren, GetEnumName(TypeInfo(TcxRenderChildren), Integer(endRender)), scxLayout, GetEnumName(TypeInfo(TcxWebControlLayout), Integer(wclFlow))]), False) else AHTMLTextBuilder.WriteText(Format('<%s:%s %s="%s">', [scxEWF, AItem.ComponentClassName, scxId, AItem.Component.Name]), False); end else begin AOldName := AParser.FStoredTags.GetOldName(AItem.Component); if not SameText(AOldName, AItem.Component.Name) then AEWFTag := ReplaceComponentName(AEWFTag, AOldName, AItem.Component.Name); if Supports(AParser.Module, IcxWebPageModule, APageModule) and (AParser.Module <> AItem.Component) and (APageModule.GetPositioningType <> cxptGrid) and (AParser.FStoredTags.PositioningType = cxptGrid) then AHTMLTextBuilder.WriteText(' '); AHTMLTextBuilder.WriteText(AEWFTag, False, False); end; end; procedure TcxDesignerWebControlHTMLItemCorrect.WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); begin cxDesignerComponentHTMLItemCorrector(TcxCustomWebDesignerHTMLProd(HTMLProd), self, AHTMLTextBuilder); end; procedure TcxDesignerWebContainerControlHTMLItemCorrect.WriteHTML(AHTMLTextBuilder: TcxHTMLTextBuilder); var I: Integer; begin cxDesignerComponentHTMLItemCorrector(TcxCustomWebDesignerHTMLProd(HTMLProd), self, AHTMLTextBuilder); for I := 0 to Count - 1 do Items[I].WriteHTML(AHTMLTextBuilder); AHTMLTextBuilder.WriteText(EWFEndTagFormat, False, False); end; function TcxWebDesignerHTMLProdCorrect.GetComponentHTMLItemClass(AComponentClass: TComponentClass): TcxComponentHTMLItemClass; begin if Supports(AComponentClass, IcxWebContainerControl) then Result := TcxDesignerWebContainerControlHTMLItemCorrect else if Supports(AComponentClass, IcxWebControl) then Result := TcxDesignerWebControlHTMLItemCorrect else Result := inherited GetComponentHTMLItemClass(AComponentClass); end; type TcxHTMLWebUpdateControlPositionItem = class(TcxCustomWebUpdateControlPositionItem) private FHTMLElement: IHTMLElement; FTableBuilderOffSet: TPoint; FWebControl: IcxWebControl; FReplaceElement: Boolean; protected function GetBoundsRect: TRect; override; procedure SetBoundsRect(const Value: TRect); override; public constructor Create(ARoot: TComponent; AHTMLElement: IHTMLElement; ATableBuilderOffset: TPoint; AReplaceElement: Boolean); procedure WriteHTML(HTMLTextBuilder: TcxHTMLTextBuilder); override; property HTMLElement: IHTMLElement read FHTMLElement; property WebControl: IcxWebControl read FWebControl; end; {TcxHTMLWebUpdateControlPositionItem} constructor TcxHTMLWebUpdateControlPositionItem.Create(ARoot: TComponent; AHTMLElement: IHTMLElement; ATableBuilderOffset: TPoint; AReplaceElement: Boolean); var AComponent: TComponent; begin FReplaceElement := AReplaceElement; FHTMLElement := AHTMLElement; FTableBuilderOffset := ATableBuilderOffset; FWebControl := nil; if ARoot <> nil then AComponent := GetComponentByHTMLElement(ARoot, AHTMLElement) else AComponent := nil; if AComponent <> nil then Supports(AComponent, IcxWebControl, FWebControl); end; function TcxHTMLWebUpdateControlPositionItem.GetBoundsRect: TRect; begin with HTMLElement.style do begin Result.Left := pixelLeft; Result.Top := pixelTop; if WebControl <> nil then begin with WebControl.BoundsRect do begin Result.Right := Result.Left + Right - Left; Result.Bottom := Result.Top + Bottom - Top; end; end else begin Result.Right := HTMLElement.offsetWidth + pixelLeft; Result.Bottom := HTMLElement.offsetHeight + pixelTop; end; end; OffsetRect(Result, -FTableBuilderOffset.X, -FTableBuilderOffset.Y); end; procedure TcxHTMLWebUpdateControlPositionItem.SetBoundsRect(const Value: TRect); var R: TRect; begin R := Value; OffsetRect(R, FTableBuilderOffset.X, FTableBuilderOffset.Y); if WebControl <> nil then WebControl.BoundsRect := R; with HTMLElement.style do begin pixelLeft := R.Left; pixelTop := R.Top; pixelWidth := R.Right - R.Left; pixelHeight := R.Bottom - R.Top; end; end; procedure TcxHTMLWebUpdateControlPositionItem.WriteHTML(HTMLTextBuilder: TcxHTMLTextBuilder); begin HTMLTextBuilder.WriteText(HTMLElement.outerHTML); if FReplaceElement then HTMLElement.outerHTML := ''; end; function IsHTMLElementTableBuilder(AElement: IHTMLElement): Boolean; var AttrValue: Variant; begin if(CompareText(AElement.tagName, 'TABLE') = 0) then begin AttrValue := AElement.getAttribute(cxWebTableBuilderAttribute, 0); if VarType(AttrValue) = varOleStr then Result := CompareText(AttrValue, 'TRUE') = 0 else Result := False; end else Result := False; end; function IsHTMLElementTableBuilderElement(AElement: IHTMLElement): Boolean; var ATagName: string; begin Result := IsHTMLElementTableBuilder(AElement); if not Result then begin ATagName := AElement.tagName; if ((CompareText(ATagName, 'TR') = 0) or (CompareText(ATagName, 'TD') = 0) or (CompareText(ATagName, 'TBODY') = 0)) and (AElement.parentElement <> nil) then Result := IsHTMLElementTableBuilderElement(AElement.parentElement) end; end; function FindHTMLTable(ADOM: IHTMLDOcument2): IHTMLElement; var ADOM3: IHTMLDocument3; AElementCollection: IHTMLElementCollection; ADispatch: IDispatch; AElement: IHTMLElement; I: Integer; begin Result := nil; if Supports(ADOM, IHTMLDocument3, ADOM3) then begin AElementCollection := ADOM3.getElementsByTagName('TABLE'); for I := 0 to AElementCollection.length - 1 do begin ADispatch := AElementCollection.item(I, i); if (ADispatch <> nil) and (ADispatch.QueryInterface(IHTMLElement, AElement) = S_OK) and IsHTMLElementTableBuilder(AElement) then begin Result := AElement; break; end; end; end; end; function GetHTMLTable(ARoot: TComponent; ADOM: IHTMLDocument2): IHTMLElement; var I: Integer; ABody_FormNode, AElementNode, ANodeAfterTable: IHTMLDOMNode; AELement: IHTMLElement; AElementCollection: IHTMLElementCollection; AHTMLTable: IHTMLTable; begin Result := FindHTMLTable(ADOM); if Result = nil then begin Result := ADOM.createElement(Format('