webwidget.pas 86 KB

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