2
0

webwidget.pas 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019-Now by Michael Van Canneyt, member of the
  4. Free Pascal development team
  5. WEB Widget Set
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit webwidget;
  13. {$mode objfpc}{$H+}
  14. interface
  15. uses
  16. Types, Classes, SysUtils, JS, Web;
  17. Const
  18. SElementData = 'wwElement';
  19. STopElementData = SElementData+'Top';
  20. SContentElementData = SElementData+'Content';
  21. SElementClass = 'wwClass';
  22. sEventAbort = 'abort';
  23. SEventAnimationCancel = 'animationcancel';
  24. SEventAnimationEnd = 'animationend';
  25. SEventAnimationIteration = 'animationiteration';
  26. SEventAnimationStart = 'animationstart';
  27. sEventAuxClick = 'auxclick';
  28. sEventBlur = 'blur';
  29. SEventCancel = 'cancel';
  30. SEventCanPlay = 'canplay';
  31. SEventCanPlayThrough = 'canplaythrough';
  32. SEventChange = 'change';
  33. sEventClick = 'click';
  34. sEventCompositionEnd = 'compositionend';
  35. sEventCompositionStart = 'compositionstart';
  36. sEventCompositionUpdate = 'compositionupdate';
  37. sEventContextMenu = 'contextmenu';
  38. sEventCopy = 'copy';
  39. sEventCut = 'cut';
  40. sEventCueChange = 'cuechange';
  41. sEventDblClick = 'dblclick';
  42. sEventDurationChange = 'durationchange';
  43. sEventEnded = 'ended';
  44. sEventError = 'error';
  45. sEventFocus = 'focus';
  46. sEventFocusIn = 'focusin';
  47. sEventFocusOut = 'focusout';
  48. SEventGotPointerCapture = 'gotpointercapture';
  49. SEventInput = 'input';
  50. SEventInvalid = 'invalid';
  51. sEventKeyDown = 'keydown';
  52. sEventKeyPress = 'keypress';
  53. sEventKeyUp = 'keyup';
  54. sEventLoad = 'load';
  55. sEventLoadedData = 'loadeddata';
  56. sEventLoadedMetaData = 'loadedmetadata';
  57. sEventLoadend = 'loadend';
  58. sEventLoadStart = 'loadstart';
  59. SEventLostPointerCapture = 'lostpointercapture';
  60. sEventMouseDown = 'mousedown';
  61. sEventMouseEnter = 'mouseenter';
  62. sEventMouseLeave = 'mouseleave';
  63. sEventMouseMove = 'mousemove';
  64. sEventMouseOut = 'mouseout';
  65. sEventMouseUp = 'mouseup';
  66. sEventOverFlow = 'overflow';
  67. sEventPaste = 'paste';
  68. sEventPause = 'pause';
  69. sEventPlay = 'play';
  70. SEventPointerCancel = 'pointercancel';
  71. SEventPointerDown = 'pointerdown';
  72. SEventPointerEnter = 'pointerenter';
  73. SEventPointerLeave = 'pointerleave';
  74. SEventPointerMove = 'pointermove';
  75. SEventPointerOut = 'pointerout';
  76. SEventPointerOver = 'pointerover';
  77. SEventPointerUp = 'pointerup';
  78. sEventReset = 'reset';
  79. sEventResize = 'resize';
  80. sEventScroll = 'scroll';
  81. sEventSelect = 'select';
  82. sEventSubmit = 'submit';
  83. sEventTouchStart = 'touchstart';
  84. SEventTransitionCancel = 'transitioncancel';
  85. SEventTransitionEnd = 'transitionend';
  86. SEventTransitionRun = 'transitionrun';
  87. SEventTransitionStart = 'transitionstart';
  88. SEventWheel = 'wheel';
  89. Type
  90. EWidgets = Class(Exception);
  91. TCustomWebWidget = Class;
  92. THTMLNotifyEvent = Procedure (Sender : TObject; Event : TJSEvent) of object;
  93. TEventDispatch = Record
  94. MsgStr : String;
  95. HTMLEvent : TJSEvent;
  96. EventHandler : THTMLNotifyEvent;
  97. end;
  98. { TStyleItem }
  99. TStylePriority = (spNone,spImportant);
  100. TStyleItem = Class(TCollectionItem)
  101. private
  102. FPriority: TStylePriority;
  103. FName: String;
  104. FValue: String;
  105. FImported : Boolean;
  106. procedure SetPriority(AValue: TStylePriority);
  107. procedure SetValue(AValue: String);
  108. procedure SetName(AValue: String);
  109. Protected
  110. procedure MarkDirty;
  111. Public
  112. Property Imported : Boolean read FImported;
  113. Procedure Assign(Source : TPersistent) ; override;
  114. Published
  115. Property Name : String Read FName Write SetName;
  116. Property Value : String Read FValue Write SetValue;
  117. Property Priority : TStylePriority Read FPriority Write SetPriority;
  118. end;
  119. { TWebWidgetStyles }
  120. TWebWidgetStyles = Class(TOwnedCollection)
  121. private
  122. Function GetStyleItem(aIndex : Integer): TStyleItem;
  123. procedure SetStyleItem(aIndex : Integer; AValue: TStyleItem);
  124. Protected
  125. Procedure MarkDirty(aItem : TStyleItem);
  126. Procedure ApplyToDOM(aElement : TJSHTMlElement;aItem : TStyleItem); virtual; overload;
  127. Public
  128. Function Widget : TCustomWebWidget;
  129. // Manipulate
  130. Function Add(Const aName : String; const aValue : String= '') : TStyleItem; overload;
  131. Function EnsureStyle(Const aName : String; const aValue : String= '') : TStyleItem;
  132. Function IndexOfStyle(Const aName : String) : integer;
  133. Function FindStyle(Const aName : String) : TStyleItem;
  134. Function GetStyle(Const aName : String) : TStyleItem;
  135. Function RemoveStyle(Const aName : String) : String;
  136. Procedure RefreshFromDOM(aElement : TJSHTMlElement = Nil;DoClear : Boolean = True);virtual;
  137. Procedure ClearImported;
  138. Procedure ApplyToDOM(aElement : TJSHTMlElement = Nil); virtual; overload;
  139. Property Styles[aIndex : Integer] : TStyleItem Read GetStyleItem Write SetStyleItem; default;
  140. end;
  141. TStyleRefresh = (srOnElementID, // Only refresh styles if ElementID was set and we bind to existing element.
  142. srAlways, // Always refresh styles
  143. srNever); // Never refresh
  144. TStyleRefreshes = Set of TStyleRefresh;
  145. { TReferenceItem }
  146. TJSHTMLElementArray = Array of TJSHTMLElement;
  147. TReferenceItem = Class(TCollectionItem)
  148. private
  149. FName: String;
  150. FSelector: String;
  151. procedure SetInputValidity(AValue: String);
  152. procedure SetName(AValue: String);
  153. procedure SetSelector(AValue: String);
  154. function GetElement: TJSHTMLElement;
  155. function GetElements: TJSHTMLElementArray;
  156. Protected
  157. procedure SetInputValue(AValue: String); virtual;
  158. Function GetInputValue : String; virtual;
  159. Procedure MarkDirty; virtual;
  160. Public
  161. Procedure Refresh;
  162. Function Exists : Boolean;
  163. Function IsArray : Boolean;
  164. Function IsInput : Boolean;
  165. Property Element : TJSHTMLElement Read GetElement;
  166. Property Elements : TJSHTMLElementArray Read GetElements;
  167. Property InputValue : String Read GetInputValue Write SetInputValue;
  168. Property InputValidity : String Write SetInputValidity;
  169. Published
  170. Property Selector : String Read FSelector Write SetSelector;
  171. Property Name : String Read FName Write SetName;
  172. end;
  173. { TWebWidgetReferences }
  174. TWebWidgetReferences = Class(TOwnedCollection)
  175. Private
  176. FRefs : TJSObject; // Arrays of elements, even for single element
  177. function GetReferenceItem(aIndex : Integer): TReferenceItem;
  178. procedure SetReferenceItem(aIndex : Integer; AValue: TReferenceItem);
  179. Protected
  180. Procedure MarkDirty(aItem : TReferenceItem);
  181. Procedure RefreshFromDOM(aItem : TReferenceItem;aElement : TJSHTMlElement);
  182. Property Refs : TJSObject Read FRefs;
  183. Public
  184. Function Widget : TCustomWebWidget;
  185. // Manipulate
  186. Function Add(Const aName : String; aSelector : String = '') : TReferenceItem; overload;
  187. Function EnsureReference(Const aName : String; Const aSelector : String = '') : TReferenceItem;
  188. Function IndexOfReference(Const aName : String) : Integer;
  189. Function FindReference(Const aName : String) : TReferenceItem;
  190. Function GetReference(Const aName : String) : TReferenceItem;
  191. Procedure RemoveReference(Const aName : String);
  192. Function ElementExists(Const aName : String) : Boolean;
  193. Function ElementIsArray(Const aName : String) : Boolean;
  194. Function FindElementByName(Const aName : String) : TJSHTMLElement;
  195. Function GetElementByName(Const aName : String) : TJSHTMLElement;
  196. Function GetElementsByName(Const aName : String) : TJSHTMLElementArray;
  197. Procedure RefreshFromDOM(aElement : TJSHTMlElement = Nil);virtual;
  198. Property Items[aIndex : Integer] : TReferenceItem Read GetReferenceItem Write SetReferenceItem;
  199. Property References[aName : String] : TReferenceItem Read GetReference; default;
  200. end;
  201. {$DispatchStrField name}
  202. { TCustomWebWidget }
  203. TCustomWebWidget = Class(TComponent)
  204. Private
  205. const MaxEvents = 66;
  206. Class Var WidgetID : NativeInt;
  207. Const FEventNames : Array[0..MaxEvents] of String = (
  208. // When adding, only add at the end !!
  209. sEventAbort, //0
  210. SEventAnimationCancel,
  211. SEventAnimationEnd,
  212. SEventAnimationIteration,
  213. SEventAnimationStart,
  214. sEventAuxClick ,
  215. sEventBlur ,
  216. SEventCancel ,
  217. SEventCanPlay ,
  218. SEventCanPlayThrough ,
  219. SEventChange , // 10
  220. sEventClick ,
  221. sEventCompositionEnd ,
  222. sEventCompositionStart ,
  223. sEventCompositionUpdate ,
  224. sEventContextMenu ,
  225. sEventCopy ,
  226. sEventCut ,
  227. sEventCueChange ,
  228. sEventDblClick ,
  229. sEventDurationChange , // 20
  230. sEventEnded ,
  231. sEventError ,
  232. sEventFocus ,
  233. sEventFocusIn ,
  234. sEventFocusOut ,
  235. SEventGotPointerCapture ,
  236. SEventInput ,
  237. SEventInvalid ,
  238. sEventKeyDown ,
  239. sEventKeyPress , // 30
  240. sEventKeyUp ,
  241. sEventLoad ,
  242. sEventLoadedData ,
  243. sEventLoadedMetaData ,
  244. sEventLoadend ,
  245. sEventLoadStart ,
  246. SEventLostPointerCapture ,
  247. sEventMouseDown ,
  248. sEventMouseEnter ,
  249. sEventMouseLeave , // 40
  250. sEventMouseMove ,
  251. sEventMouseOut ,
  252. sEventMouseUp ,
  253. sEventOverFlow ,
  254. sEventPaste ,
  255. sEventPause ,
  256. sEventPlay ,
  257. SEventPointerCancel ,
  258. SEventPointerDown ,
  259. SEventPointerEnter ,
  260. SEventPointerLeave ,
  261. SEventPointerMove ,
  262. SEventPointerOut ,
  263. SEventPointerOver ,
  264. SEventPointerUp ,
  265. sEventReset ,
  266. sEventResize ,
  267. sEventScroll ,
  268. sEventSelect ,
  269. sEventSubmit ,
  270. sEventTouchStart ,
  271. SEventTransitionCancel ,
  272. SEventTransitionEnd ,
  273. SEventTransitionRun ,
  274. SEventTransitionStart ,
  275. SEventWheel
  276. );
  277. private
  278. FAfterRenderHTML: TNotifyEvent;
  279. FAfterUnRenderHTML: TNotifyEvent;
  280. FBeforeRenderHTML: TNotifyEvent;
  281. FBeforeUnRenderHTML: TNotifyEvent;
  282. FParent : TCustomWebWidget;
  283. FMyHook : TJSRawEventHandler;
  284. // Set by setting ParentID or Parent
  285. FParentElement : TJSHTMLElement;
  286. FElement : TJSHTMLElement;
  287. FOwnsElement : Boolean;
  288. FParentID : String;
  289. FElementID: String;
  290. FChildren : TJSArray;
  291. FClasses : String;
  292. FMyEvents : TJSObject;
  293. FStyleRefresh: TStyleRefresh;
  294. FStyles: TWebWidgetStyles;
  295. FVisible : Boolean;
  296. FDisplay : String;
  297. FReferences : TWebWidgetReferences;
  298. FAttrs : TJSObject;
  299. function GetChildCount: Integer;
  300. function GetChild(aIndex : Integer): TCustomWebWidget;
  301. function GetClasses: String;
  302. function GetDataset(aName : String): String;
  303. function GetElement: TJSHTMLELement;
  304. function GetExternalElement: Boolean;
  305. function GetHaveReferences: Boolean;
  306. function GetHTMLEvent(AIndex: Integer): THTMLNotifyEvent;
  307. function GetIsElementDirty: Boolean;
  308. function GetParent: TCustomWebWidget;
  309. function GetParentElement: TJSHTMLELement;
  310. function GetParentID: String;
  311. function GetElementID: String;
  312. function GetReference(const aName : string): TJSHTMLElement;
  313. function GetReferenceItem(aName : String): TReferenceItem;
  314. function GetReferenceList(const aName : string): TJSHTMLElementArray;
  315. function GetReferences: TWebWidgetReferences;
  316. function GetRendered: Boolean;
  317. function GetVisible: Boolean;
  318. procedure SetClasses(AValue: String);
  319. procedure SetDataset(aName : String; AValue: String);
  320. procedure SetElementID(AValue: String);
  321. procedure SetHTMLEvent(AIndex: Integer; AValue: THTMLNotifyEvent);
  322. procedure SetParent(AValue: TCustomWebWidget);
  323. procedure SetParentID(AValue: String);
  324. Procedure AddChild(aValue : TCustomWebWidget);
  325. Procedure RemoveChild(aValue : TCustomWebWidget);
  326. procedure SetReferences(AValue: TWebWidgetReferences);
  327. procedure SetStyles(AValue: TWebWidgetStyles);
  328. procedure SetVisible(AValue: Boolean);
  329. procedure SetAttr(const aName : string; AValue: String);
  330. Function GetAttr(const aName : String) : String;
  331. // This protected section is not meant to be made public
  332. Protected
  333. // Events mechanism
  334. procedure EventEntry(aEvent: TJSEvent); virtual;
  335. // Low level
  336. procedure RemoveEvent(aElement: TJSHTMLElement; const aEvent: String);
  337. procedure HookupEvent(aElement: TJSHTMLElement; const aEvent: String);
  338. Procedure HookupEvents(aElement : TJSHTMLElement); virtual;
  339. // Add to internal list, if rendered, calls hookup
  340. Procedure AddEvent(aName : String; AHandler : THTMLNotifyEvent);
  341. // Remove from internal list, if rendered, calls RemoveEvent
  342. Procedure DeleteEvent(aName : String);
  343. // Override these if you want somehow to grab a fixed element on a page.
  344. Class Function FixedParent : TJSHTMLElement; virtual;
  345. Class Function DefaultParentElement : TJSHTMLElement; virtual;
  346. Class Function DefaultParent : TCustomWebWidget; virtual;
  347. Class Function FixedElement : TJSHTMLElement; virtual;
  348. // Generate an ID
  349. Class function GenerateID: String;
  350. // Find element in DOM tree.
  351. Class Function FindElement(aID : String) : TJSHTMLElement;
  352. // Create element in DOM tree, set ID if it is nonzero
  353. Class function CreateElement (aTag : String; aID : String) : TJSHTMLElement;
  354. // references are relative to this element. By default, this is the element of the widget.
  355. // override if you want for instance to indicate the parent element.
  356. function GetReferenceElement: TJSHTMLELement; virtual;
  357. // override if you want content to go in this sub-element instead of directly below the toplevel element.
  358. function GetContentElement: TJSHTMLELement; virtual;
  359. // Override this if Element is not the top element of this widget.
  360. function GetTopElement: TJSHTMLELement; virtual;
  361. // Auxiliary function to create a displayable name of this widget
  362. Function DisplayElementName : String;
  363. // Make sure there is an element.
  364. function EnsureElement: TJSHTMLElement;
  365. // Set parent element to nil. No rendering is done. Can be called when there are no DOM elements
  366. Procedure InvalidateParentElement;
  367. // Set element to nil, clears styles and references. Can be called when there are no DOM elements
  368. Procedure InvalidateElement; virtual;
  369. // Name of the tag to create. Set to '' if you don't want RenderHTML to create one.
  370. Function HTMLTag : String; virtual; abstract;
  371. // Class names that must always be applied for this widget to work.
  372. // They are only added during render, and do not show up in classes property.
  373. // e.g. for a bootstrap button widget, this would return "btn"
  374. Function WidgetClasses : String; virtual;
  375. // Override this if you want to create custom styles collection
  376. Function CreateStyles : TWebWidgetStyles; virtual;
  377. // Override this if you want to create custom references
  378. Function CreateReferences : TWebWidgetReferences; virtual;
  379. // Forces apply of visible, sets Visible property
  380. procedure ApplyVisible(aElement : TJSHTMLElement; AValue: Boolean); virtual;
  381. // Here all properties from the widget are applied to the element.
  382. // This is called during RenderHTML, but also when binding ElementID to an Element.
  383. Procedure ApplyWidgetSettings(aElement : TJSHTMLElement); virtual;
  384. {
  385. Actually create & render element.
  386. This gets the element as created by RenderHTML and the parent as received by RenderHTML.
  387. If aElement is nil, the DoRenderHTML is responsible for creating & attaching it to the parent element.
  388. Must return the value for Element.
  389. }
  390. Function DoRenderHTML(aParent,aElement : TJSHTMLElement) :TJSHTMLElement; virtual;
  391. // Apply data to Element, Top and Content. Can only be called when the 3 are set, i.e. after RenderHTML or when Element is set from ElementID.
  392. Procedure ApplyData; virtual;
  393. Procedure RemoveData; virtual;
  394. // Update references
  395. Procedure RefreshReferences; virtual;
  396. // Create html. Creates element below parent, and renders HTML using doRenderHTML
  397. Function RenderHTML(aParent : TJSHTMLELement) : TJSHTMLElement;
  398. // Override this if you need to do additional actions besides removing top element from parent. Parent is always assigned
  399. Procedure DoUnRender(aParent : TJSHTMLElement) ; virtual;
  400. // Remove HTML, if any. aParent can be nil.
  401. Procedure UnRender(aParent : TJSHTMLElement); overload;
  402. // Dispatch an event
  403. Function DispatchEvent(aName : String; aEvent : TJSEvent = Nil) : Boolean;
  404. // the rendered or attached element if ElementID was set. Can be Nil;
  405. // This is the "main" widget of the rendered HTML. There can be HTML below or HTML before.
  406. Property Element : TJSHTMLELement Read GetElement;
  407. // The attached parent element. Obtained through Parent or ParentID. Can be Nil;
  408. // Not necessarily the parent element of Element, but definitely the parent of TopElement;
  409. Property ParentElement : TJSHTMLELement Read GetParentElement;
  410. // Content Element. By default equals Element.
  411. Property ContentElement : TJSHTMLELement Read GetContentElement;
  412. // Top Element. The parent element is the direct parent of this element.
  413. Property TopElement : TJSHTMLELement Read GetTopElement;
  414. // Is true if this class created the element (i.e. it was not obtained with ElementID)
  415. Property OwnsElement : Boolean Read FOwnsElement;
  416. // My Events
  417. Property MyEvents : TJSObject Read FMyEvents;
  418. // Return true if the ElementID is referring to an existing element.
  419. Property ExternalElement : Boolean Read GetExternalElement;
  420. // since reading references creates the collection, we want a way to see if there are any without creating them.
  421. Property HaveReferences : Boolean Read GetHaveReferences;
  422. // Property attrs
  423. Property StoredAttrs : TJSObject Read FAttrs;
  424. Public
  425. Constructor Create(aOwner : TComponent); override;
  426. Destructor Destroy; override;
  427. // Does this element allow childern ?
  428. Class Function AllowChildren : Boolean; virtual;
  429. // Manipulate Classes
  430. Class Function RemoveClasses(const Source, aClasses : String; Normalize : Boolean = false) : String;
  431. Class Function RemoveClasses(el : TJSHTMLElement; const aClasses : String; Normalize : Boolean = false) : String;
  432. Class Function AddClasses(const Source, aClasses : String; Normalize : Boolean = false) : String;
  433. Class Function AddClasses(el : TJSHTMLElement; const aClasses : String; Normalize : Boolean = false) : String;
  434. // Manipulate styles
  435. function EnsureStyle(const aName: String): TStyleItem;
  436. function AddStyle(const aName,aValue: String): TStyleItem;
  437. function GetStyleValue(const aName : String) : String;
  438. function RemoveStyle(const aName: String): String;
  439. // Remove data from dataset
  440. Procedure RemoveData(const aName : String);
  441. // Set attributes
  442. // Re-render
  443. Procedure Refresh;
  444. // Unrender
  445. Procedure Unrender; overload;
  446. // These work on the classes property, and on the current element if rendered. Returns the new value of classes.
  447. Function RemoveClasses(const aClasses : String; Normalize : Boolean = false) : String;
  448. Function AddClasses(const aClasses : String; Normalize : Boolean = false) : String;
  449. // Finding widgets
  450. Function FindWidgetByID(aElementID : String; Recurse : Boolean = True) : TCustomWebWidget;
  451. Function GetWidgetByID(aElementID : String; Recurse : Boolean = True) : TCustomWebWidget;
  452. // For complex HTML, this is the toplevel element
  453. Property Parent : TCustomWebWidget Read GetParent Write SetParent;
  454. // Are we rendered, i.e. is Element valid ?
  455. Property IsRendered : Boolean Read GetRendered;
  456. // Do we need to refresh our internal properties from the element? Currently true if rendered.
  457. // Use this when reading properties and you want/need to refresh a property from the element.
  458. Property IsElementDirty : Boolean Read GetIsElementDirty;
  459. // Child widgets. Note that this can differ significantly from
  460. Property ChildCount : Integer Read GetChildCount;
  461. Property Children [aIndex : Integer] : TCustomWebWidget Read GetChild;
  462. Property Data[aName : String] : String Read GetDataset Write SetDataset;
  463. // This works with style Display: none.
  464. Property Visible : Boolean Read GetVisible Write SetVisible;
  465. // This protected section can be published in descendents
  466. Protected
  467. // Parent or Element ID: Will be used when determining the HTML element when rendering.
  468. // Only one of the Parent or Element ID can be set.
  469. Property ParentID : String Read GetParentID Write SetParentID;
  470. Property ElementID : String Read GetElementID Write SetElementID;
  471. // When reading, returns the actual classes if rendered.
  472. // When rendering, these classes are added to any existing ones if the element exists.
  473. Property Classes : String Read GetClasses Write SetClasses;
  474. // Apply these styles when rendering. Depending on StyleRefresh, styles are imported from actual element.
  475. Property Styles: TWebWidgetStyles Read FStyles Write SetStyles;
  476. // When rendering, should we refresh styles ?
  477. Property StyleRefresh : TStyleRefresh Read FStyleRefresh Write FStyleRefresh;
  478. // Possible references to sub widgets, based on CSS selectors
  479. Property References : TWebWidgetReferences Read GetReferences write SetReferences;
  480. // Direct named acces
  481. Property Reference[aName : String] : TReferenceItem Read GetReferenceItem;
  482. // Easy access to an element
  483. Property Elements[const aName : string] : TJSHTMLElement Read GetReference;
  484. // Easy access to an element list
  485. Property ElementList[const aName : string] : TJSHTMLElementArray Read GetReferenceList;
  486. // Easy access to attributed
  487. Property Attrs[const aName : string] : String Read GetAttr Write SetAttr;
  488. // Events of TWebWidget
  489. Property BeforeRenderHTML : TNotifyEvent Read FBeforeRenderHTML Write FBeforeRenderHTML;
  490. Property AfterRenderHTML : TNotifyEvent Read FAfterRenderHTML Write FAfterRenderHTML;
  491. Property BeforeUnRenderHTML : TNotifyEvent Read FBeforeUnRenderHTML Write FBeforeUnRenderHTML;
  492. Property AfterUnRenderHTML : TNotifyEvent Read FAfterUnRenderHTML Write FAfterUnRenderHTML;
  493. // HTML DOM events
  494. Property OnAbort: THTMLNotifyEvent Index 0 Read GetHTMLEvent Write SetHTMLEvent;
  495. Property OnAnimationCancel: THTMLNotifyEvent Index 1 Read GetHTMLEvent Write SetHTMLEvent;
  496. Property OnAnimationEnd: THTMLNotifyEvent Index 2 Read GetHTMLEvent Write SetHTMLEvent;
  497. Property OnAnimationIteration: THTMLNotifyEvent Index 3 Read GetHTMLEvent Write SetHTMLEvent;
  498. Property OnAnimationStart: THTMLNotifyEvent Index 4 Read GetHTMLEvent Write SetHTMLEvent;
  499. Property OnAuxClick : THTMLNotifyEvent Index 5 Read GetHTMLEvent Write SetHTMLEvent;
  500. Property OnBlur : THTMLNotifyEvent Index 6 Read GetHTMLEvent Write SetHTMLEvent;
  501. Property OnCancel : THTMLNotifyEvent Index 7 Read GetHTMLEvent Write SetHTMLEvent;
  502. Property OnCanPlay : THTMLNotifyEvent Index 8 Read GetHTMLEvent Write SetHTMLEvent;
  503. Property OnCanPlayThrough : THTMLNotifyEvent Index 9 Read GetHTMLEvent Write SetHTMLEvent;
  504. Property OnChange : THTMLNotifyEvent Index 10 Read GetHTMLEvent Write SetHTMLEvent;
  505. Property OnClick : THTMLNotifyEvent Index 11 Read GetHTMLEvent Write SetHTMLEvent;
  506. Property OnCompositionEnd : THTMLNotifyEvent Index 12 Read GetHTMLEvent Write SetHTMLEvent;
  507. Property OnCompositionStart : THTMLNotifyEvent Index 13 Read GetHTMLEvent Write SetHTMLEvent;
  508. Property OnCompositionUpdate : THTMLNotifyEvent Index 14 Read GetHTMLEvent Write SetHTMLEvent;
  509. Property OnContextMenu : THTMLNotifyEvent Index 15 Read GetHTMLEvent Write SetHTMLEvent;
  510. Property OnCopy : THTMLNotifyEvent Index 16 Read GetHTMLEvent Write SetHTMLEvent;
  511. Property OnCut : THTMLNotifyEvent Index 17 Read GetHTMLEvent Write SetHTMLEvent;
  512. Property OnCueChange : THTMLNotifyEvent Index 18 Read GetHTMLEvent Write SetHTMLEvent;
  513. Property OnDblClick : THTMLNotifyEvent Index 19 Read GetHTMLEvent Write SetHTMLEvent;
  514. Property OnDurationChange : THTMLNotifyEvent Index 20 Read GetHTMLEvent Write SetHTMLEvent;
  515. Property OnEnded : THTMLNotifyEvent Index 21 Read GetHTMLEvent Write SetHTMLEvent;
  516. Property OnError : THTMLNotifyEvent Index 22 Read GetHTMLEvent Write SetHTMLEvent;
  517. Property OnFocus : THTMLNotifyEvent Index 23 Read GetHTMLEvent Write SetHTMLEvent;
  518. Property OnFocusIn : THTMLNotifyEvent Index 24 Read GetHTMLEvent Write SetHTMLEvent;
  519. Property OnFocusOut : THTMLNotifyEvent Index 25 Read GetHTMLEvent Write SetHTMLEvent;
  520. Property OnGotPointerCapture : THTMLNotifyEvent Index 26 Read GetHTMLEvent Write SetHTMLEvent;
  521. Property OnInput : THTMLNotifyEvent Index 27 Read GetHTMLEvent Write SetHTMLEvent;
  522. Property OnInvalid : THTMLNotifyEvent Index 28 Read GetHTMLEvent Write SetHTMLEvent;
  523. Property OnKeyDown : THTMLNotifyEvent Index 29 Read GetHTMLEvent Write SetHTMLEvent;
  524. Property OnKeyPress : THTMLNotifyEvent Index 30 Read GetHTMLEvent Write SetHTMLEvent;
  525. Property OnKeyUp : THTMLNotifyEvent Index 31 Read GetHTMLEvent Write SetHTMLEvent;
  526. Property OnLoad : THTMLNotifyEvent Index 32 Read GetHTMLEvent Write SetHTMLEvent;
  527. Property OnLoadedData : THTMLNotifyEvent Index 33 Read GetHTMLEvent Write SetHTMLEvent;
  528. Property OnLoadedMetaData : THTMLNotifyEvent Index 34 Read GetHTMLEvent Write SetHTMLEvent;
  529. Property OnLoadend : THTMLNotifyEvent Index 35 Read GetHTMLEvent Write SetHTMLEvent;
  530. Property OnLoadStart : THTMLNotifyEvent Index 36 Read GetHTMLEvent Write SetHTMLEvent;
  531. Property OnLostPointerCapture : THTMLNotifyEvent Index 37 Read GetHTMLEvent Write SetHTMLEvent;
  532. Property OnMouseDown : THTMLNotifyEvent Index 38 Read GetHTMLEvent Write SetHTMLEvent;
  533. Property OnMouseEnter : THTMLNotifyEvent Index 39 Read GetHTMLEvent Write SetHTMLEvent;
  534. Property OnMouseLeave : THTMLNotifyEvent Index 40 Read GetHTMLEvent Write SetHTMLEvent;
  535. Property OnMouseMove : THTMLNotifyEvent Index 41 Read GetHTMLEvent Write SetHTMLEvent;
  536. Property OnMouseOut : THTMLNotifyEvent Index 42 Read GetHTMLEvent Write SetHTMLEvent;
  537. Property OnMouseUp : THTMLNotifyEvent Index 43 Read GetHTMLEvent Write SetHTMLEvent;
  538. Property OnOverFlow : THTMLNotifyEvent Index 44 Read GetHTMLEvent Write SetHTMLEvent;
  539. Property OnPaste : THTMLNotifyEvent Index 45 Read GetHTMLEvent Write SetHTMLEvent;
  540. Property OnPause : THTMLNotifyEvent Index 46 Read GetHTMLEvent Write SetHTMLEvent;
  541. Property OnPlay : THTMLNotifyEvent Index 47 Read GetHTMLEvent Write SetHTMLEvent;
  542. Property OnPointerCancel : THTMLNotifyEvent Index 48 Read GetHTMLEvent Write SetHTMLEvent;
  543. Property OnPointerDown : THTMLNotifyEvent Index 49 Read GetHTMLEvent Write SetHTMLEvent;
  544. Property OnPointerEnter : THTMLNotifyEvent Index 50 Read GetHTMLEvent Write SetHTMLEvent;
  545. Property OnPointerLeave : THTMLNotifyEvent Index 51 Read GetHTMLEvent Write SetHTMLEvent;
  546. Property OnPointerMove : THTMLNotifyEvent Index 52 Read GetHTMLEvent Write SetHTMLEvent;
  547. Property OnPointerOut : THTMLNotifyEvent Index 53 Read GetHTMLEvent Write SetHTMLEvent;
  548. Property OnPointerOver : THTMLNotifyEvent Index 54 Read GetHTMLEvent Write SetHTMLEvent;
  549. Property OnPointerUp : THTMLNotifyEvent Index 55 Read GetHTMLEvent Write SetHTMLEvent;
  550. Property OnReset : THTMLNotifyEvent Index 56 Read GetHTMLEvent Write SetHTMLEvent;
  551. Property OnResize : THTMLNotifyEvent Index 57 Read GetHTMLEvent Write SetHTMLEvent;
  552. Property OnScroll : THTMLNotifyEvent Index 58 Read GetHTMLEvent Write SetHTMLEvent;
  553. Property OnSelect : THTMLNotifyEvent Index 59 Read GetHTMLEvent Write SetHTMLEvent;
  554. Property OnSubmit : THTMLNotifyEvent Index 60 Read GetHTMLEvent Write SetHTMLEvent;
  555. Property OnTouchStart : THTMLNotifyEvent Index 61 Read GetHTMLEvent Write SetHTMLEvent;
  556. Property OnTransitionCancel : THTMLNotifyEvent Index 62 Read GetHTMLEvent Write SetHTMLEvent;
  557. Property OnTransitionEnd : THTMLNotifyEvent Index 63 Read GetHTMLEvent Write SetHTMLEvent;
  558. Property OnTransitionRun : THTMLNotifyEvent Index 64 Read GetHTMLEvent Write SetHTMLEvent;
  559. Property OnTransitionStart : THTMLNotifyEvent Index 65 Read GetHTMLEvent Write SetHTMLEvent;
  560. Property OnWheel : THTMLNotifyEvent Index 66 Read GetHTMLEvent Write SetHTMLEvent;
  561. end;
  562. TCustomWebWidgetClass = Class of TCustomWebWidget;
  563. { TWebWidget }
  564. TWebWidget = Class(TCustomWebWidget)
  565. Published
  566. // Properties
  567. Property ParentID;
  568. Property ElementID;
  569. Property Classes;
  570. Property Styles;
  571. Property StyleRefresh;
  572. Property Visible;
  573. // Events
  574. Property BeforeRenderHTML;
  575. Property AfterRenderHTML;
  576. Property OnAbort;
  577. Property OnAnimationCancel;
  578. Property OnAnimationEnd;
  579. Property OnAnimationIteration;
  580. Property OnAnimationStart;
  581. Property OnAuxClick;
  582. Property OnBlur;
  583. Property OnCancel;
  584. Property OnCanPlay;
  585. Property OnCanPlayThrough;
  586. Property OnChange;
  587. Property OnClick;
  588. Property OnCompositionEnd;
  589. Property OnCompositionStart;
  590. Property OnCompositionUpdate;
  591. Property OnContextMenu;
  592. Property OnCopy;
  593. Property OnCut;
  594. Property OnCueChange;
  595. Property OnDblClick;
  596. Property OnDurationChange;
  597. Property OnEnded ;
  598. Property OnError ;
  599. Property OnFocus;
  600. Property OnFocusIn ;
  601. Property OnFocusOut ;
  602. Property OnGotPointerCapture;
  603. Property OnInput;
  604. Property OnInvalid;
  605. Property OnKeyDown;
  606. Property OnKeyPress;
  607. Property OnKeyUp;
  608. Property OnLoad;
  609. Property OnLoadedData;
  610. Property OnLoadedMetaData;
  611. Property OnLoadend;
  612. Property OnLoadStart;
  613. Property OnLostPointerCapture;
  614. Property OnMouseDown;
  615. Property OnMouseEnter;
  616. Property OnMouseLeave;
  617. Property OnMouseMove;
  618. Property OnMouseOut;
  619. Property OnMouseUp;
  620. Property OnOverFlow;
  621. Property OnPaste;
  622. Property OnPause;
  623. Property OnPlay;
  624. Property OnPointerCancel;
  625. Property OnPointerDown;
  626. Property OnPointerEnter;
  627. Property OnPointerLeave;
  628. Property OnPointerMove;
  629. Property OnPointerOut;
  630. Property OnPointerOver;
  631. Property OnPointerUp;
  632. Property OnReset;
  633. Property OnResize;
  634. Property OnScroll;
  635. Property OnSelect;
  636. Property OnSubmit;
  637. Property OnTouchStart;
  638. Property OnTransitionCancel;
  639. Property OnTransitionEnd;
  640. Property OnTransitionRun;
  641. Property OnTransitionStart;
  642. Property OnWheel;
  643. end;
  644. TWebWidgetClass = Class of TWebWidget;
  645. { TContainerWidget }
  646. TContainerWidget = Class(TWebWidget)
  647. private
  648. const KnownStyleCount = 6;
  649. Const KnownStyles : Array[0..KnownStyleCount] of string = ('min-width','max-width','min-height','max-height','display','width','height');
  650. function GetKnownStyle(AIndex: Integer): String;
  651. procedure SetKnownStyle(AIndex: Integer; AValue: String);
  652. Public
  653. Function HTMLTag : String; override;
  654. Constructor Create(aOwner : TComponent); override;
  655. Property MinWidth : String Index 0 Read GetKnownStyle Write SetKnownStyle;
  656. Property MaxWidth : String Index 1 Read GetKnownStyle Write SetKnownStyle;
  657. Property MinHeight : String Index 2 Read GetKnownStyle Write SetKnownStyle;
  658. Property MaxHeight : String Index 3 Read GetKnownStyle Write SetKnownStyle;
  659. Property Display : String Index 4 Read GetKnownStyle Write SetKnownStyle;
  660. Property Width : String Index 5 Read GetKnownStyle Write SetKnownStyle;
  661. Property Height : String Index 6 Read GetKnownStyle Write SetKnownStyle;
  662. end;
  663. { TCustomTemplateWidget }
  664. TCustomTemplateWidget = Class(TWebWidget)
  665. private
  666. FContainerTag: String;
  667. procedure SetContainerTag(AValue: String);
  668. Protected
  669. function GetReferenceElement: TJSHTMLELement; override;
  670. function GetTemplateHTML: String; virtual; abstract;
  671. Procedure ApplyTemplate(aElement : TJSHTMLElement); virtual;
  672. Function DoRenderHTML(aParent, aElement: TJSHTMLElement) : TJSHTMLElement; override;
  673. // When set, a tag will be created and the template will be rendered below this tag.
  674. Property ContainerTag : String Read FContainerTag Write SetContainerTag;
  675. Public
  676. Function HTMLTag : String; override;
  677. end;
  678. { TSimpleTemplateWidget }
  679. TSimpleTemplateWidget = Class(TCustomTemplateWidget)
  680. Private
  681. FTemplate: String;
  682. procedure SetTemplate(AValue: String);
  683. Protected
  684. function GetTemplateHTML: String; override;
  685. Public
  686. Property Reference;
  687. Property References;
  688. Property Elements;
  689. Property ElementList;
  690. Published
  691. // The template.
  692. Property Template : String Read FTemplate Write SetTemplate;
  693. Property ContainerTag;
  694. end;
  695. TTemplateWidget = Class(TCustomTemplateWidget)
  696. Private
  697. FTemplate: TStrings;
  698. procedure DoTemplateChanged(Sender: TObject);
  699. procedure SetTemplate(AValue: TStrings);
  700. Protected
  701. function GetTemplateHTML: String; override;
  702. Public
  703. Constructor Create(aOwner : TComponent); override;
  704. Destructor Destroy; override;
  705. Property Reference;
  706. Property References;
  707. Property Elements;
  708. Property ElementList;
  709. Published
  710. // The template.
  711. Property Template : TStrings Read FTemplate Write SetTemplate;
  712. Property ContainerTag;
  713. end;
  714. { TCustomLoopTemplateWidget }
  715. { TLoopTemplateValue }
  716. TLoopTemplateValue = Class
  717. Public
  718. Index : Integer;
  719. Name : String;
  720. Value : String;
  721. end;
  722. TGetLoopTemplateValueEvent = Procedure (Sender : TObject; aValue : TLoopTemplateValue) of object;
  723. { TLoopTemplateGroup }
  724. TLoopTemplateGroup = class(TCollectionItem)
  725. private
  726. FGroupValue : string;
  727. FFooterTemplate: String;
  728. FHeaderTemplate: String;
  729. FName: string;
  730. procedure SetFooterTemplate(AValue: String);
  731. procedure SetHeaderTemplate(AValue: String);
  732. procedure SetName(AValue: string);
  733. Public
  734. Procedure Assign(Source: TPersistent); override;
  735. Published
  736. Property Name : string Read FName Write SetName;
  737. Property HeaderTemplate : String Read FHeaderTemplate Write SetHeaderTemplate;
  738. Property FooterTemplate : String Read FFooterTemplate Write SetFooterTemplate;
  739. end;
  740. { TLoopTemplateGroupList }
  741. TLoopTemplateGroupList = class(TOwnedCollection)
  742. private
  743. function GetG(aIndex : Integer): TLoopTemplateGroup;
  744. procedure SetG(aIndex : Integer; AValue: TLoopTemplateGroup);
  745. Protected
  746. procedure Update(Item: TCollectionItem); override;
  747. Public
  748. Function IndexOfGroup(const aName : string) : Integer;
  749. Function FindGroup(const aName : string) : TLoopTemplateGroup;
  750. Function GetGroup(const aName : string) : TLoopTemplateGroup;
  751. Function AddGroup(Const aName,aHeader,aFooter : String) : TLoopTemplateGroup;
  752. Property Groups [aIndex : Integer] : TLoopTemplateGroup Read GetG Write SetG; default;
  753. end;
  754. TCustomLoopTemplateWidget = Class(TCustomTemplateWidget)
  755. Private
  756. FFooter: String;
  757. FGroups: TLoopTemplateGroupList;
  758. FHeader: String;
  759. FOnGetValue: TGetLoopTemplateValueEvent;
  760. FTemplate: String;
  761. procedure SetFooter(AValue: String);
  762. procedure SetGroups(AValue: TLoopTemplateGroupList);
  763. procedure SetHeader(AValue: String);
  764. procedure SetTemplate(AValue: String);
  765. Protected
  766. Type
  767. { TLoopEnumerator }
  768. TLoopEnumerator = Class
  769. private
  770. FGroup : TLoopTemplateGroup;
  771. FWidget: TCustomLoopTemplateWidget;
  772. FIndex : Integer;
  773. FCurrValues : TLoopTemplateValue;
  774. public
  775. constructor Create(AWidget : TCustomLoopTemplateWidget; aValues: TLoopTemplateValue); reintroduce; virtual;
  776. destructor destroy; override;
  777. Function GetValue(Const aName : String): String; virtual;
  778. function MoveNext: Boolean; virtual;
  779. Property Widget: TCustomLoopTemplateWidget Read FWidget;
  780. Property Index : Integer Read FIndex;
  781. Property CurrValues : TLoopTemplateValue Read FCurrValues;
  782. end;
  783. Protected
  784. // Template support
  785. function GetTemplateHTML: String; override;
  786. Function RenderTemplate(aEnum : TLoopEnumerator; aTemplate : String) : String; virtual;
  787. // Grouping support
  788. function RenderGroupFooters(aStartIndex: Integer; aEnum: TLoopEnumerator): String; virtual;
  789. function RenderGroupHeaders(aEnum: TLoopEnumerator): String; virtual;
  790. function GetGroupValue(enum: TLoopEnumerator; aGroupIndex: Integer; aGroup: TLoopTemplateGroup): String; virtual;
  791. // Create all kinds of helper classes
  792. Class Function CreateGroups(aOwner : TComponent) : TLoopTemplateGroupList; virtual;
  793. Class Function CreateCurrValues : TLoopTemplateValue; virtual;
  794. Function CreateLoopEnumerator (aCurrValues : TLoopTemplateValue) : TLoopEnumerator; virtual; abstract;
  795. Public
  796. Constructor Create(aOwner : TComponent); override;
  797. Destructor Destroy; override;
  798. Property Elements;
  799. Property ElementList;
  800. Protected
  801. // The templates.
  802. Property Groups : TLoopTemplateGroupList Read FGroups Write SetGroups;
  803. Property HeaderTemplate : String Read FHeader Write SetHeader;
  804. Property ItemTemplate : String Read FTemplate Write SetTemplate;
  805. Property FooterTemplate : String Read FFooter Write SetFooter;
  806. Property OnGetValue : TGetLoopTemplateValueEvent Read FOnGetValue Write FOnGetValue;
  807. end;
  808. { TSimpleLoopTemplateWidget }
  809. { TSimpleLoopTemplateGroup }
  810. TSimpleLoopTemplateGroup = Class(TLoopTemplateGroup)
  811. private
  812. FGroupValueTemplate: String;
  813. procedure SetGroupValueTemplate(AValue: String);
  814. Published
  815. Property GroupValueTemplate : String Read FGroupValueTemplate Write SetGroupValueTemplate;
  816. end;
  817. TSimpleLoopTemplateWidget = Class(TCustomLoopTemplateWidget)
  818. private
  819. FItemCount: Integer;
  820. FOnGetGroupValue: TGetLoopTemplateValueEvent;
  821. procedure SetItemCount(AValue: Integer);
  822. Protected
  823. Type
  824. { TSimpleLoopEnumerator }
  825. TSimpleLoopEnumerator = Class(TLoopEnumerator)
  826. private
  827. FMaxCount: Integer;
  828. public
  829. function MoveNext: Boolean; override;
  830. Property MaxCount : Integer Read FMaxCount;
  831. end;
  832. Protected
  833. Function CreateLoopEnumerator(aCurrValues : TLoopTemplateValue) : TLoopEnumerator; override;
  834. function GetGroupValue(aEnum: TLoopEnumerator; aGroupIndex: Integer; aGroup: TLoopTemplateGroup): String; override;
  835. Class Function CreateGroups(aOwner : TComponent) : TLoopTemplateGroupList; override;
  836. Published
  837. Property ItemCount : Integer Read FItemCount Write SetItemCount;
  838. Property Groups;
  839. Property HeaderTemplate;
  840. Property ItemTemplate;
  841. Property FooterTemplate;
  842. Property OnGetValue;
  843. Property OnGetGroupValue : TGetLoopTemplateValueEvent Read FOnGetGroupValue Write FOnGetGroupValue;
  844. Property References;
  845. Property ContainerTag;
  846. end;
  847. { TListLoopTemplateWidget }
  848. TListLoopTemplateWidget = Class(TCustomLoopTemplateWidget)
  849. Public
  850. Type
  851. TListKind = (lkCollection,lkFPList,lkList,lkObjectArray,lkJSArray);
  852. TValueMode = (vmRTTI,vmProperty);
  853. Const
  854. ListKindNames : Array[TlistKind] of string = ('Collection','FPList','List','ObjectArray','JSArray');
  855. private
  856. FListKind: TListKind;
  857. FList : JSValue;
  858. procedure CheckList(aKind: TListKind);
  859. function GetCollection: TCollection;
  860. function GetFPList: TFPList;
  861. function GetJSArray: TJSArray;
  862. function GetList: TList;
  863. function GetObjectArray: TObjectDynArray;
  864. function GetValueMode: TValueMode;
  865. procedure SetCollection(AValue: TCollection);
  866. procedure SetFPList(AValue: TFPList);
  867. procedure SetJSArray(AValue: TJSArray);
  868. procedure SetList(AValue: TList);
  869. procedure SetObjectArray(AValue: TObjectDynArray);
  870. Protected
  871. Type
  872. { TListLoopEnumerator }
  873. TListLoopEnumerator = Class(TLoopEnumerator)
  874. private
  875. FArray : TJSArray;
  876. FCurrent : JSValue;
  877. public
  878. function MoveNext: Boolean; override;
  879. Property Current : JSValue Read FCurrent;
  880. end;
  881. { TRTTIListLoopEnumerator }
  882. TRTTIListLoopEnumerator = Class(TListLoopEnumerator)
  883. public
  884. function GetValue(const aName: String): String; override;
  885. end;
  886. { TPropListLoopEnumerator }
  887. TPropListLoopEnumerator = Class(TListLoopEnumerator)
  888. public
  889. function GetValue(const aName: String): String; override;
  890. end;
  891. Protected
  892. // Return JS array from list
  893. Function GetArray : TJSArray;virtual;
  894. Function CreateLoopEnumerator(aCurrValues : TLoopTemplateValue) : TLoopEnumerator; override;
  895. Public
  896. Property Collection : TCollection Read GetCollection Write SetCollection;
  897. Property FPList : TFPList Read GetFPList Write SetFPList;
  898. Property List : TList Read GetList Write SetList;
  899. Property ObjectArray : TObjectDynArray Read GetObjectArray Write SetObjectArray;
  900. Property JSArray : TJSArray Read GetJSArray Write SetJSArray;
  901. // What kind of list do we have
  902. Property ListKind : TListKind Read FListKind;
  903. // How do we get values from the objects.
  904. Property ValueMode : TValueMode Read GetValueMode;
  905. Published
  906. Property HeaderTemplate;
  907. Property ItemTemplate;
  908. Property FooterTemplate;
  909. Property OnGetValue;
  910. end;
  911. implementation
  912. uses Strutils, TypInfo;
  913. ResourceString
  914. SErrCannotSetParentAndElementID = 'ElementID and ParentID cannot be set at the same time.';
  915. SErrCannotRenderWithoutParent = '%s: Cannot render without parent';
  916. SErrInvalidChildIndex = 'Invalid child index: value %d is not in valid range [0..%d]';
  917. SErrUnknownStyle = 'Unknown style: %s';
  918. SErrElementIDNotAllowed = '%s: Setting element ID is not allowed';
  919. SErrParentIDNotAllowed = '%s: Setting parent ID is not allowed';
  920. SErrParentNotAllowed = '%s: Setting parent is not allowed';
  921. SErrChildrenNotAllowed = '%s: Parent does not allow children';
  922. SErrWidgetNotFound = 'Widget with ID "%s" not found.';
  923. SErrUnknownReference = 'Unknown reference: %s';
  924. SErrNoElement = '%s: Element reference is empty: "%s"';
  925. SErrNotRendered = 'Cannot perform this operation: Widget not rendered';
  926. SErrCannotRefreshNoWidget = 'Cannot refresh references without widget';
  927. SErrNotInput = 'Reference %s is not an input element';
  928. SErrListNotA = '%s: List is not a %';
  929. SErrUnknownTemplateGroup = 'Unknown template group item: "%s"';
  930. SErrDuplicateTemplateGroup = 'Duplicate template group item: "%s"';
  931. SErrNoGroupInNonGroupTemplate = 'Group name can only be used group value template';
  932. { TSimpleLoopTemplateGroup }
  933. procedure TSimpleLoopTemplateGroup.SetGroupValueTemplate(AValue: String);
  934. begin
  935. if FGroupValueTemplate=AValue then Exit;
  936. FGroupValueTemplate:=AValue;
  937. Changed(False);
  938. end;
  939. { TLoopTemplateGroupList }
  940. function TLoopTemplateGroupList.GetG(aIndex : Integer): TLoopTemplateGroup;
  941. begin
  942. Result:=TLoopTemplateGroup(Items[aIndex])
  943. end;
  944. procedure TLoopTemplateGroupList.SetG(aIndex : Integer; AValue: TLoopTemplateGroup);
  945. begin
  946. Items[aIndex]:=aValue;
  947. end;
  948. procedure TLoopTemplateGroupList.Update(Item: TCollectionItem);
  949. begin
  950. inherited Update(Item);
  951. if Owner is TCustomLoopTemplateWidget then
  952. With TCustomLoopTemplateWidget(Owner) do
  953. if IsRendered then
  954. Refresh;
  955. end;
  956. function TLoopTemplateGroupList.IndexOfGroup(const aName: string): Integer;
  957. begin
  958. Result:=Count-1;
  959. While (Result>=0) and Not SameText(GetG(Result).Name,aName) do
  960. Dec(Result);
  961. end;
  962. function TLoopTemplateGroupList.FindGroup(const aName: string): TLoopTemplateGroup;
  963. Var
  964. Idx: Integer;
  965. begin
  966. Idx:=IndexOfGroup(aName);
  967. if (Idx=-1) then
  968. Result:=Nil
  969. else
  970. Result:=GetG(Idx);
  971. end;
  972. function TLoopTemplateGroupList.GetGroup(const aName: string): TLoopTemplateGroup;
  973. begin
  974. Result:=FindGroup(aName);
  975. if (Result=Nil) then
  976. raise EWidgets.CreateFmt(SErrUnknownTemplateGroup, [aName]);
  977. end;
  978. function TLoopTemplateGroupList.AddGroup(const aName, aHeader, aFooter: String): TLoopTemplateGroup;
  979. begin
  980. if IndexOfGroup(aName)<>-1 then
  981. raise EWidgets.CreateFmt(SErrDuplicateTemplateGroup, [aName]);
  982. Result:=add as TLoopTemplateGroup;
  983. Result.Name:=aName;
  984. Result.FFooterTemplate:=aFooter;
  985. Result.HeaderTemplate:=aHeader;
  986. end;
  987. { TLoopTemplateGroup }
  988. procedure TLoopTemplateGroup.SetFooterTemplate(AValue: String);
  989. begin
  990. if FFooterTemplate=AValue then Exit;
  991. FFooterTemplate:=AValue;
  992. Changed(False);
  993. end;
  994. procedure TLoopTemplateGroup.SetHeaderTemplate(AValue: String);
  995. begin
  996. if FHeaderTemplate=AValue then Exit;
  997. FHeaderTemplate:=AValue;
  998. Changed(False);
  999. end;
  1000. procedure TLoopTemplateGroup.SetName(AValue: string);
  1001. begin
  1002. if FName=AValue then Exit;
  1003. if Assigned(Collection) then
  1004. if TLoopTemplateGroupList(Collection).IndexOfGroup(aValue)<>-1 then
  1005. raise EWidgets.CreateFmt(SErrDuplicateTemplateGroup, [aValue]);
  1006. FName:=AValue;
  1007. end;
  1008. procedure TLoopTemplateGroup.Assign(Source: TPersistent);
  1009. Var
  1010. G : TLoopTemplateGroup;
  1011. begin
  1012. if Source is TLoopTemplateGroup then
  1013. begin
  1014. G:=Source as TLoopTemplateGroup;
  1015. FName:=G.Name;
  1016. FHeaderTemplate:=G.HeaderTemplate;
  1017. FFooterTemplate:=G.FooterTemplate;
  1018. end
  1019. else
  1020. inherited Assign(Source);
  1021. end;
  1022. { TListLoopTemplateWidget.TPropListLoopEnumerator }
  1023. function TListLoopTemplateWidget.TPropListLoopEnumerator.GetValue(const aName: String): String;
  1024. Var
  1025. V : JSValue;
  1026. begin
  1027. V:=TJSObject(Current)[aName];
  1028. if IsDefined(V) then
  1029. Result:=String(V);
  1030. end;
  1031. { TListLoopTemplateWidget.TRTTIListLoopEnumerator }
  1032. function TListLoopTemplateWidget.TRTTIListLoopEnumerator.GetValue(const aName: String): String;
  1033. Const
  1034. AllowedTypes = [tkInteger,tkChar, tkString, tkEnumeration, tkSet,tkDouble, tkBool, tkJSValue];
  1035. Var
  1036. O : TObject;
  1037. MP : TTypeMemberProperty;
  1038. begin
  1039. O:=TObject(Current);
  1040. MP:=GetPropInfo(O,aName,AllowedTypes);
  1041. if Assigned(Mp) then
  1042. case MP.TypeInfo.Kind of
  1043. tkInteger : Result:=IntToStr(GetOrdProp(O,MP));
  1044. tkChar,
  1045. tkString : Result:=GetStrProp(O,MP);
  1046. tkEnumeration : Result:=GetEnumName(TTypeInfoEnum(MP.TypeInfo),GetOrdProp(O,MP));
  1047. tkSet : Result:=GetSetProp(O,MP);
  1048. tkDouble : Result:=FloatToStr(GetFloatProp(O,MP));
  1049. tkBool : Result:=BoolToStr(GetBoolProp(O,MP));
  1050. tkJSValue : Result:=String(GetJSValueProp(O,MP));
  1051. end;
  1052. end;
  1053. { TListLoopTemplateWidget.TListLoopEnumerator }
  1054. function TListLoopTemplateWidget.TListLoopEnumerator.MoveNext: Boolean;
  1055. begin
  1056. Result:=Index<FArray.Length-1;
  1057. Result:=inherited MoveNext;
  1058. if Result then
  1059. FCurrent:=FArray[Index];
  1060. end;
  1061. { TListLoopTemplateWidget }
  1062. procedure TListLoopTemplateWidget.CheckList(aKind: TListKind);
  1063. begin
  1064. If FListKind<>aKind then
  1065. Raise EWidgets.CreateFmt(SErrListNotA,[DisplayElementName,ListKindNames[aKind]]);
  1066. end;
  1067. function TListLoopTemplateWidget.GetCollection: TCollection;
  1068. begin
  1069. CheckList(lkCollection);
  1070. Result:=TCollection(FList)
  1071. end;
  1072. function TListLoopTemplateWidget.GetFPList: TFPList;
  1073. begin
  1074. CheckList(lkFPList);
  1075. Result:=TFPList(FList)
  1076. end;
  1077. function TListLoopTemplateWidget.GetJSArray: TJSArray;
  1078. begin
  1079. CheckList(lkJSArray);
  1080. Result:=TJSArray(FList)
  1081. end;
  1082. function TListLoopTemplateWidget.GetList: TList;
  1083. begin
  1084. CheckList(lkList);
  1085. Result:=TList(FList)
  1086. end;
  1087. function TListLoopTemplateWidget.GetObjectArray: TObjectDynArray;
  1088. begin
  1089. CheckList(lkObjectArray);
  1090. Result:=TObjectDynArray(FList);
  1091. end;
  1092. function TListLoopTemplateWidget.GetValueMode: TValueMode;
  1093. begin
  1094. if ListKind in [lkCollection,lkFPList,lkList,lkObjectArray] then
  1095. Result:=vmRTTI
  1096. else
  1097. Result:=vmProperty;
  1098. end;
  1099. procedure TListLoopTemplateWidget.SetCollection(AValue: TCollection);
  1100. begin
  1101. Flist:=aValue;
  1102. FListKind:=lkCollection;
  1103. end;
  1104. procedure TListLoopTemplateWidget.SetFPList(AValue: TFPList);
  1105. begin
  1106. Flist:=aValue;
  1107. FListKind:=lkFPList;
  1108. end;
  1109. procedure TListLoopTemplateWidget.SetJSArray(AValue: TJSArray);
  1110. begin
  1111. FList:=AValue;
  1112. FListKind:=lkJSArray;
  1113. end;
  1114. procedure TListLoopTemplateWidget.SetList(AValue: TList);
  1115. begin
  1116. Flist:=aValue;
  1117. FListKind:=lkList;
  1118. end;
  1119. procedure TListLoopTemplateWidget.SetObjectArray(AValue: TObjectDynArray);
  1120. begin
  1121. FListKind:=lkObjectArray;
  1122. FList:=aValue;
  1123. end;
  1124. function TListLoopTemplateWidget.GetArray: TJSArray;
  1125. Var
  1126. I : integer;
  1127. C : TCollection;
  1128. begin
  1129. Case FListKind of
  1130. lkCollection :
  1131. begin
  1132. C:=TCollection(Flist);
  1133. Result:=TJSArray.New(C.Count);
  1134. for I:=0 To C.Count-1 do
  1135. Result[i]:=C.Items[i];
  1136. end;
  1137. lkFPList:
  1138. Result:=TJSArray(TFPList(FList).List);
  1139. lkList:
  1140. Result:=TJSArray(TList(FList).List);
  1141. lkJSArray,
  1142. lkObjectArray :
  1143. Result:=TJSArray(FList);
  1144. end;
  1145. end;
  1146. function TListLoopTemplateWidget.CreateLoopEnumerator(aCurrValues : TLoopTemplateValue) : TLoopEnumerator;
  1147. begin
  1148. Case ValueMode of
  1149. vmRTTI : Result:=TRTTIListLoopEnumerator.Create(Self,aCurrValues);
  1150. vmProperty : Result:=TPropListLoopEnumerator.Create(Self,aCurrValues);
  1151. end;
  1152. TListLoopEnumerator(Result).FArray:=GetArray;
  1153. end;
  1154. { TSimpleLoopTemplateWidget.TSimpleLoopEnumerator }
  1155. function TSimpleLoopTemplateWidget.TSimpleLoopEnumerator.MoveNext: Boolean;
  1156. begin
  1157. Result:=(Index<MaxCount-1);
  1158. if Result then
  1159. Inherited MoveNext;
  1160. end;
  1161. { TSimpleLoopTemplateWidget }
  1162. procedure TSimpleLoopTemplateWidget.SetItemCount(AValue: Integer);
  1163. begin
  1164. if FItemCount=AValue then Exit;
  1165. FItemCount:=AValue;
  1166. if IsRendered then
  1167. Refresh;
  1168. end;
  1169. function TSimpleLoopTemplateWidget.CreateLoopEnumerator(aCurrValues : TLoopTemplateValue) : TLoopEnumerator;
  1170. Var
  1171. L : TSimpleLoopEnumerator;
  1172. begin
  1173. L:=TSimpleLoopEnumerator.Create(Self,aCurrValues);
  1174. L.FMaxCount:=Self.ItemCount;
  1175. Result:=L;
  1176. end;
  1177. function TSimpleLoopTemplateWidget.GetGroupValue(aEnum: TLoopEnumerator; aGroupIndex: Integer; aGroup: TLoopTemplateGroup): String;
  1178. begin
  1179. aEnum.CurrValues.Name:=aGroup.Name;
  1180. if TSimpleLoopTemplateGroup(aGroup).GroupValueTemplate<>'' then
  1181. aEnum.FCurrValues.Value:=RenderTemplate(aEnum,TSimpleLoopTemplateGroup(aGroup).GroupValueTemplate);
  1182. if Assigned(OnGetGroupValue) then
  1183. OnGetGroupValue(Self,aEnum.CurrValues);
  1184. Result:=aEnum.CurrValues.Value;
  1185. // Writeln('Group Value: ',aEnum.CurrValues.Value,' for ',aGroup.Name);
  1186. end;
  1187. class function TSimpleLoopTemplateWidget.CreateGroups(aOwner: TComponent): TLoopTemplateGroupList;
  1188. begin
  1189. Result:=TLoopTemplateGroupList.Create(aOwner,TSimpleLoopTemplateGroup)
  1190. end;
  1191. { TCustomLoopTemplateWidget }
  1192. procedure TCustomLoopTemplateWidget.SetTemplate(AValue: String);
  1193. begin
  1194. if FTemplate=aValue then exit;
  1195. FTemplate:=aValue;
  1196. if IsRendered then
  1197. Refresh;
  1198. end;
  1199. Class function TCustomLoopTemplateWidget.CreateGroups(aOwner : TComponent): TLoopTemplateGroupList;
  1200. begin
  1201. Result:=TLoopTemplateGroupList.Create(AOwner,TLoopTemplateGroup);
  1202. end;
  1203. Class function TCustomLoopTemplateWidget.CreateCurrValues: TLoopTemplateValue;
  1204. begin
  1205. Result:=TLoopTemplateValue.Create;
  1206. end;
  1207. function TCustomLoopTemplateWidget.RenderTemplate(aEnum: TLoopEnumerator; aTemplate: String): String;
  1208. Var
  1209. E : TJSRegexp;
  1210. begin
  1211. E:=TJSRegexp.New('{{([_\w]*)}}','g');
  1212. Result:=TJSString(aTemplate).Replace(E,Function (Const match,p1 : string; offset : Integer; AString : String) : string
  1213. begin
  1214. aEnum.CurrValues.Value:=aEnum.GetValue(p1);
  1215. // Writeln(p1,' -> ',aEnum.CurrValues.Value);
  1216. if Assigned(OnGetValue) then
  1217. begin
  1218. aEnum.CurrValues.Index:=aEnum.Index;
  1219. aEnum.CurrValues.Name:=P1;
  1220. OnGetValue(Self,aEnum.CurrValues);
  1221. end;
  1222. Result:=AEnum.CurrValues.Value;
  1223. end);
  1224. end;
  1225. procedure TCustomLoopTemplateWidget.SetFooter(AValue: String);
  1226. begin
  1227. if FFooter=AValue then Exit;
  1228. FFooter:=AValue;
  1229. if IsRendered then
  1230. Refresh;
  1231. end;
  1232. procedure TCustomLoopTemplateWidget.SetGroups(AValue: TLoopTemplateGroupList);
  1233. begin
  1234. if FGroups=AValue then Exit;
  1235. FGroups.Assign(AValue);
  1236. if IsRendered then
  1237. Refresh;
  1238. end;
  1239. procedure TCustomLoopTemplateWidget.SetHeader(AValue: String);
  1240. begin
  1241. if FHeader=AValue then Exit;
  1242. FHeader:=AValue;
  1243. if IsRendered then
  1244. Refresh;
  1245. end;
  1246. function TCustomLoopTemplateWidget.GetGroupValue(enum : TLoopEnumerator; aGroupIndex : Integer; aGroup : TLoopTemplateGroup) : String;
  1247. begin
  1248. Result:=aGroup.Name;
  1249. end;
  1250. function TCustomLoopTemplateWidget.RenderGroupHeaders(aEnum : TLoopEnumerator) : String;
  1251. Var
  1252. GrpIdx: Integer;
  1253. grp : TLoopTemplateGroup;
  1254. StartGroups : Boolean;
  1255. S,V : String;
  1256. begin
  1257. // Writeln('Rendering group headers for row ',aEnum.Index);
  1258. Result:='';
  1259. StartGroups:=False;
  1260. For GrpIdx:=0 to Groups.Count-1 do
  1261. begin
  1262. Grp:=Groups[GrpIdx];
  1263. aEnum.FGroup:=Grp;
  1264. V:=GetGroupValue(aEnum,GrpIdx,Grp);
  1265. if Not StartGroups then
  1266. begin
  1267. StartGroups:=(aEnum.Index=0) or (V<>Grp.FGroupValue);
  1268. if StartGroups and (aEnum.Index>0) then
  1269. Result:=Result+RenderGroupFooters(grpIdx,aEnum);
  1270. end;
  1271. Grp.FGroupValue:=V;
  1272. if StartGroups then
  1273. begin
  1274. S:=RenderTemplate(aEnum,Grp.HeaderTemplate);
  1275. // Writeln('Rendering group ',Grp.Name,' (',V,') header template: ',Grp.HeaderTemplate,' : ',S);
  1276. Result:=Result+S;
  1277. end;
  1278. aEnum.FGroup:=Nil;
  1279. end;
  1280. end;
  1281. function TCustomLoopTemplateWidget.RenderGroupFooters(aStartIndex : Integer; aEnum : TLoopEnumerator) : String;
  1282. Var
  1283. GrpIdx : Integer;
  1284. grp : TLoopTemplateGroup;
  1285. begin
  1286. Result:='';
  1287. For GrpIdx:=Groups.Count-1 downto aStartIndex do
  1288. begin
  1289. Grp:=Groups[GrpIdx];
  1290. Result:=Result+RenderTemplate(aEnum,Grp.FooterTemplate);
  1291. end;
  1292. end;
  1293. function TCustomLoopTemplateWidget.GetTemplateHTML: String;
  1294. Var
  1295. Enum : TLoopEnumerator;
  1296. begin
  1297. Enum:=CreateLoopEnumerator(CreateCurrValues);
  1298. try
  1299. Result:=RenderTemplate(Enum,HeaderTemplate);
  1300. While enum.MoveNext do
  1301. begin
  1302. if Groups.Count>0 then
  1303. Result:=Result+RenderGroupHeaders(Enum);
  1304. Result:=Result+RenderTemplate(Enum,ItemTemplate);
  1305. end;
  1306. if Groups.Count>0 then
  1307. Result:=Result+RenderGroupFooters(0,Enum);
  1308. Result:=Result+RenderTemplate(Enum,FooterTemplate);
  1309. finally
  1310. Enum.Free;
  1311. end;
  1312. end;
  1313. constructor TCustomLoopTemplateWidget.Create(aOwner: TComponent);
  1314. begin
  1315. inherited Create(aOwner);
  1316. FGroups:=CreateGroups(Self);
  1317. end;
  1318. destructor TCustomLoopTemplateWidget.Destroy;
  1319. begin
  1320. FreeAndNil(FGroups);
  1321. inherited Destroy;
  1322. end;
  1323. { TCustomLoopTemplateWidget.TLoopEnumerator }
  1324. constructor TCustomLoopTemplateWidget.TLoopEnumerator.Create(AWidget: TCustomLoopTemplateWidget; aValues: TLoopTemplateValue);
  1325. begin
  1326. FWidget:=AWidget;
  1327. FCurrValues:=aValues;
  1328. FIndex:=-1;
  1329. end;
  1330. destructor TCustomLoopTemplateWidget.TLoopEnumerator.destroy;
  1331. begin
  1332. FreeAndNil(FCurrValues);
  1333. inherited destroy;
  1334. end;
  1335. function TCustomLoopTemplateWidget.TLoopEnumerator.GetValue(const aName: String): String;
  1336. begin
  1337. Case AName of
  1338. '_index_' : Result:=IntToStr(Index);
  1339. '_row_' : Result:=IntToStr(Index+1);
  1340. '_group_' : if Assigned(FGroup) then
  1341. Result:=FGroup.FGroupValue
  1342. else
  1343. Raise EWidgets.Create(SErrNoGroupInNonGroupTemplate);
  1344. else
  1345. Result:='';
  1346. end;
  1347. end;
  1348. function TCustomLoopTemplateWidget.TLoopEnumerator.MoveNext: Boolean;
  1349. begin
  1350. Result:=True;
  1351. Inc(FIndex);
  1352. FCurrValues.Index:=FIndex;
  1353. end;
  1354. { TSimpleTemplateWidget }
  1355. procedure TSimpleTemplateWidget.SetTemplate(AValue: String);
  1356. begin
  1357. FTemplate:=AValue;
  1358. if isRendered then
  1359. Refresh;
  1360. end;
  1361. function TSimpleTemplateWidget.GetTemplateHTML: String;
  1362. begin
  1363. Result:=FTemplate;
  1364. end;
  1365. { TWebWidgetReferences }
  1366. function TWebWidgetReferences.GetReferenceItem(aIndex : Integer): TReferenceItem;
  1367. begin
  1368. Result:=TReferenceItem(Inherited Items[aIndex])
  1369. end;
  1370. procedure TWebWidgetReferences.SetReferenceItem(aIndex : Integer; AValue: TReferenceItem);
  1371. begin
  1372. Items[aIndex]:=aValue;
  1373. end;
  1374. procedure TWebWidgetReferences.MarkDirty(aItem: TReferenceItem);
  1375. begin
  1376. if Assigned(Widget) and Assigned(Widget.Element) then
  1377. RefreshFromDOM(aItem,Widget.GetReferenceElement)
  1378. end;
  1379. procedure TWebWidgetReferences.RefreshFromDOM(aItem: TReferenceItem; aElement: TJSHTMlElement);
  1380. Var
  1381. a : TJSHTMlElementArray;
  1382. Nodes : TJSNodeList;
  1383. I : integer;
  1384. begin
  1385. if aElement=Nil then
  1386. begin
  1387. if (Widget=Nil) then
  1388. Raise EWidgets.Create(SErrCannotRefreshNoWidget);
  1389. if (Widget.Element=Nil) then
  1390. Raise EWidgets.Create(SErrNotRendered);
  1391. aElement:=Widget.GetReferenceElement;
  1392. end;
  1393. if FRefs=Nil then
  1394. FRefs:=New([]);
  1395. try
  1396. Nodes:=aElement.querySelectorAll(aItem.Selector);
  1397. SetLength(a,Nodes.length);
  1398. For I:=0 to Nodes.length-1 do
  1399. A[i]:=TJSHTMLElement(Nodes[i]);
  1400. except
  1401. SetLength(a,0);
  1402. end;
  1403. FRefs[LowerCase(aItem.Name)]:=A;
  1404. end;
  1405. function TWebWidgetReferences.Widget: TCustomWebWidget;
  1406. begin
  1407. Result:=TCustomWebWidget(owner);
  1408. end;
  1409. function TWebWidgetReferences.Add(const aName: String; aSelector: String): TReferenceItem;
  1410. begin
  1411. Result:=Add as TReferenceItem;
  1412. Result.FName:=aName;
  1413. Result.Selector:=aSelector;
  1414. if (aSelector<>'') then
  1415. MarkDirty(Result)
  1416. end;
  1417. function TWebWidgetReferences.EnsureReference(const aName: String; const aSelector: String): TReferenceItem;
  1418. begin
  1419. Result:=FindReference(aName);
  1420. if Result=Nil then
  1421. Result:=Add(aName,aSelector);
  1422. end;
  1423. function TWebWidgetReferences.IndexOfReference(const aName: String): Integer;
  1424. begin
  1425. Result:=Count-1;
  1426. While (Result>=0) and not SameText(GetReferenceItem(Result).Name,aName) do
  1427. Dec(Result);
  1428. end;
  1429. function TWebWidgetReferences.FindReference(const aName: String): TReferenceItem;
  1430. Var
  1431. Idx:Integer;
  1432. begin
  1433. Idx:=IndexOfReference(aName);
  1434. if Idx=-1 then
  1435. Result:=Nil
  1436. else
  1437. Result:=GetReferenceItem(Idx)
  1438. end;
  1439. function TWebWidgetReferences.GetReference(const aName: String): TReferenceItem;
  1440. begin
  1441. Result:=FindReference(aName);
  1442. if (Result=Nil) then
  1443. Raise EWidgets.CreateFmt(SErrUnknownReference,[aName]);
  1444. end;
  1445. procedure TWebWidgetReferences.RemoveReference(const aName: String);
  1446. Var
  1447. Idx:Integer;
  1448. begin
  1449. Idx:=IndexOfReference(aName);
  1450. if Idx<>-1 then
  1451. Delete(Idx);
  1452. end;
  1453. function TWebWidgetReferences.ElementExists(const aName: String): Boolean;
  1454. Var
  1455. V : JSValue;
  1456. begin
  1457. Result:=Assigned(FRefs);
  1458. if Result then
  1459. begin
  1460. V:=FRefs[LowerCase(aName)];
  1461. Result:=Assigned(V);
  1462. end;
  1463. end;
  1464. function TWebWidgetReferences.ElementIsArray(const aName: String): Boolean;
  1465. Var
  1466. V : JSValue;
  1467. begin
  1468. Result:=Assigned(FRefs);
  1469. if Result then
  1470. begin
  1471. V:=FRefs[LowerCase(aName)];
  1472. Result:=isArray(V) and (TJSArray(V).Length>1);
  1473. end;
  1474. end;
  1475. function TWebWidgetReferences.FindElementByName(const aName: String): TJSHTMLElement;
  1476. Var
  1477. J : JSValue;
  1478. Arr : TJSArray absolute J;
  1479. begin
  1480. Result:=Nil;
  1481. if FRefs=Nil then
  1482. exit;
  1483. J:=FRefs[LowerCase(aName)];
  1484. if isArray(J) and (Arr.Length>0) then
  1485. Result:=TJSHTMLElement(Arr[0])
  1486. end;
  1487. function TWebWidgetReferences.GetElementByName(const aName: String): TJSHTMLElement;
  1488. begin
  1489. Result:=FindElementByName(aName);
  1490. if Result=Nil then
  1491. Raise EWidgets.CreateFmt(SErrNoElement,[Widget.DisplayElementName,aName]);
  1492. end;
  1493. function TWebWidgetReferences.GetElementsByName(const aName: String): TJSHTMLElementArray;
  1494. Var
  1495. J : JSValue;
  1496. Arr : TJSArray absolute J;
  1497. begin
  1498. Result:=Nil;
  1499. if FRefs=Nil then
  1500. exit;
  1501. J:=FRefs[LowerCase(aName)];
  1502. if isArray(J) and (Arr.Length>0) then
  1503. Result:=TJSHTMLElementArray(Arr)
  1504. end;
  1505. procedure TWebWidgetReferences.RefreshFromDOM(aElement: TJSHTMlElement);
  1506. Var
  1507. I : Integer;
  1508. begin
  1509. For I:=0 to Count-1 do
  1510. RefreshFromDOM(GetReferenceItem(I),aElement);
  1511. end;
  1512. { TReferenceItem }
  1513. procedure TReferenceItem.SetName(AValue: String);
  1514. begin
  1515. if FName=AValue then Exit;
  1516. FName:=AValue;
  1517. MarkDirty;
  1518. end;
  1519. procedure TReferenceItem.SetInputValidity(AValue: String);
  1520. begin
  1521. if IsInput then
  1522. // this is not quite correct, but will work
  1523. TJSHTMLInputElement(Element).setCustomValidity(aValue)
  1524. else
  1525. Raise EWidgets.CreateFmt(SErrNotInput,[Name]);
  1526. end;
  1527. function TReferenceItem.GetElement: TJSHTMLElement;
  1528. begin
  1529. if Assigned(Collection) then
  1530. Result:=(Collection as TWebWidgetReferences).GetElementByName(Name)
  1531. else
  1532. Result:=Nil;
  1533. end;
  1534. function TReferenceItem.GetElements: TJSHTMLElementArray;
  1535. begin
  1536. if Assigned(Collection) then
  1537. Result:=(Collection as TWebWidgetReferences).GetElementsByName(Name)
  1538. else
  1539. Result:=Nil;
  1540. end;
  1541. procedure TReferenceItem.SetInputValue(AValue: String);
  1542. begin
  1543. if IsInput then
  1544. TJSObject(Element)['value']:=aValue
  1545. else
  1546. Raise EWidgets.CreateFmt(SErrNotInput,[Name])
  1547. end;
  1548. procedure TReferenceItem.MarkDirty;
  1549. begin
  1550. if Assigned(Collection) then
  1551. (Collection as TWebWidgetReferences).MarkDirty(Self);
  1552. end;
  1553. procedure TReferenceItem.Refresh;
  1554. begin
  1555. MarkDirty;
  1556. end;
  1557. function TReferenceItem.Exists: Boolean;
  1558. begin
  1559. if Assigned(Collection) then
  1560. Result:=(Collection as TWebWidgetReferences).ElementExists(Name)
  1561. else
  1562. Result:=False;
  1563. end;
  1564. function TReferenceItem.IsArray: Boolean;
  1565. begin
  1566. if Assigned(Collection) then
  1567. Result:=(Collection as TWebWidgetReferences).ElementIsArray(Name)
  1568. else
  1569. Result:=False;
  1570. end;
  1571. function TReferenceItem.IsInput: Boolean;
  1572. Var
  1573. el : TJSHTMLELement;
  1574. begin
  1575. Result:=Exists and not IsArray;
  1576. if Result then
  1577. begin
  1578. el:=Element;
  1579. Result:= ((el is TJSHTMLInputElement)
  1580. or (el is TJSHTMLTextAreaElement)
  1581. or (el is TJSHTMLSelectElement));
  1582. end;
  1583. end;
  1584. function TReferenceItem.GetInputValue: String;
  1585. begin
  1586. if IsInput then
  1587. Result:=String(TJSObject(Element)['value'])
  1588. else
  1589. Raise EWidgets.CreateFmt(SErrNotInput,[Name])
  1590. end;
  1591. procedure TReferenceItem.SetSelector(AValue: String);
  1592. begin
  1593. if FSelector=AValue then Exit;
  1594. FSelector:=AValue;
  1595. MarkDirty;
  1596. end;
  1597. { TCustomTemplateWidget }
  1598. procedure TCustomTemplateWidget.ApplyTemplate(aElement: TJSHTMLElement);
  1599. begin
  1600. aElement.InnerHTML:=GetTemplateHTML;
  1601. end;
  1602. function TCustomTemplateWidget.DoRenderHTML(aParent, aElement: TJSHTMLElement): TJSHTMLElement;
  1603. begin
  1604. if (ContainerTag='') then
  1605. begin
  1606. ApplyTemplate(AParent);
  1607. Result:= TJSHTMLElement(aParent.firstElementChild);
  1608. end
  1609. else
  1610. begin
  1611. ApplyTemplate(aElement);
  1612. Result:=aElement;
  1613. end;
  1614. end;
  1615. procedure TCustomTemplateWidget.SetContainerTag(AValue: String);
  1616. begin
  1617. if FContainerTag=AValue then Exit;
  1618. FContainerTag:=AValue;
  1619. if IsRendered then
  1620. Refresh;
  1621. end;
  1622. function TCustomTemplateWidget.GetReferenceElement: TJSHTMLELement;
  1623. begin
  1624. If (ContainerTag='') then
  1625. Result:=ParentElement
  1626. else
  1627. Result:=Element;
  1628. end;
  1629. function TCustomTemplateWidget.HTMLTag: String;
  1630. begin
  1631. Result:=ContainerTag;
  1632. end;
  1633. { TTemplateWidget }
  1634. procedure TTemplateWidget.SetTemplate(AValue: TStrings);
  1635. begin
  1636. if FTemplate=AValue then Exit;
  1637. FTemplate.Assign(AValue);
  1638. end;
  1639. function TTemplateWidget.GetTemplateHTML: String;
  1640. begin
  1641. Result:=FTemplate.Text;
  1642. end;
  1643. procedure TTemplateWidget.DoTemplateChanged(Sender: TObject);
  1644. begin
  1645. if isRendered then
  1646. Refresh;
  1647. end;
  1648. constructor TTemplateWidget.Create(aOwner: TComponent);
  1649. begin
  1650. inherited Create(aOwner);
  1651. FTemplate:=TStringList.Create;
  1652. TStringList(FTemplate).OnChange:=@DoTemplateChanged;
  1653. FContainerTag:='';
  1654. end;
  1655. destructor TTemplateWidget.Destroy;
  1656. begin
  1657. FreeAndNil(FTemplate);
  1658. inherited Destroy;
  1659. end;
  1660. { TContainerWidget }
  1661. function TContainerWidget.GetKnownStyle(AIndex: Integer): String;
  1662. var
  1663. S : TStyleItem;
  1664. begin
  1665. S:=Styles.FindStyle(KnownStyles[aIndex]);
  1666. if Assigned(S) then
  1667. Result:=S.Value;
  1668. end;
  1669. procedure TContainerWidget.SetKnownStyle(AIndex: Integer; AValue: String);
  1670. begin
  1671. Styles.EnsureStyle(KnownStyles[aIndex]).Value:=aValue;
  1672. end;
  1673. function TContainerWidget.HTMLTag: String;
  1674. begin
  1675. Result:='div';
  1676. end;
  1677. constructor TContainerWidget.Create(aOwner: TComponent);
  1678. begin
  1679. inherited Create(aOwner);
  1680. MinWidth:='32px';
  1681. MinHeight:='12px';
  1682. Width:='50%';
  1683. Height:='50%';
  1684. end;
  1685. { TWebWidgetStyles }
  1686. function TWebWidgetStyles.GetStyleItem(aIndex: Integer): TStyleItem;
  1687. begin
  1688. Result:=TStyleItem(Items[Aindex]);
  1689. end;
  1690. procedure TWebWidgetStyles.SetStyleItem(aIndex: Integer; AValue: TStyleItem);
  1691. begin
  1692. Items[aIndex]:=aValue;
  1693. end;
  1694. procedure TWebWidgetStyles.MarkDirty(aItem: TStyleItem);
  1695. Var
  1696. El : TJSHTMLElement;
  1697. begin
  1698. If Assigned(Widget) then
  1699. begin
  1700. el:=Widget.Element;
  1701. if Assigned(El) then
  1702. ApplyToDom(El,aItem);
  1703. end;
  1704. end;
  1705. procedure TWebWidgetStyles.ApplyToDOM(aElement: TJSHTMlElement; aItem: TStyleItem);
  1706. Const
  1707. Prios : Array[TStylePriority] of string = ('','important');
  1708. begin
  1709. With AItem do
  1710. if (Name<>'') then
  1711. if (Value<>'') then
  1712. aElement.Style.setProperty(Name,Value,Prios[Priority])
  1713. else
  1714. aElement.Style.removeProperty(name);
  1715. end;
  1716. function TWebWidgetStyles.Add(const aName: String; const aValue: String): TStyleItem;
  1717. begin
  1718. Result:=Add as TStyleItem;
  1719. // Don't use Name
  1720. Result.FName:=aName;
  1721. if aValue<>'' then
  1722. Result.Value:=aValue; // will trigger markdirty
  1723. end;
  1724. function TWebWidgetStyles.EnsureStyle(const aName: String; const aValue: String): TStyleItem;
  1725. begin
  1726. Result:=FindStyle(aName);
  1727. if Result=Nil then
  1728. Result:=Add(aName,aValue)
  1729. else if AValue<>'' then
  1730. Result.Value:=aValue
  1731. end;
  1732. function TWebWidgetStyles.Widget: TCustomWebWidget;
  1733. begin
  1734. Result:=TCustomWebWidget(Owner);
  1735. end;
  1736. function TWebWidgetStyles.IndexOfStyle(const aName: String): integer;
  1737. begin
  1738. Result:=Count-1;
  1739. While (Result>=0) and not SameText(aName,GetStyleItem(Result).Name) do
  1740. Dec(Result);
  1741. end;
  1742. function TWebWidgetStyles.FindStyle(const aName: String): TStyleItem;
  1743. Var
  1744. Idx : integer;
  1745. begin
  1746. Idx:=IndexOfStyle(aName);
  1747. If Idx=-1 then
  1748. Result:=Nil
  1749. else
  1750. Result:=GetStyleItem(Idx)
  1751. end;
  1752. function TWebWidgetStyles.GetStyle(const aName: String): TStyleItem;
  1753. begin
  1754. Result:=FindStyle(aName);
  1755. if Result=Nil then
  1756. Raise EWidgets.CreateFmt(SErrUnknownStyle,[aName]);
  1757. end;
  1758. function TWebWidgetStyles.RemoveStyle(const aName: String): String;
  1759. Var
  1760. I : Integer;
  1761. el : TJSHTMLElement;
  1762. begin
  1763. I:=IndexOfStyle(aName);
  1764. if I<>-1 then
  1765. begin
  1766. Result:=Styles[i].Value;
  1767. Delete(I);
  1768. end;
  1769. if Assigned(Widget) then
  1770. begin
  1771. el:=Widget.Element;
  1772. if Assigned(el) then
  1773. begin
  1774. if (Result='') then
  1775. Result:=el.style.getPropertyValue(aName);
  1776. el.style.removeProperty(aName);
  1777. end;
  1778. end;
  1779. end;
  1780. procedure TWebWidgetStyles.RefreshFromDOM(aElement : TJSHTMlElement = Nil;DoClear: Boolean = False);
  1781. Var
  1782. S : TJSCSSStyleDeclaration;
  1783. I : integer;
  1784. K : String;
  1785. W : TCustomWebWidget;
  1786. itm : TStyleItem;
  1787. begin
  1788. if aElement= Nil then
  1789. begin
  1790. W:=Widget;
  1791. if assigned(W) then
  1792. aElement:=W.Element;
  1793. if AElement=Nil then exit;
  1794. end;
  1795. if DoClear then
  1796. Clear;
  1797. S:=aElement.style;
  1798. For I:=0 to S.length-1 do
  1799. begin
  1800. K:=S.Item(I);
  1801. itm:=FindStyle(K);
  1802. if Itm=Nil then
  1803. begin
  1804. Itm:=Add(K);
  1805. Itm.FImported:=True;
  1806. end;
  1807. Itm.FValue:=S.getPropertyValue(K);
  1808. Case LowerCase(S.getPropertyPriority(K)) of
  1809. 'important' : Itm.FPriority:=spImportant;
  1810. end;
  1811. end;
  1812. end;
  1813. procedure TWebWidgetStyles.ClearImported;
  1814. Var
  1815. I : integer;
  1816. begin
  1817. I:=Count-1;
  1818. While I>=0 do
  1819. begin
  1820. If GetStyleItem(I).Fimported then
  1821. Delete(I);
  1822. Dec(I);
  1823. end;
  1824. end;
  1825. procedure TWebWidgetStyles.ApplyToDOM(aElement : TJSHTMlElement = Nil);
  1826. Var
  1827. I : Integer;
  1828. begin
  1829. if (AElement=Nil) and (Widget<>Nil) then
  1830. aElement:=Widget.Element;
  1831. if AElement<>Nil then
  1832. For I:=0 to Count-1 do
  1833. ApplyToDOM(aElement,GetStyleItem(i));
  1834. end;
  1835. { TStyleItem }
  1836. procedure TStyleItem.MarkDirty;
  1837. begin
  1838. If Assigned(Collection) then
  1839. TWebWidgetStyles(Collection).MarkDirty(Self);
  1840. end;
  1841. procedure TStyleItem.SetValue(AValue: String);
  1842. begin
  1843. if FValue=AValue then Exit;
  1844. FValue:=aValue;
  1845. MarkDirty;
  1846. end;
  1847. procedure TStyleItem.SetPriority(AValue: TStylePriority);
  1848. begin
  1849. if FPriority=AValue then Exit;
  1850. FPriority:=AValue;
  1851. MarkDirty;
  1852. end;
  1853. procedure TStyleItem.SetName(AValue: String);
  1854. begin
  1855. if aValue=FName then Exit;
  1856. FName:=AValue;
  1857. MarkDirty;
  1858. end;
  1859. procedure TStyleItem.Assign(Source: TPersistent);
  1860. Var
  1861. SI : TStyleItem;
  1862. begin
  1863. if Source is TStyleItem then
  1864. begin
  1865. SI:=Source as TStyleItem;
  1866. FName:=SI.FName;
  1867. FValue:=SI.FValue;
  1868. FImported:=SI.FImported;
  1869. MarkDirty;
  1870. end
  1871. else
  1872. inherited Assign(Source);
  1873. end;
  1874. { TCustomWebWidget }
  1875. function TCustomWebWidget.DisplayElementName: String;
  1876. begin
  1877. Result:=Name;
  1878. If Result='' then
  1879. Result:=' <'+HTMLTag+'>';
  1880. if Assigned(FElement) then
  1881. Result:=Result+'#'+FElement.ID;
  1882. Result:=Result+' (Type: '+ClassName+')';
  1883. end;
  1884. function TCustomWebWidget.EnsureElement : TJSHTMLElement;
  1885. var
  1886. P : TJSHTMLElement;
  1887. begin
  1888. Result:=GetElement;
  1889. if Result=Nil then
  1890. begin
  1891. // If we have a parent, make sure it has it's element
  1892. if Assigned(Parent) then
  1893. Parent.EnsureElement;
  1894. P:=ParentElement;
  1895. if (P=Nil) and (FixedElement=Nil) then
  1896. Raise EWidgets.CreateFmt(SErrCannotRenderWithoutParent,[DisplayElementName])
  1897. else
  1898. begin
  1899. Result:=RenderHTML(P);
  1900. FOwnsElement:=True;
  1901. FElement:=Result;
  1902. end;
  1903. ApplyData;
  1904. RefreshReferences; // After data, so data can be used in selectors
  1905. end;
  1906. end;
  1907. procedure TCustomWebWidget.InvalidateParentElement;
  1908. Var
  1909. I : Integer;
  1910. C : TCustomWebWidget;
  1911. begin
  1912. FParentElement:=nil;
  1913. For I:=0 to ChildCount-1 do
  1914. begin
  1915. C:=Children[i];
  1916. if Assigned(C) then // Can be Nil
  1917. C.InvalidateParentElement;
  1918. end;
  1919. end;
  1920. procedure TCustomWebWidget.InvalidateElement;
  1921. Var
  1922. I : Integer;
  1923. C : TCustomWebWidget;
  1924. begin
  1925. If FStyles.Count>0 then
  1926. FStyles.ClearImported;
  1927. if Assigned(Freferences) then
  1928. FReferences.FRefs:=Nil;
  1929. FElement:=nil;
  1930. For I:=0 to ChildCount-1 do
  1931. begin
  1932. C:=Children[i];
  1933. if Assigned(C) then // Can be Nil
  1934. C.InvalidateElement;
  1935. end;
  1936. end;
  1937. function TCustomWebWidget.WidgetClasses: String;
  1938. begin
  1939. Result:='';
  1940. end;
  1941. function TCustomWebWidget.GetElement: TJSHTMLELement;
  1942. Var
  1943. El : TJSHTMLElement;
  1944. begin
  1945. if (FElement=Nil) then
  1946. begin
  1947. if (FElementID<>'') then
  1948. begin
  1949. El:=FindElement(FElementID);
  1950. if Assigned(El) then
  1951. begin
  1952. ApplyWidgetSettings(el);
  1953. HookupEvents(el);
  1954. end;
  1955. FElement:=El;
  1956. if Assigned(El) then
  1957. ApplyData;
  1958. RefreshReferences;// After data, so data can be used in selectors
  1959. end;
  1960. end;
  1961. Result:=FElement;
  1962. end;
  1963. function TCustomWebWidget.GetExternalElement: Boolean;
  1964. begin
  1965. Result:=(FElementID<>'')
  1966. end;
  1967. function TCustomWebWidget.GetHaveReferences: Boolean;
  1968. begin
  1969. Result:=Assigned(FReferences);
  1970. end;
  1971. function TCustomWebWidget.GetHTMLEvent(AIndex: Integer): THTMLNotifyEvent;
  1972. Var
  1973. Fun : JSValue;
  1974. begin
  1975. Result:=nil;
  1976. if Assigned(FMyEvents) and (aIndex>=0) and (aIndex<=MaxEvents) then
  1977. begin
  1978. Fun:=FMyEvents[FEventNames[aindex]];
  1979. if Not isUndefined(Fun) then
  1980. Result:=THTMLNotifyEvent(Fun);
  1981. end;
  1982. end;
  1983. function TCustomWebWidget.GetIsElementDirty: Boolean;
  1984. begin
  1985. Result:=IsRendered;
  1986. end;
  1987. function TCustomWebWidget.GetClasses: String;
  1988. begin
  1989. if IsRendered Then
  1990. FClasses:=FElement.ClassName;
  1991. Result:=FClasses;
  1992. end;
  1993. function TCustomWebWidget.GetDataset(aName : String): String;
  1994. Var
  1995. el : TJSHTMLElement;
  1996. begin
  1997. el:=Element;
  1998. if Assigned(El) then
  1999. Result:=String(El.Dataset[aName])
  2000. else
  2001. Result:='';
  2002. end;
  2003. function TCustomWebWidget.GetChildCount: Integer;
  2004. begin
  2005. Result:=FChildren.Length;
  2006. end;
  2007. function TCustomWebWidget.GetChild(aIndex : Integer): TCustomWebWidget;
  2008. begin
  2009. if (aIndex<0) or (aIndex>=FChildren.Length) then
  2010. Raise EListError.CreateFmt(SErrInvalidChildIndex,[aIndex,FChildren.Length-1]);
  2011. Result:=TCustomWebWidget(FChildren[aIndex]);
  2012. end;
  2013. function TCustomWebWidget.GetContentElement: TJSHTMLELement;
  2014. begin
  2015. Result:=Element;
  2016. end;
  2017. function TCustomWebWidget.GetParent: TCustomWebWidget;
  2018. begin
  2019. Result:=FParent;
  2020. end;
  2021. function TCustomWebWidget.GetParentElement: TJSHTMLELement;
  2022. Var
  2023. El : TJSHTMLElement;
  2024. begin
  2025. if (FParentElement=Nil) then
  2026. begin
  2027. El:=TopElement;
  2028. if Assigned(el) then
  2029. FParentElement:=TJSHTMLElement(el.parentElement)
  2030. else if (FParentID<>'') then
  2031. FParentElement:=FindElement(FParentID)
  2032. else if Assigned(FParent) then
  2033. FParentElement:=FParent.ContentElement
  2034. else
  2035. FParentElement:=DefaultParentElement;
  2036. end;
  2037. Result:=FParentElement;
  2038. end;
  2039. function TCustomWebWidget.GetParentID: String;
  2040. Var
  2041. E : TJSHTMLElement;
  2042. begin
  2043. Result:='';
  2044. E:=ParentElement;
  2045. if Assigned(E) then
  2046. Result:=E.ID
  2047. else
  2048. Result:=FParentID;
  2049. end;
  2050. function TCustomWebWidget.GetElementID: String;
  2051. Var
  2052. El : TJSHTMLElement;
  2053. begin
  2054. El:=Element;
  2055. If Assigned(El) then
  2056. Result:=el.ID
  2057. else
  2058. Result:=FElementID;
  2059. end;
  2060. function TCustomWebWidget.GetReference(const aName : string): TJSHTMLElement;
  2061. begin
  2062. if Assigned(FReferences) then
  2063. Result:=FReferences.GetElementByName(aName)
  2064. else
  2065. Result:=Nil;
  2066. end;
  2067. function TCustomWebWidget.GetReferenceItem(aName : String): TReferenceItem;
  2068. begin
  2069. if Assigned(FReferences) then
  2070. Result:=FReferences.GetReference(aName)
  2071. else
  2072. Result:=Nil;
  2073. end;
  2074. function TCustomWebWidget.GetReferenceList(const aName : string): TJSHTMLElementArray;
  2075. begin
  2076. if Assigned(FReferences) then
  2077. Result:=FReferences.GetElementsByName(aName)
  2078. else
  2079. Result:=Nil;
  2080. end;
  2081. function TCustomWebWidget.GetReferences: TWebWidgetReferences;
  2082. begin
  2083. if (FReferences=Nil) then
  2084. FReferences:=CreateReferences;
  2085. Result:=FReferences;
  2086. end;
  2087. function TCustomWebWidget.GetRendered: Boolean;
  2088. begin
  2089. Result:=(FElement<>Nil)
  2090. end;
  2091. function TCustomWebWidget.GetTopElement: TJSHTMLELement;
  2092. begin
  2093. Result:=Element;
  2094. end;
  2095. function TCustomWebWidget.GetVisible: Boolean;
  2096. begin
  2097. Result:=FVisible;
  2098. end;
  2099. procedure TCustomWebWidget.SetAttr(const aName : string; AValue: String);
  2100. begin
  2101. if IsRendered then
  2102. Element[aName]:=aValue;
  2103. if Not Assigned(FAttrs) then
  2104. FAttrs:=TJSObject.New;
  2105. FAttrs[aName]:=aValue;
  2106. end;
  2107. procedure TCustomWebWidget.SetClasses(AValue: String);
  2108. begin
  2109. FClasses:=AddClasses(AValue,WidgetClasses);
  2110. If IsRendered then
  2111. FElement.ClassName:=FClasses;
  2112. end;
  2113. procedure TCustomWebWidget.SetDataset(aName : String; AValue: String);
  2114. Var
  2115. El : TJSHTMLElement;
  2116. begin
  2117. el:=Element;
  2118. If (El=Nil) then
  2119. Raise EWidgets.Create(SErrNotRendered);
  2120. el.Dataset[aName]:=aValue;
  2121. end;
  2122. procedure TCustomWebWidget.SetElementID(AValue: String);
  2123. begin
  2124. if (FElementID=AValue) then Exit;
  2125. if (aValue<>'') then
  2126. begin
  2127. if (FParentID<>'') then
  2128. Raise EWidgets.CreateFmt(SErrCannotSetParentAndElementID,[DisplayElementName]);
  2129. if FixedElement<>Nil then
  2130. Raise EWidgets.CreateFmt(SErrElementIDNotAllowed,[DisplayElementName]);
  2131. FElementID:=AValue;
  2132. end
  2133. else
  2134. begin
  2135. FElementID:=AValue;
  2136. if IsRendered then
  2137. Unrender(ParentElement);
  2138. end;
  2139. end;
  2140. procedure TCustomWebWidget.SetHTMLEvent(AIndex: Integer; AValue: THTMLNotifyEvent);
  2141. Var
  2142. EventName : String;
  2143. begin
  2144. if (aIndex<0) or (aIndex>MaxEvents) then
  2145. exit;
  2146. EventName:=FEventNames[aIndex];
  2147. if Assigned(aValue) then
  2148. AddEvent(EventName,AValue)
  2149. else
  2150. DeleteEvent(EventName);
  2151. end;
  2152. procedure TCustomWebWidget.SetParent(AValue: TCustomWebWidget);
  2153. Var
  2154. ReRender : Boolean;
  2155. begin
  2156. if (AValue=FParent) then exit;
  2157. if (FixedParent<>Nil) then
  2158. Raise EWidgets.CreateFmt(SErrParentNotAllowed,[DisplayElementName]);
  2159. if Assigned(aValue) then
  2160. if Not aValue.AllowChildren then
  2161. Raise EWidgets.CreateFmt(SErrChildrenNotAllowed,[DisplayElementName]);
  2162. If Assigned(FParent) then
  2163. FParent.RemoveChild(Self);
  2164. // Unrender
  2165. ReRender:=IsRendered;
  2166. if ReRender then
  2167. UnRender(ParentElement);
  2168. If (aValue=Nil) and (csDestroying in ComponentState) then
  2169. exit;
  2170. // here we re-render if needed
  2171. InvalidateParentElement;
  2172. If Assigned(aValue) then
  2173. begin
  2174. FParentID:='';
  2175. aValue.AddChild(Self); // Sets FParent
  2176. end;
  2177. if ReRender and Assigned(ParentElement) then
  2178. begin
  2179. FElement:=RenderHTML(ParentElement);
  2180. if Assigned(FElement) then
  2181. begin
  2182. ApplyData;
  2183. RefreshReferences;
  2184. end;
  2185. end;
  2186. end;
  2187. procedure TCustomWebWidget.SetParentID(AValue: String);
  2188. Var
  2189. ReRender : Boolean;
  2190. begin
  2191. if (FParentID=AValue) then exit;
  2192. if (aValue<>'') then
  2193. begin
  2194. if (FElementID<>'') then
  2195. Raise EWidgets.CreateFmt(SErrCannotSetParentAndElementID,[DisplayElementName]);
  2196. if (FixedParent<>Nil) then
  2197. Raise EWidgets.CreateFmt(SErrParentIDNotAllowed,[DisplayElementName]);
  2198. end;
  2199. ReRender:=IsRendered;
  2200. if ReRender then
  2201. UnRender(ParentElement);
  2202. if (aValue<>'') and Assigned(FParent) then
  2203. FParent.RemoveChild(Self);
  2204. FParentID:=aValue;
  2205. InvalidateParentElement;
  2206. if ReRender and Assigned(ParentElement) then
  2207. EnsureElement;
  2208. end;
  2209. procedure TCustomWebWidget.AddChild(aValue: TCustomWebWidget);
  2210. begin
  2211. if AValue=Nil then exit;
  2212. aValue.FParent:=Self;
  2213. if FChildren.IndexOf(aValue)=-1 then
  2214. FChildren.Push(aValue);
  2215. end;
  2216. procedure TCustomWebWidget.RemoveChild(aValue: TCustomWebWidget);
  2217. Var
  2218. I : NativeInt;
  2219. begin
  2220. if AValue=Nil then exit;
  2221. I:=FChildren.indexOf(aValue);
  2222. if I>=0 then
  2223. begin
  2224. FChildren.splice(I,1);
  2225. aValue.FParent:=Nil;
  2226. end;
  2227. end;
  2228. procedure TCustomWebWidget.SetReferences(AValue: TWebWidgetReferences);
  2229. begin
  2230. if (aValue=FReferences) then exit;
  2231. References.Assign(aValue);
  2232. if IsRendered then
  2233. References.RefreshFromDOM(GetReferenceElement);
  2234. end;
  2235. procedure TCustomWebWidget.SetStyles(AValue: TWebWidgetStyles);
  2236. begin
  2237. if FStyles=AValue then Exit;
  2238. FStyles.Assign(AValue);
  2239. end;
  2240. procedure TCustomWebWidget.SetVisible(AValue: Boolean);
  2241. Var
  2242. el : TJSHTMLElement;
  2243. begin
  2244. if aValue=FVisible then
  2245. Exit;
  2246. el:=Element;
  2247. if Assigned(el) then
  2248. ApplyVisible(el,aValue)
  2249. else
  2250. FVisible:=aValue;
  2251. end;
  2252. function TCustomWebWidget.GetAttr(const aName: String): String;
  2253. Var
  2254. el : TJSObject;
  2255. begin
  2256. Result:='';
  2257. if IsRendered then
  2258. el:=Element
  2259. else
  2260. el:=FAttrs;
  2261. if Assigned(el) and isDefined(el[aName]) then
  2262. Result:=String(el[aName]);
  2263. end;
  2264. procedure TCustomWebWidget.ApplyVisible(aElement: TJSHTMLElement;AValue: Boolean);
  2265. begin
  2266. if aValue then
  2267. begin
  2268. if (FDisplay<>'') then
  2269. aElement.Style.setProperty('display',FDisplay)
  2270. else
  2271. aElement.Style.removeProperty('display');
  2272. end
  2273. else
  2274. begin
  2275. FDisplay:=aElement.Style.getPropertyValue('display');
  2276. aElement.Style.setProperty('display','none');
  2277. end;
  2278. FVisible:=aValue;
  2279. end;
  2280. procedure TCustomWebWidget.EventEntry(aEvent: TJSEvent);
  2281. Var
  2282. R : TEventDispatch;
  2283. Fun : JSValue;
  2284. begin
  2285. R.MsgStr:=aEvent._type;
  2286. R.HTMLEvent:=aEvent;
  2287. if Assigned(FMyEvents) then
  2288. Fun:=FMyEvents[R.MsgStr]
  2289. else
  2290. Fun:=nil;
  2291. if Not (isUndefined(Fun) or isNull(Fun)) then
  2292. R.EventHandler:=THTMLNotifyEvent(Fun);
  2293. DispatchStr(R);
  2294. if (R.EventHandler<>Nil) then
  2295. R.EventHandler(Self,R.HTMLEvent);
  2296. end;
  2297. function TCustomWebWidget.CreateStyles: TWebWidgetStyles;
  2298. begin
  2299. Result:=TWebWidgetStyles.Create(Self,TStyleItem);
  2300. end;
  2301. function TCustomWebWidget.CreateReferences: TWebWidgetReferences;
  2302. begin
  2303. Result:=TWebWidgetReferences.Create(Self,TReferenceItem);
  2304. end;
  2305. procedure TCustomWebWidget.RemoveEvent(aElement: TJSHTMLElement; const aEvent: String);
  2306. begin
  2307. aElement.RemoveEventListener(aEvent,FMyHook);
  2308. end;
  2309. procedure TCustomWebWidget.HookupEvent(aElement: TJSHTMLElement; const aEvent : String);
  2310. begin
  2311. aElement.addEventListener(aEvent,FMyHook);
  2312. end;
  2313. procedure TCustomWebWidget.HookupEvents(aElement: TJSHTMLElement);
  2314. Var
  2315. Event : String;
  2316. begin
  2317. if Assigned(FMyEvents) then
  2318. for Event in TJSObject.keys(FMyEvents) do
  2319. HookupEvent(aElement,Event);
  2320. end;
  2321. procedure TCustomWebWidget.AddEvent(aName: String; AHandler: THTMLNotifyEvent);
  2322. Var
  2323. el : TJSHTMLElement;
  2324. begin
  2325. if FMyEvents=nil then
  2326. FMyEvents:=TJSObject.New;
  2327. FMyEvents[aName]:=aHandler;
  2328. El:=FElement;
  2329. if Assigned(El) then
  2330. HookupEvent(el,aName);
  2331. end;
  2332. procedure TCustomWebWidget.DeleteEvent(aName: String);
  2333. Var
  2334. el : TJSHTMLElement;
  2335. begin
  2336. if (FMyEvents<>nil) and FMyEvents.hasOwnProperty(aName) then
  2337. JSDelete(FMyEvents,aName);
  2338. El:=Element;
  2339. if Assigned(El) then
  2340. RemoveEvent(el,aName);
  2341. end;
  2342. class function TCustomWebWidget.FixedParent: TJSHTMLElement;
  2343. begin
  2344. Result:=Nil;
  2345. end;
  2346. class function TCustomWebWidget.DefaultParentElement: TJSHTMLElement;
  2347. begin
  2348. Result:=Nil;
  2349. end;
  2350. class function TCustomWebWidget.DefaultParent: TCustomWebWidget;
  2351. begin
  2352. Result:=nil;
  2353. end;
  2354. class function TCustomWebWidget.FixedElement: TJSHTMLElement;
  2355. begin
  2356. Result:=Nil;
  2357. end;
  2358. class function TCustomWebWidget.FindElement(aID: String): TJSHTMLElement;
  2359. begin
  2360. Result:=TJSHTMLElement(Document.getElementbyID(aID));
  2361. end;
  2362. class function TCustomWebWidget.CreateElement(aTag: String; aID: String
  2363. ): TJSHTMLElement;
  2364. begin
  2365. Result:=TJSHTMLElement(Document.createElement(aTag));
  2366. if aID<>'' then
  2367. Result.id:=aID;
  2368. end;
  2369. function TCustomWebWidget.GetReferenceElement: TJSHTMLELement;
  2370. begin
  2371. Result:=Element;
  2372. end;
  2373. procedure TCustomWebWidget.Refresh;
  2374. Var
  2375. I : integer;
  2376. begin
  2377. if IsRendered then
  2378. UnRender(ParentElement);
  2379. InvalidateParentElement;
  2380. EnsureElement;
  2381. For I:=0 to ChildCount-1 do
  2382. Children[i].Refresh;
  2383. end;
  2384. procedure TCustomWebWidget.Unrender;
  2385. Var
  2386. P : TJSHTMLElement;
  2387. begin
  2388. P:=ParentElement;
  2389. If Assigned(P) then
  2390. UnRender(P);
  2391. end;
  2392. procedure TCustomWebWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
  2393. // Normally, this should be called BEFORE FElement is set.
  2394. // But we'll be extra careful, and not rely on getters using FElement.
  2395. Var
  2396. S : String;
  2397. begin
  2398. if aElement.id='' then
  2399. aElement.id:=GenerateID;
  2400. // Don't use Classes, it will return FElement.Classname when set
  2401. S:=AddClasses(FClasses,WidgetClasses);
  2402. if (S<>'') then
  2403. AddClasses(aElement,S);
  2404. if FStyles.Count>0 then
  2405. FStyles.ApplyToDOM(aElement);
  2406. if Not FVisible then
  2407. ApplyVisible(aElement,FVisible);
  2408. // Maybe we should put this under control of a property or so ?
  2409. // TStyleRefresh = (srAlways,srOnElementID,srNever)
  2410. if (StyleRefresh = srAlways)
  2411. or ((FelementID<>'') and (FElementID<>'')) then
  2412. FStyles.RefreshFromDom(aElement,False);
  2413. if Assigned(FAttrs) then
  2414. for S in TJSObject.getOwnPropertyNames(FAttrs) do
  2415. if IndexText(S,['id','class'])=-1 then
  2416. aElement[S]:=String(FAttrs[S]);
  2417. end;
  2418. function TCustomWebWidget.DoRenderHTML(aParent, aElement: TJSHTMLElement): TJSHTMLElement;
  2419. begin
  2420. If AParent=Nil then
  2421. Console.Log(DisplayElementName+': render without parent!');
  2422. Result:=aElement;
  2423. end;
  2424. procedure TCustomWebWidget.ApplyData;
  2425. Var
  2426. AID : String;
  2427. Procedure MaybeSet(El : TJSHTMLElement; AName : String);
  2428. begin
  2429. if Assigned(el) then
  2430. el.Dataset[aName]:=AID;
  2431. end;
  2432. begin
  2433. AID:=ElementID;
  2434. if assigned(Element) then
  2435. Element.dataset[SElementClass]:=ClassName;
  2436. MaybeSet(Element,SElementData);
  2437. MaybeSet(TopElement,STopElementData);
  2438. if AllowChildren then
  2439. MaybeSet(ContentElement,SContentElementData);
  2440. end;
  2441. procedure TCustomWebWidget.RemoveData;
  2442. Procedure MaybeUnSet(El : TJSHTMLElement; AName : String);
  2443. begin
  2444. if Assigned(el) then
  2445. jsDelete(el.Dataset,aName);
  2446. end;
  2447. begin
  2448. MaybeUnSet(Element,SElementData);
  2449. MaybeUnSet(TopElement,STopElementData);
  2450. MaybeUnSet(ContentElement,SContentElementData);
  2451. end;
  2452. procedure TCustomWebWidget.RefreshReferences;
  2453. begin
  2454. if Assigned(FReferences) then
  2455. if Assigned(Element) then
  2456. References.RefreshFromDom(GetReferenceElement)
  2457. else
  2458. References.FRefs:=Nil;
  2459. end;
  2460. class function TCustomWebWidget.GenerateID: String;
  2461. begin
  2462. Inc(WidgetID);
  2463. Result:='ww-'+intToStr(WidgetID);
  2464. end;
  2465. function TCustomWebWidget.RenderHTML(aParent: TJSHTMLELement): TJSHTMLElement;
  2466. Var
  2467. aTag : String;
  2468. begin
  2469. aTag:=HTMLTag;
  2470. if aTag='' then
  2471. Result:=Nil
  2472. else
  2473. begin
  2474. Result:=FixedElement;
  2475. if Result=Nil then
  2476. Result:=CreateElement(HTMLTag,GenerateID);
  2477. end;
  2478. if Assigned(Result) and Assigned(aParent) then
  2479. aParent.AppendChild(Result);
  2480. if Assigned(FBeforeRenderHTML) then
  2481. FBeforeRenderHTML(Self);
  2482. Result:=DoRenderHTML(aParent,Result);
  2483. if Assigned(Result) then
  2484. begin
  2485. ApplyWidgetSettings(Result);
  2486. HookupEvents(Result);
  2487. end;
  2488. if Assigned(FAfterRenderHTML) then
  2489. FAfterRenderHTML(Self);
  2490. end;
  2491. procedure TCustomWebWidget.DoUnRender(aParent: TJSHTMLElement);
  2492. Var
  2493. el : TJSHTMLElement;
  2494. begin
  2495. if Assigned(aParent) and Assigned(FElement) then
  2496. begin
  2497. if FOwnsElement then
  2498. begin
  2499. el:=TopElement;
  2500. if (El.ParentElement=aParent) then
  2501. aParent.removeChild(el);
  2502. end;
  2503. InvalidateElement;
  2504. end;
  2505. end;
  2506. procedure TCustomWebWidget.UnRender(aParent: TJSHTMLElement);
  2507. begin
  2508. if Assigned(FBeforeUnRenderHTML) then
  2509. FBeforeUnRenderHTML(Self);
  2510. RemoveData;
  2511. if assigned(AParent) then
  2512. DoUnRender(aParent);
  2513. if Assigned(FAfterUnRenderHTML) then
  2514. FAfterUnRenderHTML(Self);
  2515. end;
  2516. function TCustomWebWidget.DispatchEvent(aName: String; aEvent: TJSEvent): Boolean;
  2517. begin
  2518. if not IsRendered then
  2519. exit;
  2520. if (aEvent=Nil) then
  2521. aEvent:=TJSEvent.New(aName);
  2522. Result:=Element.dispatchEvent(aEvent);
  2523. end;
  2524. constructor TCustomWebWidget.Create(aOwner: TComponent);
  2525. begin
  2526. inherited Create(aOwner);
  2527. FChildren:=TJSArray.New;
  2528. FStyles:=CreateStyles;
  2529. FMyHook:=@EventEntry;
  2530. FParent:=DefaultParent;
  2531. FVisible:=True;
  2532. end;
  2533. destructor TCustomWebWidget.Destroy;
  2534. Var
  2535. I : integer;
  2536. C : TCustomWebWidget;
  2537. begin
  2538. For I:=0 to FChildren.Length-1 do
  2539. begin
  2540. C:=TCustomWebWidget(FChildren[i]);
  2541. FChildren[i]:=Nil;
  2542. C.Free;
  2543. end;
  2544. FChildren.Length:=0;
  2545. Parent:=Nil;
  2546. ParentID:='';
  2547. FChildren:=Nil;
  2548. FreeAndNil(FStyles);
  2549. inherited Destroy;
  2550. end;
  2551. class function TCustomWebWidget.AllowChildren: Boolean;
  2552. begin
  2553. Result:=True;
  2554. end;
  2555. class function TCustomWebWidget.RemoveClasses(const Source, aClasses: String; Normalize : Boolean = false): String;
  2556. var
  2557. T : TJSStringDynArray;
  2558. i : integer;
  2559. S : String;
  2560. begin
  2561. Result:=Source;
  2562. if Normalize then
  2563. Result:=TJSString(Result).replace(TJSRegexp.New('\s\s+','g'),' ');
  2564. T:=TJSString(Result).split(' ');
  2565. For S in TJSString(aClasses).split(' ') do
  2566. if (S<>'') then
  2567. begin
  2568. I:=TJSArray(T).indexOf(S);
  2569. if (I<>-1) then
  2570. TJSArray(T).splice(i,1);
  2571. end;
  2572. Result:=TJSArray(T).join(' ');
  2573. end;
  2574. class function TCustomWebWidget.RemoveClasses(el: TJSHTMLElement; const aClasses: String; Normalize : Boolean = false): String;
  2575. begin
  2576. Result:=RemoveClasses(el.ClassName,aClasses,Normalize);
  2577. el.ClassName:=Result;
  2578. end;
  2579. class function TCustomWebWidget.AddClasses(const Source, aClasses: String; Normalize : Boolean = false): String;
  2580. var
  2581. T : TJSStringDynArray;
  2582. S : String;
  2583. begin
  2584. Result:=Source;
  2585. if Normalize then
  2586. Result:=TJSString(Result).replace(TJSRegexp.New('\s\s+','g'),' ');
  2587. if AClasses='' then exit;
  2588. T:=TJSString(Result).split(' ');
  2589. For S in TJSString(aClasses).split(' ') do
  2590. if (S<>'') then
  2591. begin
  2592. if (TJSArray(T).indexOf(S)=-1) then
  2593. TJSArray(T).Push(S);
  2594. end;
  2595. Result:=TJSArray(T).Join(' ');
  2596. end;
  2597. class function TCustomWebWidget.AddClasses(el: TJSHTMLElement; const aClasses: String; Normalize : Boolean = false): String;
  2598. begin
  2599. Result:=AddClasses(el.ClassName,aClasses,Normalize);
  2600. el.ClassName:=Trim(Result);
  2601. end;
  2602. function TCustomWebWidget.RemoveClasses(const aClasses: String; Normalize : Boolean = false): String;
  2603. begin
  2604. FClasses:=RemoveClasses(FClasses,aClasses,Normalize);
  2605. Result:=FClasses;
  2606. if IsRendered then
  2607. Result:=RemoveClasses(FElement,aClasses,Normalize)
  2608. end;
  2609. function TCustomWebWidget.AddClasses(const aClasses: String; Normalize: Boolean): String;
  2610. begin
  2611. FClasses:=AddClasses(FClasses,aClasses,Normalize);
  2612. Result:=FClasses;
  2613. if IsRendered then
  2614. Result:=AddClasses(FElement,aClasses,Normalize)
  2615. end;
  2616. function TCustomWebWidget.FindWidgetByID(aElementID: String; Recurse: Boolean): TCustomWebWidget;
  2617. Var
  2618. I : Integer;
  2619. begin
  2620. Result:=Nil;
  2621. if aElementID='' then
  2622. exit;
  2623. if (aElementID=elementID) then
  2624. Exit(Self);
  2625. I:=ChildCount-1;
  2626. // First this level. Typical layout is not so nested.
  2627. While (i>=0) and (Result=Nil) do
  2628. begin
  2629. Result:=Children[i];
  2630. if (Result.ElementID<>aElementID) then
  2631. Result:=nil;
  2632. Dec(I);
  2633. end;
  2634. If (Result=Nil) and (Recurse) then
  2635. begin
  2636. I:=ChildCount-1;
  2637. While (i>=0) and (Result=Nil) do
  2638. begin
  2639. Result:=Children[i].FindWidgetByID(aElementID,True);
  2640. Dec(I);
  2641. end;
  2642. end;
  2643. end;
  2644. function TCustomWebWidget.GetWidgetByID(aElementID: String; Recurse: Boolean): TCustomWebWidget;
  2645. begin
  2646. Result:=FindWidgetByID(aElementID,Recurse);
  2647. if Result=Nil then
  2648. Raise EWidgets.CreateFmt(SErrWidgetNotFound,[aElementID]);
  2649. end;
  2650. function TCustomWebWidget.EnsureStyle(const aName: String): TStyleItem;
  2651. begin
  2652. Result:=Styles.EnsureStyle(aName);
  2653. end;
  2654. function TCustomWebWidget.AddStyle(const aName, aValue: String): TStyleItem;
  2655. begin
  2656. Result:=EnsureStyle(aName);
  2657. Result.Value:=aValue;
  2658. end;
  2659. function TCustomWebWidget.GetStyleValue(const aName : String): String;
  2660. Var
  2661. S : TStyleItem;
  2662. begin
  2663. S:=Styles.FindStyle(aName);
  2664. if Assigned(S) then
  2665. Result:=S.Value
  2666. else
  2667. Result:='';
  2668. end;
  2669. function TCustomWebWidget.RemoveStyle(const aName: String): String;
  2670. begin
  2671. Result:=Styles.RemoveStyle(aName);
  2672. end;
  2673. procedure TCustomWebWidget.RemoveData(const aName: String);
  2674. begin
  2675. if IsRendered then
  2676. jsDelete(Element.Dataset,aName)
  2677. end;
  2678. end.