JSExtented.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. (*
  2.  *                               NeuglsWorkStudio
  3.  *                     HTML Interface Javascript Extendtion
  4.  *  This unit implmented TNCJsExtented which used for extend the capablity of
  5.  *  javascript.
  6.  *
  7.  *  Author     : Neugls
  8.  *  Create time: 4/27/2011
  9.  *
  10.  *  Thanks for : Henri Gourvest
  11.  *
  12.  *
  13.  *
  14.  *
  15.  *
  16.  *)
  17. unit JSExtented;
  18. interface
  19. uses
  20. SysUtils, Classes, ceflib, Rtti, cefvcl;
  21. const
  22.   csErrorParameters            ='Error Parameters';
  23.   csHaveNoThisMember           ='Have no member';
  24.   csChromiumCouldNotBeNil      ='Chromium could not be nil, please first set the Chromium property';
  25. type
  26. TVCLJsExtended=class(TComponent)
  27. type
  28. TANameType=(ntMethod,ntField,ntProperty);
  29. {Inner class}
  30. TNCJSHandle=class(TCefv8HandlerOwn)
  31. private
  32. FContainer:TVCLJsExtended;
  33. protected
  34. function Execute(const name: ustring; const obj: ICefv8Value;
  35. const arguments: TCefv8ValueArray; var retval: ICefv8Value;
  36. var exception: ustring): Boolean; override;
  37. procedure JsCallMethod(Method:TRttiMethod;out ReturnVal:ICefv8Value; const Param:TCefv8ValueArray);overload;
  38. procedure JsCallMethod(Method:TRttiMethod;out ReturnVal:ICefv8Value);overload;
  39. function MethodParamLength(Mn:string):Integer;
  40. public
  41. constructor Create(Container:TVCLJsExtended);
  42. end;
  43. private
  44. FProcessObject:TObject;
  45. FJsHandle:TNCJSHandle;
  46. FTypeInfo:Pointer;
  47. FCustomChromium:TChromium;
  48. FFrame:ICefFrame;
  49. public
  50. Frame:ICefFrame{ read FFrame write FFrame};
  51. property ProcessObject:TObject read FProcessObject;
  52. property ATypeInfo:Pointer read FTypeInfo;
  53. procedure SetProcessObject(value:TObject;ATypeInfo:Pointer);
  54. Procedure ExecuteJavaScript(const jsCode, scriptUrl: string; startLine: Integer);overload;
  55. Procedure ExecuteJavaScript(const jsCode:string);overload;
  56. constructor create(AOwner:TComponent);override;
  57. property Chromium:TChromium read FCustomChromium write FCustomChromium;
  58. end;
  59. TVCLNcJsExtended = class(TVCLJsExtended)
  60. published
  61. property Chromium;
  62. end;
  63. TNCWebBrowser=class(TChromium)
  64. end;
  65. procedure Register;
  66. implementation
  67. uses TypInfo;
  68. procedure Register;
  69. begin
  70. RegisterComponents('NwControls', [TVCLNcJsExtended]);
  71. RegisterComponents('NwControls', [TChromium]);
  72. end;
  73. { TVCLJsExtended }
  74. constructor TVCLJsExtended.create(AOwner:TComponent);
  75. begin
  76. inherited create(AOwner);
  77. FProcessObject:=nil;
  78. FJsHandle:=TNCJSHandle.Create(Self);
  79. end;
  80. procedure TVCLJsExtended.ExecuteJavaScript(const jsCode, scriptUrl: string;
  81.   startLine: Integer);
  82. begin
  83. if not Assigned(FCustomChromium) then
  84. begin
  85. raise Exception.Create(csChromiumCouldNotBeNil);
  86. Exit;
  87. end;
  88. FCustomChromium.Browser.MainFrame.ExecuteJavaScript(jsCode,scriptUrl,startLine);
  89. end;
  90. procedure TVCLJsExtended.ExecuteJavaScript(const jsCode:string);
  91. begin
  92. ExecuteJavaScript(jsCode,'',0);
  93. end;
  94. procedure TVCLJsExtended.SetProcessObject(value: TObject;ATypeInfo:Pointer);
  95. var
  96. RttiContext:TRttiContext;
  97. RttiType:TRttiType;
  98. RM:TRttiMethod;
  99. RP:TRttiProperty;
  100. RF:TRttiField;
  101. JsStr,name:String;
  102. I:Integer;
  103. begin
  104. {
  105. 根据object所提供的方法属性生成js字符串,希望注册.
  106. }
  107. FProcessObject:=value;
  108. FTypeInfo:=ATypeInfo;
  109. RttiType:=RttiContext.GetType(FTypeInfo);
  110. name:=RttiType.Name;
  111. JsStr:=Format('var %s;',[name]);
  112. JsStr:=Format('%s if(!%s) %s={};',[JsStr,name,name]);
  113. {Process method}
  114. for RM in RttiType.GetMethods  do
  115. begin
  116. JsStr:=JsStr+Format(#$A#$D' native function %s(',[RM.Name]);
  117. if Length(RM.GetParameters)=0 then
  118. JsStr:=Format('%s);',[JsStr])
  119. else
  120. begin
  121. for I := 0 to Length(RM.GetParameters)-2 do
  122. JsStr:=Format('%s %s,',[JsStr,chr(ord('A')+I)]);
  123. I:=Length(RM.GetParameters)-1;
  124. JsStr:=Format('%s %s);',[JsStr,chr(ord('A')+I)]);
  125. end;
  126. end;
  127. {Process Field}
  128. for RF in RttiType.GetFields do
  129. begin
  130. JsStr:=Format('%s'#$A#$D' var %s;',[JsStr,RF.Name]);
  131. case RF.FieldType.TypeKind of
  132. tkUnknown: ;
  133. tkInteger: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsInteger]);
  134. tkChar: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  135. tkEnumeration: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsInteger]);
  136. tkFloat: JsStr:=Format('%s'#$A#$D' %s=%f;',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsExtended]);
  137. tkString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  138. tkSet: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsInteger]);
  139. tkClass:{support later} JsStr:=Format('%s'#$A#$D' %s={};',[JsStr,RF.Name]);
  140. tkMethod: ;
  141. tkWChar: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  142. tkLString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  143. tkWString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  144. tkVariant: ;
  145. tkArray: ;
  146. tkRecord: ;
  147. tkInterface: ;
  148. tkInt64: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsInteger]);
  149. tkDynArray: ;
  150. tkUString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RF.Name,RF.GetValue(FProcessObject).AsString]);
  151. tkClassRef: ;
  152. tkPointer: ;
  153. tkProcedure: ;
  154. end;
  155. end;
  156. {Process property}
  157. for RP in RttiType.GetProperties do
  158. begin
  159. JsStr:=Format('%s'#$A#$D' var %s;',[JsStr,RP.Name]);
  160. case RF.FieldType.TypeKind of
  161. tkUnknown: ;
  162. tkInteger: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsInteger]);
  163. tkChar: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  164. tkEnumeration: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsInteger]);
  165. tkFloat: JsStr:=Format('%s'#$A#$D' %s=%f;',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsExtended]);
  166. tkString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  167. tkSet: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsInteger]);
  168. tkClass:{support later} JsStr:=Format('%s'#$A#$D' %s={};',[JsStr,RP.Name]);
  169. tkMethod: ;
  170. tkWChar: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  171. tkLString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  172. tkWString: JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  173. tkVariant: ;
  174. tkArray: ;
  175. tkRecord: ;
  176. tkInterface: ;
  177. tkInt64: JsStr:=Format('%s'#$A#$D' %s=%d;',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsInteger]);
  178. tkDynArray: ;
  179. tkUString: if not RP.GetValue(FProcessObject).IsObject then  JsStr:=Format('%s'#$A#$D' %s="%s";',[JsStr,RP.Name,RP.GetValue(FProcessObject).AsString]);
  180. tkClassRef: ;
  181. tkPointer: ;
  182. tkProcedure: ;
  183. end;
  184. end;
  185. if not CefRegisterExtension(RttiType.Name,JsStr,FJsHandle) then
  186. Raise Exception.Create('Register JavaScript Extension Error');
  187. end;
  188. { TVCLJsExtended.TNCJSHandle }
  189. constructor TVCLJsExtended.TNCJSHandle.Create(
  190.   Container: TVCLJsExtended);
  191. begin
  192.   inherited Create;
  193.   FContainer:=Container;
  194. end;
  195. function TVCLJsExtended.TNCJSHandle.Execute(const name: ustring;
  196.   const obj: ICefv8Value; const arguments: TCefv8ValueArray;
  197.   var retval: ICefv8Value; var exception: ustring): Boolean;
  198. var
  199.    RttiContext:TRttiContext;
  200.    rm:TRttiMember;
  201.    M:TRttiMethod;
  202.    F:TRttiField;
  203.    P:TRttiProperty;
  204.    A:TRttiArrayType;
  205.    nameType:TANameTYpe;
  206.    o:TObject;
  207.    n:string;
  208. function ObjectHaveName(const AObject:TObject; const name:String;out isMethod:TANameTYpe; out mb:TRttiMember):Boolean;
  209. var
  210. RttiType:TRttiType;
  211. RM:TRttiMethod;
  212. RP:TRttiProperty;
  213. RF:TRttiField;
  214. begin
  215. Result:=false;
  216. RttiType:=RttiContext.GetType(FContainer.FTypeInfo);
  217. for RM in RttiType.GetMethods do
  218. begin
  219. if CompareText(RM.Name,name)=0 then
  220. begin
  221. isMethod:=ntMethod;
  222. mb:=RM;
  223. Exit(True);
  224. end;
  225. end;
  226. for RP in RttiType.GetProperties do
  227. begin
  228. if CompareText(RP.Name,name)=0 then
  229. begin
  230. isMethod:=ntProperty;
  231. mb:=RP;
  232. Exit(True);
  233. end;
  234. end;
  235. for RF in RttiType.GetFields do
  236. begin
  237. if CompareText(RF.Name,name)=0 then
  238. begin
  239. isMethod:=ntField;
  240. mb:=RF;
  241. Exit(True);
  242. end;
  243. end;
  244. end;
  245. begin
  246. Result:=true;
  247. O:=FContainer.ProcessObject;
  248. n:=name;
  249. if not ObjectHaveName(O,name,nameType,rm) then
  250. begin
  251. exception:=csHaveNoThisMember;
  252. Exit(False);
  253. end;
  254. case nameType of
  255. ntMethod:
  256. begin
  257. M:=rm as TRttiMethod;
  258. //Assert(M.MethodKind<>mkFunction);
  259. if Length(M.GetParameters)>0 then
  260. begin
  261. if (Length(arguments)>0) and (Length(arguments)=Length(M.GetParameters)) then
  262. begin
  263. JsCallMethod(M,retval,arguments);
  264. end
  265. else
  266. begin
  267. exception:=csErrorParameters;
  268. Exit(False);
  269. end;
  270. end
  271. else
  272. begin
  273. JsCallMethod(M,retval);
  274. end;
  275. end;
  276. ntField:
  277. begin
  278. F:=rm as TRttiField;
  279. case F.FieldType.TypeKind of
  280. tkUnknown: ;
  281. tkInteger: retval:=TCefv8ValueRef.CreateInt(F.GetValue(FContainer.ProcessObject).AsInteger);
  282. tkChar: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  283. tkEnumeration: retval:=TCefv8ValueRef.CreateInt(F.GetValue(FContainer.ProcessObject).AsInteger);
  284. tkFloat: retval:=TCefv8ValueRef.CreateDouble(F.GetValue(FContainer.ProcessObject).AsExtended);
  285. tkString: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  286. tkSet: retval:=TCefv8ValueRef.CreateInt(F.GetValue(FContainer.ProcessObject).AsInteger);
  287. tkClass: ;//retval:=TCefv8ValueRef.CreateObject(F.GetValue(FContainer.ProcessObject).AsObject);
  288. tkMethod: ;
  289. tkWChar: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  290. tkLString: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  291. tkWString: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  292. tkVariant: ;
  293. tkArray:
  294. begin
  295. {
  296.                     retval:=TCefv8ValueRef.CreateArray;
  297.                     A:=F.FieldType as TRttiArrayType;
  298.                     //support only one demision array
  299.                     if A.DimensionCount=1 then
  300.                      for I := 0 to A.TotalElementCount do
  301.                      begin
  302.                        case A.ElementType.TypeKind of
  303.                          tkUnknown: retval.SetValueByIndex(I,TCefv8ValueRef.create());
  304.                          tkInteger: ;
  305.                          tkChar: ;
  306.                          tkEnumeration: ;
  307.                          tkFloat: ;
  308.                          tkString: ;
  309.                          tkSet: ;
  310.                          tkClass: ;
  311.                          tkMethod: ;
  312.                          tkWChar: ;
  313.                          tkLString: ;
  314.                          tkWString: ;
  315.                          tkVariant: ;
  316.                          tkArray: ;
  317.                          tkRecord: ;
  318.                          tkInterface: ;
  319.                          tkInt64: ;
  320.                          tkDynArray: ;
  321.                          tkUString: ;
  322.                          tkClassRef: ;
  323.                          tkPointer: ;
  324.                          tkProcedure: ;
  325.                        end;
  326.                        retval.SetValueByIndex(I,TCefv8ValueRef.create)
  327.                      end;
  328.                     retval.SetValueByIndex()
  329.                   end;;
  330.            tkRecord: ;
  331.            tkInterface: ;
  332.            tkInt64: retval:=TCefv8ValueRef.CreateInt(F.GetValue(FContainer.ProcessObject).AsInteger);
  333.            tkDynArray: ;
  334.            tkUString: retval:=TCefv8ValueRef.CreateString(F.GetValue(FContainer.ProcessObject).AsString);
  335.            tkClassRef: ;
  336.            tkPointer: retval:=TCefv8ValueRef.CreateInt(F.GetValue(FContainer.ProcessObject).AsInteger);
  337.            tkProcedure: ; }
  338. end;
  339. end;
  340. end;
  341. ntProperty:
  342. begin
  343. P:=rm as TRttiProperty;
  344. case P.PropertyType.TypeKind of
  345. tkUnknown: ;
  346. tkInteger: retval:=TCefv8ValueRef.CreateInt(p.GetValue(FContainer.ProcessObject).AsInteger);
  347. tkChar: retval:=TCefv8ValueRef.CreateString(p.GetValue(FContainer.ProcessObject).AsString);
  348. tkEnumeration: retval:=TCefv8ValueRef.CreateInt(p.GetValue(FContainer.ProcessObject).AsInteger);
  349. tkFloat: retval:=TCefv8ValueRef.CreateDouble(p.GetValue(FContainer.ProcessObject).AsExtended);
  350. tkString: retval:=TCefv8ValueRef.CreateString(p.GetValue(FContainer.ProcessObject).AsString);
  351. tkSet: retval:=TCefv8ValueRef.CreateInt(p.GetValue(FContainer.ProcessObject).AsInteger);
  352. tkClass: ;//retval:=TCefv8ValueRef.CreateObject(p.GetValue(FContainer.ProcessObject).AsObject);
  353. tkMethod: ;
  354. tkWChar: retval:=TCefv8ValueRef.CreateString(p.GetValue(FContainer.ProcessObject).AsString);
  355. tkLString: retval:=TCefv8ValueRef.CreateString(p.GetValue(FContainer.ProcessObject).AsString);
  356. tkWString: retval:=TCefv8ValueRef.CreateString(p.GetValue(FContainer.ProcessObject).AsString);
  357. tkVariant: ;
  358. tkArray:;
  359. end;
  360. end;
  361. end;
  362. end;
  363. procedure TVCLJsExtended.TNCJSHandle.JsCallMethod(Method: TRttiMethod;
  364. out ReturnVal: ICefv8Value; const Param: TCefv8ValueArray);
  365. var
  366. VA:array of TValue;
  367. I:Integer;
  368. rva:TValue;
  369. AInstance:TObject;
  370. begin
  371. if Param<>nil then
  372. begin
  373. SetLength(VA,Length(Param));
  374. for I := 0 to Length(Method.GetParameters)-1 do
  375. begin
  376. if Param[I].IsBool then
  377. VA[I]:=TValue.From<Boolean>(Param[I].GetBoolValue);
  378. if Param[I].IsInt then
  379. begin
  380. VA[I]:=TValue.From<Integer>(Param[I].GetIntValue);
  381. Continue;
  382. end;
  383. if Param[I].IsDouble then
  384. begin
  385. VA[I]:=TValue.From<Double>(Param[I].GetDoubleValue);
  386. Continue;
  387. end;
  388. if Param[I].IsString then
  389. VA[I]:=TValue.From<String>(Param[I].GetStringValue);
  390. if Param[I].IsObject then
  391. {VA[I].AsObject:=Param[I].get};
  392.       //if Param[I].is then
  393. end;
  394. end
  395. else
  396.       ;//VA:=nil;
  397. AInstance:=FContainer.ProcessObject;
  398. Rva:=Method.Invoke(AInstance,VA);
  399. case rva.Kind of
  400. tkUnknown: ;
  401. tkInteger: ReturnVal:=TCefv8ValueRef.CreateInt(rva.AsInteger);
  402. tkChar: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  403. tkEnumeration: ReturnVal:=TCefv8ValueRef.CreateInt(rva.AsOrdinal);
  404. tkFloat: ReturnVal:=TCefv8ValueRef.CreateDouble(rva.AsExtended);
  405. tkString: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  406. tkSet: ReturnVal:=TCefv8ValueRef.CreateInt(rva.AsInteger);
  407. tkClass: ;//ReturnVal:=TCefv8ValueRef.CreateObject(rva.AsObject);
  408. tkMethod: ;
  409. tkWChar: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  410. tkLString: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  411. tkWString: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  412. tkVariant: ;
  413. tkArray:;
  414. tkRecord: ;
  415. tkInterface: ;
  416. tkInt64: ReturnVal:=TCefv8ValueRef.CreateInt(rva.AsInteger);
  417. tkDynArray: ;
  418. tkUString: ReturnVal:=TCefv8ValueRef.CreateString(rva.AsString);
  419. tkClassRef: ;
  420. tkPointer: ;
  421. tkProcedure: ;
  422. end;
  423. end;
  424. procedure TVCLJsExtended.TNCJSHandle.JsCallMethod(Method: TRttiMethod;
  425. out ReturnVal: ICefv8Value);
  426. begin
  427. JsCallMethod(Method,ReturnVal,nil);
  428. end;
  429. function TVCLJsExtended.TNCJSHandle.MethodParamLength(Mn: string): Integer;
  430. var
  431. Rtx:TRttiContext;
  432. M:TRttiMethod;
  433. RT:TRttiType;
  434. begin
  435. RT:=Rtx.GetType(FContainer.FTypeInfo);
  436. M:=Rt.GetMethod(Mn);
  437. Result:=Length(M.GetParameters);
  438. end;
  439. {$M-}
  440. end.