2
0

webwidget.pas 91 KB

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