webwidget.pas 90 KB

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