Extindeți TMS WEB Core cu bibliotecile JS cu Andrew: FlatPickr (partea 2)

TMS Software Componente Delphi
Ultima dată, ne-am uitat la cum să încorporăm FlatPickr într-un proiect TMS WEB Core. Am luat ceea ce ar putea fi considerat abordarea manuală. Un link către un CDN sau altă sursă pentru bibliotecă este adăugat la fișierul Project.html , iar apoi un mic cod JavaScript este folosit pentru a lega manual codul bibliotecii la un element care a fost plasat pe un TWebForm . Acest lucru funcționează destul de bine și, de obicei, folosesc aceasta și multe alte biblioteci JS în proiectele mele. Dar există o altă modalitate care ar putea fi mai în concordanță cu modul în care Delphi este utilizat în mare parte a timpului – prin utilizarea componentelor. Deci, în această postare, vom revizui aceeași bibliotecă JS, dar vom parcurge cum să creați o componentă care va apărea în paleta de componente a IDE-ului Delphi. De acolo, vom putea adăuga controale FlatPickr la orice TWebForm sau oriunde avem nevoie să apară componenta, la fel de ușor ca și cu un TWebLabel sau un TWebEdit . Și vom putea ajusta multe dintre opțiunile pe care dorim să le transmitem la FlatPickr setând proprietăți în Delphi IDE Object Inspector.

Motivația.

Dincolo de a facilita utilizarea FlatPickr într-o aplicație TMS WEB Core, ideea acestei postări este de a înțelege cum să creați un pachet Delphi care poate include multe astfel de controale. Pe măsură ce ne facem drum prin mai multe biblioteci JS și controalele acestora în postările viitoare, sperăm că vom putea face upgrade acest pachet și cu acele noi comenzi și poate chiar vom arunca și altele pe parcurs. Acest pachet poate fi apoi instalat de oricine lucrează la proiectele TMS WEB Core și, astfel, obțineți acces mai ușor la toate bibliotecile JS pe care le acoperim într-un singur pas simplu.

Rețineți că, dacă utilizați o bibliotecă JS într-o situație unică, munca necesară pentru a crea un pachet de componente este probabil să fie substanțial mai mult decât abordarea manuală. Dar există potențialul de a economisi timp și efort în (cel puțin) următoarele scenarii.

  • Când doriți să utilizați mai multe instanțe ale unei componente, poate în mai multe forme.
  • Când doriți să utilizați aceeași componentă în mai multe proiecte.
  • Când nu doriți să fiți nevoit să vă amestecați cu JavaScript sau cu nuanțele bibliotecii JS de bază.
  • Când doriți să creați ceva pentru a fi folosit cu alții, economisindu-le timp și efort.

Având aceste tipuri de controale în Delphi, puteți pur și simplu să lucrați așa cum ați proceda în mod normal, fără a fi nevoie să știți că utilizați o bibliotecă JavaScript.

Crearea unui pachet.

Dar înainte de a crea componente, primul lucru pe care îl vom face este să creăm un pachet care să dețină aceste tipuri de componente. Ieșit de la poartă, avem câteva lucruri de acoperit. Scrierea aplicațiilor TMS WEB Core în Delphi înseamnă că folosim IDE-ul Delphi pentru a face o parte din lucru și apoi transpilăm codul folosind pas2js în culise pentru a produce codul final care rulează într-un browser. Dar Delphi IDE nu știe prea multe despre JavaScript sau HTML sau CSS sau lucruri de genul – este un mediu Delphi, până la urmă. Și odată ce aplicația rulează într-un browser, a uitat în mare măsură de orice legat de Delphi sau Pascal. Când dezvoltăm componente, trebuie, de asemenea, să căpătăm această diviziune și facem acest lucru furnizând, în esență, două versiuni ale componentei – una care menține IDE-ul Delphi fericit (versiunea în timp de proiectare) și una care menține compilatorul pas2js fericit (versiunea versiunea de rulare). Vedem acest lucru în TMS WEB Core în sine, unde există două seturi de coduri.

  • Folderul Component Library Source conține toate componentele, dar multe dintre funcții și proceduri sunt doar stub-uri – comentate. Există suficient acolo pentru a activa completarea codului funcțional în IDE-ul Delphi, pentru a oferi proprietăți prin Inspectorul de obiecte și poate chiar și câteva pictograme pentru Paleta de componente. Dar nu mult mai mult decât atât.
  • Dosarul Core Source conține toate aceleași componente, dar o implementare separată a tuturor funcțiilor și procedurilor, claselor și așa mai departe care trebuie compilate în aplicația finală.

Pot apărea probleme dacă există discrepanțe între stub-urile din folderul Component Library Source și echivalentele lor din folderul Core Source. Este adesea o sursă de confuzie (unii ar putea spune alarmă!) atunci când se uită la codul din Sursa bibliotecii de componente, doar pentru a găsi nimic altceva decât stub-uri. Configurarea Delphi pentru a utiliza acest aranjament de foldere nu este dificilă – programul de instalare TMS WEB Core face acest lucru pentru dvs. în mod implicit. Dar, dacă sunteți genul care ține, modificarea modului în care acestea sunt prezentate la Delphi este o modalitate destul de solidă de a cauza probleme. Atunci când dezvoltăm componente, trebuie să ținem cont și de acest aranjament. De asemenea, vom avea nevoie de două seturi de cod – unul pentru mediul IDE de proiectare și unul pentru mediul JavaScript de rulare.

Suita noastră (eventuală) de componente va fi cunoscută sub numele de Pachetul JSExtend. Deci, vom începe prin a crea un folder JSExtend în folderul nostru obișnuit Delphi Projects. Și apoi, în cadrul acestui folder, vom crea un folder separat Design-Time și Run-Time pentru a urma aceeași idee ca și folderele Component Library Source și Core Source. Folderul Design-Time va conține apoi tot ce vom avea nevoie în IDE-ul Delphi, iar folderul Run-Time va conține tot ce vom avea nevoie la compilarea aplicației JavaScript finale.

…ProiecteJSExtend

…ProjectsJSExtendDesign-Time

…ProjectsJSExtendRun-Time

Pachetul Design-Time.

Să ne ocupăm mai întâi de pachetul Design-Time. Acesta este ceea ce va fi folosit în IDE-ul Delphi. Pornind de la nimic, primul pas este să folosiți New/File pentru a crea un nou pachet. Rețineți că folosesc Delphi 10.3.2 pentru aceasta (și TMS WEB Core 1.9.8.3), așa că este posibil să nu arate la fel dacă utilizați o versiune diferită de Delphi. Când lucrați la aplicațiile TMS WEB Core din Delphi, este mai mult sau mai puțin un mediu VCL. Deci nu trebuie să facem inițial nimic specific pentru TMS WEB Core aici, trebuie doar să creăm un nou pachet Delphi.

TMS Software Componente Delphi

Crearea unui nou pachet Delphi

După crearea pachetului Delphi, salvarea acestuia vă va solicita un folder în care să-l puneți (JSExtend/Design-Time), apoi numele proiectului (JSExtend) și numele grupului de proiecte (JSExtend Group). Dacă apoi construiești proiectul, nu prea face prea mult. Dar, de asemenea, nu ar trebui să aibă erori, avertismente sau indicii în această etapă. Ai putea chiar să-l instalezi, dar întrucât nu are componente, acest lucru nu va fi de mare folos.

Crearea unei componente.

Foarte, foarte, foarte ultima secțiune din documentația TMS WEB Core acoperă crearea a patru tipuri diferite de componente.

  1. Componente non-vizuale.
  2. Componente HTML.
  3. Componente FNC.
  4. Componentele jQuery.
Componentele non-vizuale pot fi utile pentru situațiile în care există doar tipuri de date sau funcții care trebuie să fie împachetate într-o componentă. Vom încerca această abordare când vom ajunge la Luxon , de exemplu, care nu are elemente vizuale. Orice bibliotecă JS care nu este un Control ar putea intra în acest tip de componentă.

Componentele HTML sunt folosite atunci când doriți să utilizați un fel de element HTML ca bază pentru componenta dvs. Este exact ceea ce căutăm. Dar să ne uităm rapid la celelalte tipuri de componente doar pentru a ne asigura că aceasta este cea mai bună.

Componentele FNC sunt grozave atunci când doriți să aveți o componentă care funcționează pe toate platformele pe care le acceptă FNC, cum ar fi WEB, VCL, FireMonkey, iOS, Android și așa mai departe. Este poate mai aplicabil atunci când doriți să trageți singur controlul. În HTML, acest lucru înseamnă probabil utilizarea intensă a elementelor , care vă permit să oglindiți îndeaproape modul în care ați putea desena aceleași controale într-un mediu VCL. Toate bune, dar nu în special ceea ce încercăm să facem aici. FlatPickr poate avea grijă de desenul singur. Și nu sunt un fan al etichetei , deoarece tinde să interfereze cu eforturile de tematică. Totuși, există o mulțime de alte motive solide pentru a utiliza FNC și nu este neapărat o cerință de a folosi , așa că ceva pe care să fii cu ochii pe ochi, mai ales dacă vrei să creezi componente multi-platformă.

Componentele jQuery sunt o potrivire naturală, desigur, atunci când doriți să creați o componentă Delphi care utilizează o bibliotecă JavaScript jQuery. În cazul nostru, deoarece FlatPickr în sine nu necesită jQuery, nu are sens să introducem jQuery ca dependență doar pentru a-l folosi ca componentă. Dacă jQuery face deja parte din proiectul dvs., atunci această abordare poate funcționa cel mai bine. Există, de asemenea, destul de multe componente jQuery care sunt incluse implicit cu TMS WEB Core care merită verificate, atât pentru utilizarea în propriile proiecte, cât și pentru exemple de creație de componente.

Pentru scopurile noastre, #2 pare a fi cea mai bună potrivire. FlatPickr are nevoie de un element HTML la care să se lege și nu prea multe altele pentru a începe.

Crearea unei componente începe cu selectarea Componente/Componentă nouă… din meniul Delphi IDE. Pentru primul ecran, vom alege VCL, dar puțin mai târziu va trebui să facem câteva modificări pentru a ne asigura că această componentă este disponibilă într-o aplicație TMS WEB Core.

TMS Software Componente Delphi

Deoarece lucrăm cu TMS WEB Core , clasa strămoșească pe care dorim să o folosim este TWebCustomComponent .

TMS Software Componente Delphi

Pagina următoare mai pune câteva întrebări. Vom dori ca aceste componente să fie adunate împreună în propriul lor grup în Paleta de componente Delphi, de exemplu.

TMS Software Componente Delphi

Ultima pagină întreabă unde să creeze unitatea pentru această componentă. Sunt disponibile câteva opțiuni, dar deoarece tocmai am creat un pachet în acest scop, îl vom folosi.

TMS Software Componente Delphi

Aceasta este urmată de un dialog care vă întreabă unde să salvați unitatea. Va intra în folderul Design-Time. Poate apărea și un alt mesaj. Aici am spus doar „Da”. Vom aborda problema despre care vorbește mesajul în doar un moment.

TMS Software Componente Delphi

Cu asta din drum, avem acum o nouă componentă cu care să lucrăm. Salvarea și construirea proiectului nu ar trebui să genereze erori, avertismente sau indicii. De fapt, dacă ați instalat pachetul, ar trebui să funcționeze. Faceți clic dreapta pe JSExtend.bpl în fereastra Project Manager și selectați Instalare. Acesta ar trebui să fie rezultatul. Toate bune până acum!

TMS Software Componente Delphi

Dar, desigur, nu vrem să facem asta încă. Aceasta este doar o componentă VCL implicită. Va trebui să facem ceva mai multă muncă pentru a-l pune în formă pentru scopurile noastre.

Pictograma paletă de componente.

Componentele care apar în Paleta de componente au de obicei o pictogramă. Uneori nu o fac și ajungi cu pictograma implicită, așa.

TMS Software Componente Delphi

Este destul de plictisitor, dar se rezolvă ușor. Veți avea nevoie de o imagine BMP (nu ICO, JPG sau PNG) pentru a începe. Apoi, în meniul Proiect, alegeți Resurse și imagini … și adăugați în bitmap. „Smecheria” aici este că numele resursei ar trebui să fie același cu numele componentei, dar cu majuscule. Nu știu dacă dimensiunea imaginii contează mult (am încercat câteva) dar se pare că se scalează rezonabil de bine. Dacă utilizați o versiune mai veche a Delphi, este posibil ca acest proces să nu fie la fel de plăcut și probabil va trebui să utilizați un Bitmap de o anumită dimensiune. 24px x 24px este probabil locul unde veți dori să începeți.

TMS Software Componente Delphi

Reinstalarea pachetului a actualizat pictograma. Nicio problemă.

TMS Software Componente Delphi

Rețineți că pentru a vedea componenta în Paleta de componente, a trebuit să lucrez cu un TForm. Dacă lucram la un TWebForm sau la un alt bit din Delphi care nu avea un formular, atunci această componentă nu ar apărea în Paleta de componente. Deci, să abordăm asta în continuare.

Platforme componente.

Până acum, avem o componentă în pachetul nostru care, atunci când este instalată, va apărea în lista de componente pentru un TForm. Dar pentru ca acesta să fie disponibil ca componentă pentru un TWebForm, trebuie să adăugăm un atribut la clasa noastră, [ComponentPlatforms(TMSWebPlatform)] . Sursa noastră de componente (gol) arată acum ca următorul.

 unitate JSFlatPickr;

interfata

utilizări
System.SysUtils, System.Classes, Vcl.Controls, WEBLib.Controls;

tip
[ComponentPlatforms(TMSWebPlatform)]
TJSFlatPickr = clasa (TWebCustomControl)
privat
{ Declarații private }
protejat
{ Declarații protejate }
public
{ Declarații publice }
publicat
{ Declarații publicate }
Sfârşit;

Registrul de procedură;

implementare

Registrul de procedură;
ÎNCEPE
RegisterComponents('JSExtend', [TJSFlatPickr]);
Sfârşit;

Sfârşit.

Instalarea (sau reinstalarea) componentei după această modificare ar trebui să însemne că, dacă edităm un TWebForm în IDE, componenta va apărea așa cum era de așteptat, de obicei în partea de jos a listei Paletei de componente. Tot ar trebui să apară și atunci când lucrați cu un TForm VCL, dar dacă încercați să-l adăugați la formular, probabil veți primi următorul mesaj. Ceea ce ne dorim să se întâmple.

TMS Software Componente Delphi

NOTĂ: În funcție de ordinea în care faceți lucrurile, acest lucru poate sau nu să meargă fără probleme. Se pare că Delphi are un „Package Cache” în Registrul Windows care nu este neapărat actualizat atunci când se efectuează anumite tipuri de modificări. Și adăugarea unui atribut în acest mod pare să se califice. Deci, deși încă puteam vedea componenta pe TForms, nu era vizibilă inițial când lucram cu TWebForms după adăugarea atributului, chiar și la reinstalarea pachetului. Nici repornirea IDE-ului nu a ajutat. Ceea ce părea să funcționeze au fost următorii pași. Probabil că ar putea sări peste unele dintre ele, dar acest lucru durează doar un moment în orice caz.

  1. Proiect/Construiește totul
  2. Dezinstalați pachetul folosind Project Manager
  3. Închide Delphi
  4. Porniți RegEdit
  5. Căutați în Regedit clasa (TJSFlatPickr în acest caz)
  6. Ștergeți întreaga cheie de pachet care apare sub Package Cache, de exemplu: Delete HKEY_CURRENT_USERSOFTWAREEmbarcaderoBDS20.0Package CacheJSExtend.bp
  7. Închide RegEdit
  8. Porniți Delphi
  9. Proiect/Construiește totul
  10. Instalați pachetul folosind Project Manager

După aceea, componenta a apărut conform așteptărilor. Un fel de durere, dar aceasta era singura situație în care era nevoie de asta. Dacă nu aș fi instalat componenta în pasul anterior și aș fi instalat-o în schimb după adăugarea atributului, probabil că acest lucru nu ar fi fost deloc o problemă.

Care este echivalentul metric al Inching Forward?

Pași mici aici, oricum. Deci, în continuare, este să adăugăm câteva proprietăți controlului nostru, doar pentru a testa puțin apele. Putem seta dimensiunea implicită a controlului atunci când este aruncat pe un formular, de exemplu. Una dintre proprietățile de care vom avea nevoie cu siguranță este „inline” – o opțiune booleană care determină dacă întregul calendar FlatPickr este vizibil sau dacă este doar un câmp de intrare care are un calendar drop-down. O altă opțiune booleană este dacă să „activezi Time” în control. În cele din urmă, vom ajunge la întreaga listă de opțiuni care se află pe site-ul FlatPickr, dar haideți să le încercăm mai întâi.

Pentru ca proprietățile să fie accesibile din IDE, acestea trebuie adăugate la declarațiile publicate ale unității. Acești primi parametri sunt de tip boolean și ar trebui să aibă o valoare implicită False . Puteți modifica setările implicite aici dacă preferați ceva diferit, cum ar fi versiunea „inline” a selectorului de date afișată implicit. Vom rămâne cu orice FlatPickr a ales pentru propriile valori implicite. Și, doar pentru a fi enervant, nu putem folosi „inline” deoarece este un cuvânt cheie rezervat. Deci, vom merge cu „CalendarInline” în schimb. Valoarea acestor proprietăți trebuie, de asemenea, stocată undeva. Puțin în afara subiectului în acest moment, dar vom defini unele câmpuri ca parte a clasei și apoi vom face referire la ele în declarația de proprietate. Prefixul „F” este menit să fie un memento că acestea sunt „câmpuri” și nu „variabile”.

Noua noastră componentă este construită dintr-un TWebCustomComponent, așa că are deja o structură destul de mare. Singurul lucru pe care îl vom face este doar să reglam dimensiunea controlului atunci când este aruncat pe formular. Nu pentru un motiv anume, decât pentru a vă aminti că va trebui să se potrivească cumva în aspectul paginii. Dimensiunea finală va depinde de multe lucruri care depășesc cu mult domeniul sau controlul IDE-ului.

Codul din pachetul Design-Time (cu ce avem de-a face aici) este folosit doar în IDE, așa că nu sunt prea multe de făcut aici decât dacă doriți să se întâmple mai multe lucruri când schimbați proprietățile în IDE. În alte medii (cum ar fi VCL), aceasta este o modalitate puternică de a obține o previzualizare a modului în care va arăta controlul atunci când aplicația rulează. Dar în cazul nostru, IDE-ul nu redă HTML sau CSS, așa că nu putem face multe în acest sens. În schimb, vom folosi doar porțiunea IDE ca un fel de instrument de blocare – așa că vom ști cât spațiu este de așteptat să ocupe, dar nu prea mult altceva. Rezultatul acestor modificări este atunci următorul.

 unitate JSFlatPickr;

interfata

utilizări
System.SysUtils, System.Classes, Vcl.Controls, WEBLib.Controls;

tip
[ComponentPlatforms(TMSWebPlatform)]
TJSFlatPickr = clasa (TWebCustomControl)
privat
{ Declarații private }
FCalendarInline: Boolean;
FEnableTime: Boolean;
protejat
{ Declarații protejate }
public
{ Declarații publice }
constructor Create(AOwner: TComponent); trece peste;
publicat
{ Declarații publicate }
proprietate CalendarInline: Boolean citire FCalendarInline scriere FCalendarInline implicit Fals;
proprietate EnableTime: Boolean citire FEnableTime scriere FEnableTime implicit Fals;
Sfârşit;

Registrul de procedură;

implementare

Registrul de procedură;
ÎNCEPE
RegisterComponents('JSExtend', [TJSFlatPickr]);
Sfârşit;

constructor TJSFlatPickr.Create(AOwner: TComponent);
ÎNCEPE
mostenit;
Latime := 200;
Inaltime := 30;
Sfârşit;

Sfârşit.

Toate bune. Acum, când pachetul este reinstalat, adăugarea unei componente TJSFlatPickr la un TWebForm funcționează conform așteptărilor. Dimensiunea implicită a componentei este 200×30 și există două proprietăți noi, CalendarInline și EnableTime , ambele setate la False în mod implicit. Vom adăuga patru doar pentru a încerca cele patru combinații ale celor două proprietăți booleene într-un pic, dar rețineți că nu există nicio modificare vizibilă a componentelor din formular atunci când aceste proprietăți sunt modificate. Iată cum arată.

TMS Software Componente Delphi

Clasificați acea proprietate.

Când utilizați Object Inspector, proprietățile pot fi clasificate. Orice lucru neașteptat apare automat sub Diverse. Deoarece avem o mulțime de proprietăți aici, vom crea o categorie FlatPickr pentru a le pune. Desigur, dacă nu vizualizați lista de proprietăți în forma ei clasificată, acest lucru va avea puțină relevanță pentru dvs. Când aveți de-a face cu pachete, pentru ca acest lucru să funcționeze, este necesar să adăugați DesignIntf la clauza de utilizare a unității noastre TJSFlatPickr , precum și să adăugați designide.dcp la clauza requires a pachetului. Cu acelea la locul lor, putem folosi ceva de genul acesta pentru a clasifica proprietățile. Vom face acest lucru pentru toate proprietățile FlatPickr.

 Registrul de procedură;
ÎNCEPE
RegisterComponents('JSExtend', [TJSFlatPickr]);
RegisterPropertiesInCategory('FlatPickr', TJSFlatPickr, ['CalendarInline', 'EnableTime']);
Sfârşit;

Funcții de proprietate

Proprietățile în acest moment fac doar referire la câmpurile corespunzătoare și nu folosesc nicio funcție get sau set. Acest lucru ar putea fi puțin diferit de numeroasele exemple care plutesc în jurul cărora funcțiile sunt folosite pentru a efectua alte sarcini conexe. În acest caz, nu am făcut acest lucru (încă) doar pentru a face lucrurile simple. La început, vrem doar să folosim aceste proprietăți atunci când inițializam controlul FlatPickr. Vom schimba acest lucru mai târziu, astfel încât componentele create în timpul execuției să poată fi gestionate și prin modificarea proprietăților.

Rețineți, totuși, că în cazul FlatPickr, și probabil în multe alte cazuri, unele proprietăți nu pot fi modificate după ce controlul a fost creat. Acesta este cazul ambelor proprietăți pe care le-am creat și este o „limitare” a FlatPickr, nu a Delphi sau a TMS WEB Core. Deci, a avea flexibilitatea funcțiilor set/get poate fi de puțin ajutor aici și, de asemenea, complică generarea de controale Run-Time unde controlul ar putea fi creat cu o valoare implicită nepotrivită. Vom avea nevoie de o modalitate de a rezolva asta, la care vom ajunge în timp util.

Sursă de rulare.

În regulă. Avem totul din partea Design-Time funcționând așa cum ne-am dori. Acum trebuie să facem ceva similar pentru a implementa partea Run-Time.

În cazul aplicațiilor TMS WEB Core, nu trebuie să trecem prin munca de instalare a unui pachet Run-Time separat, dar trebuie să îi spunem unde să găsească codul, astfel încât să poată fi compilat în proiect. Acest lucru se poate face folosind opțiunile găsite prin meniul Instrumente/Opțiuni… și apoi în TMS WEB / Opțiuni / Calea bibliotecii. Acesta este echivalentul modului în care componentele incluse în TMS WEB Core sunt împărțite între două foldere diferite. Alternativ, puteți doar să adăugați fișiere în proiectul dvs. direct, astfel încât acesta să știe unde să caute, în virtutea faptului că are referința la el în proiectul în sine.

Codul în cauză este doar unitatea JSFlatPickr.pas. În pachetul Design-Time, totul este doar un înveliș pentru această unitate. În versiunea Run-Time, tot ce avem nevoie este unitatea în sine. Deci, locația acestui fișier (și mai târziu, a altor unități din același folder) este de care Delphi trebuie să fie conștient. Folosind Calea Bibliotecii menționată mai sus, fie adăugând unitatea (unitățile) la proiectul dumneavoastră.

Versiunea Run-Time a JSFlatPickr.pas ar trebui să imite în mare măsură versiunea Design-Time, în special în ceea ce privește proprietățile. Dar nu trebuie să ne preocupăm de înregistrarea componentelor. Vrem doar să ne asigurăm că orice valori pe care le-am configurat în IDE sau în Object Inspector sunt accesibile aici în timpul execuției. Iată ce trebuie să începem.

 unitate JSFlatPickr;

interfata

utilizări
Clasuri, WEBLib.Controls, Web;

tip
TJSFlatPickr = clasa (TWebCustomControl)
privat
{ Declarații private }
FIinițializat: boolean;
FCalendarInline: Boolean;
FEnableTime: Boolean;
protejat
{ Declarații protejate }
funcția CreateElement: TJSElement; trece peste;
procedura încărcată; trece peste;
public
{ Declarații publice }
publicat
{ Declarații publicate }
proprietate CalendarInline: Boolean citire FCalendarInline scriere FCalendarInline implicit Fals;
proprietate EnableTime: Boolean citire FEnableTime scriere FEnableTime implicit Fals;
Sfârşit;

implementare

funcția TJSFlatPickr.CreateElement: TJSElement;
ÎNCEPE
Rezultat := document.createElement('DIV');
Sfârşit;

procedura TJSFlatPickr.Loaded;
var
elDIV: TJSElement;
elINPUT: TJSElement;
ÎNCEPE
moștenit Încărcat;

dacă nu (FIinițializat) atunci
ÎNCEPE
FIinițializat := Adevărat;

// Crearea acestei structuri:
// 
// //
elDIV := document.getElementById(ElementID); elINPUT := document.createElement('INPUT'); elDIV.appendChild(elINPUT); // Atașarea FlatPickr la elementul INPUT // Setarea proprietăților așa cum sunt atribuite în IDE asm flatpickr(elINPUT, { inline: this.FCalendarInline, enableTime: this.FEnableTime }) Sfârşit; Sfârşit; Sfârşit; Sfârşit.

Sunt câteva lucruri care se întâmplă aici, care sunt puțin diferite. În primul rând, funcția CreateElement va fi apelată, deoarece fiecare instanță a unei componente TJSFlatPickr se găsește pe TWebForm . Cu toate acestea, aceasta este apelată înainte ca proprietățile din TWebForm (.DFM) să fie încărcate, așa că tot ceea ce facem în acest moment este să creăm primul DIV. Procedura Loaded este apelată atunci când toate proprietățile unei componente au fost încărcate. S-ar putea (sau mai degrabă, foarte probabil) să fie apelat de mai multe ori, așa că am adăugat un câmp FIinițializat la componentă pentru a ne ajuta să ne asigurăm că facem munca de configurare o singură dată pentru fiecare componentă. Probabil că ar putea face același lucru verificând dacă ElementID are o valoare sau nu, dar procedând astfel este ușor de urmărit, de asemenea.

Strămoșul componentei noastre TJSFlatPickr este un TWebCustomControl, deci are toate proprietățile obișnuite precum ElementID și ElementClassName. Când setăm un nou control TJSFlatPickr, ceea ce creăm de fapt este un pic de HTML și apoi rulăm ceva JavaScript care este îndreptat către o anumită parte din acel HTML, așa cum se arată în codul de mai sus. Nimic prea luxos în acest caz, dar este ușor de văzut cum ar putea fi extins acest lucru pentru a gestiona scenarii mai complexe fără prea multe probleme.

Și, în sfârșit, ajungem la subiectul tuturor acestor lucruri, care este codul care inițializează controlul FlatPickr. Cele două opțiuni cu care am ales să începem, inline și enableTime , sunt doar opțiuni booleene care sunt transmise atunci când obiectul FlatPickr JS este creat pentru prima dată. Trebuie să ne prefixăm câmpurile cu „acest”. să funcționeze în blocul JS, dar întrucât avem de-a face doar cu valori booleene, nu este necesar nimic altceva în ceea ce privește conversia proprietăților Delphi Object Inspector în opțiunile obiectului JavaScript. Nu vom fi atât de norocoși cu toate proprietățile, dar pentru început funcționează destul de bine.

După rearanjarea aspectului componentelor și setarea diferitelor combinații de proprietăți CalendarInline și EnableTime , nu este prea mult de văzut în IDE. Rețineți că asta este tot ce am făcut cu adevărat aici pentru o aplicație demo. Creați o nouă aplicație TMS WEB Core. Puneți patru controale TJSFlatPickr pe formular și aranjați-le. Setați cele două proprietăți. Adăugați linkurile FlatPickr JS și CSS la Project.html. Și apoi fugi.

TMS Software Componente Delphi

Dar odată ce aplicația este lansată, ea prinde viață! Fără codificare JS în aplicația demo și nicio indicație reală că JS este chiar o parte din ecuație.

TMS Software Componente Delphi

Mai multe optiuni va rog.

Ce a rămas? Ei bine, există zeci de opțiuni care pot fi transmise unei instanțe FlatPickr atunci când este creată și cel puțin opt evenimente diferite cu care poate comunica. Unele dintre acestea nu sunt deosebit de interesante sau relevante pentru o aplicație TMS WEB Core, dar avem nevoie de mai multe pentru a face din aceasta o componentă viabilă. Cu structura noastră în loc, unele dintre acestea vor fi triviale de implementat. De asemenea, am dori ca aceste lucruri să fie setate la Run-Time, așa că vom rearanja codul pentru a folosi funcțiile get/set pentru a realiza acest lucru. Deci, să abordăm mai întâi elementele ușoare – tipurile de opțiuni simple.

Există un număr bun de opțiuni booleene. Am acoperit deja două dintre ele, așa că adăugarea celorlalte este destul de ușoară. Singurele lucruri la care mă gândesc aici sunt să păstrez numele opțiunilor cât mai aproape de ceea ce este pe site-ul FlatPickr și să mă asigur că valorile implicite sunt aceleași. Iată lista completă a opțiunilor booleene.

  • altInput (fals)
  • allowInput (fals)
  • allowInvalidPreload (fals)
  • anima (adevărat)
  • faceți clic pe Deschide (adevărat)
  • disableMobile (fals)
  • enableTime (fals)
  • enableSeconds (False)
  • inline (fals)
  • noCalendar (fals)
  • shortHandCurrentMonth (fals)
  • static (fals)
  • time_24hr (fals)
  • weekNumbers (fals)
  • înfășurare (fals)

Cele două care nu vor funcționa (deoarece sunt cuvinte cheie rezervate Delphi) vor primi un prefix Calendar, așa că le vom numi CalendarInline și CalendarStatic. În caz contrar, acestea urmează același model pe care l-am folosit deja. Ar putea folosi la fel de ușor un sufix sau orice alt nume.

Urmează câmpurile întregi. Nu la fel de multe dintre acestea, dar totuși utile. Nu vom face prea multe în privința verificării erorilor aici, așa că dacă doriți să le setați la ceva ridicol, sunt sigur că veți fi recompensat în natură. Nu există o mare diferență când vine vorba de proprietăți care sunt întregi în loc de boolee. Se aplică în continuare setările implicite. În general, cu cât plasăm mai puține bucăți de cod între componentă și biblioteca JS reală, cu atât mai bine, deoarece vom avea mai puțină muncă de făcut pentru a menține această implementare actuală, pe măsură ce FlatPickr evoluează singur în timp. Iată ce avem pentru opțiunile întregi în acest moment. Din fericire, niciunul dintre acestea nu este cuvinte cheie rezervate Delphi.

  • defaultHour (12)
  • defaultMinute (0)
  • Creștere oră (1)
  • MinutIncrement (5)
  • arataLuni (1)

Următorul tip cel mai dificil de abordat este sfoară. Nu există valori implicite pentru proprietățile șirului – valoarea implicită este automat „”. Dar putem seta valori implicite atunci când componenta este creată, la fel ca atunci când setăm Lățimea și Înălțimea. În lista de opțiuni FlatPickr, există o mână de șiruri simple pe care le putem configura aici. Există, de asemenea, câteva care sunt listate ca șir, dar sunt într-adevăr un set de opțiuni fixe. Și apoi sunt unele care sunt cu totul altceva. Așa că vom ajunge la acestea într-o clipă. Șirurile simple sunt după cum urmează.

  • altFormat (“F j, Y”)
  • altInputClass (“”)
  • ariaDateFormat (“F j, Y”)
  • conjuncție (“”)
  • dateFormat (“Ymd”)
  • nextArrow (“>”)
  • prevArrow (“<")
Rețineți că atunci când vine vorba de jetoane de formatare a datei, nu mai suntem în Delphi. FlatPickr are propria sa listă surprinzător de scurtă pe care o puteți găsi aici . Personal îmi plac valorile implicite (în afară de timp – care ar trebui să fie 24 de ore în mod implicit), deoarece este de obicei versiunea mai frumoasă a ISO8601, cum ar fi 2022-02-22 22:22:22, de exemplu. Dar dacă preferați altceva, fie pentru introducere, fie pentru afișare, aveți o mulțime de opțiuni. Vom aprofunda acest subiect când vom aborda Luxon.
  • adăuga la ()
  • pozițieElement ()

Aceste ultime două elemente, appendTo și positionElement, sunt puțin speciale prin faptul că vom folosi orice șir furnizat (dacă există) ca o căutare pentru valoarea elementului HTML.

Mai multe dintre opțiuni sunt de tip șir, dar sunt într-adevăr mai mult ca o listă de opțiuni. Nu chiar un tip enumerat, deoarece sunt de fapt șiruri de caractere, dar în Object Inspector am prefera ca opțiunile disponibile să fie limitate la lista pe care FlatPickr o așteaptă, deci da, tipuri enumerate. Iată cu ce avem de-a face.

  • mod (“singur”, “multiplu” sau “gamă”)
  • poziție („automat”, „deasupra”, „dedesubt”, „auto stânga”, „autocentr”, „auto dreapta”, „sus stânga”, „deasupra centrului”, „sus dreapta”, „sub stânga”, „ dedesubt centru”, „dreapta jos”)
  • monthSelectorType (“menu derulant”, “static”)

Modul în care a fost configurat este de a defini un tip separat pentru fiecare dintre acestea (TJSFPmode, TJSFPposition, TJSFPmonthselector) și apoi lăsați Inspectorul de obiecte să facă munca grea de a crea casete combinate și restul.

În continuare, destul de ironic, va trebui să ne ocupăm de unele proprietăți care se referă la date. Inspectorul de obiecte Delphi are un mod frumos de a trata proprietățile TDate (da!), dar se pare că nu pentru TDateTimes sau TTimes (huu!). Din fericire, ne vom putea descurca doar cu TDate pentru opțiunile minDate și maxDate. Este posibil să creez un editor personalizat de proprietăți TDateTime și am fost tentat 😉 dar de fapt nu există prea multă justificare pentru asta aici. Rețineți, totuși, că trebuie să convertim din Delphi TDates în date JS, care este opusul a ceea ce am acoperit data trecută. „Înțelegerea” aici este că codul JS care generează date (folosind un TDateTime decodat) folosește luni bazate pe zero.

În afară de opțiunile legate de funcții, ne aflăm la ultimele trei – defaultDate, activat și dezactivat. Acestea sunt puțin complicate, deoarece toate pot fi matrice de date. Și există câteva moduri nebunești prin care matricele pot fi furnizate aici, cu mult dincolo de orice ar putea fi de așteptat să se ocupe de Object Inspector (sau orice UI, într-adevăr). În cazul defaultDate, valoarea poate fi o dată reală, ca valoarea implicită a Today() sau poate Now() dacă vrem să includem ora. Dar poate fi, de asemenea, matrice care indică ce date sunt selectate inițial. Și „matrice” este plural aici, ceea ce înseamnă că puteți trece mai multe matrice FlatPickr. În mod similar, activat și dezactivat se referă la matrice de date care sunt fie activate, fie dezactivate în calendar. Vom avea nevoie de nume diferite pentru acestea, desigur, dar cum să ne descurcăm cu o serie de date?

Pentru defaultDate, gândirea aici este că în marea majoritate a timpului acesta fie va fi setat la data/ora curentă, fie va fi setat la o anumită dată. Nu eliminăm opțiunile aici – există întotdeauna posibilitatea de a folosi JS pentru a face modificări direct la instanța FlatPickr, chiar și după ce aceasta a fost creată. Este doar o chestiune de cât de mult poate fi înghesuit în Object Inspector și totuși să fie util. O vom aborda pe aceasta cu trei proprietăți. Prima, defaultDate va fi o listă enumerată TJSFPdefault(Acum, Azi, Personalizat). defaultDateStart și defaultDateEnd end vor fi TDates. Dacă defaultDate este Now sau Today, Now() sau Today() vor fi atribuite. Dacă Personalizat, atunci defaultDateStart va fi atribuit. Pentru activat și dezactivat, vom presupune doar că este un interval care este necesar, așa că vom avea enabledStart, enabledEnd, disabledStart și disabledEnd, care ajută la problema cu cuvintele cheie rezervate și oferă o oarecare flexibilitate. Dacă oricare dintre acestea nu este setat, atunci opțiunea nu este setată.

Există unele cazuri în care o opțiune poate afecta alta. De exemplu, dacă setați un interval de date activate, dar apoi setați defaultDate să fie ceva în afara intervalului respectiv, controlul nu o va accepta în mod normal (consultați allowInvalidPreload dacă doriți de fapt să faceți acest lucru). Nu vom face mare lucru în privința asta, lăsând-o pe FlatPickr să-și rezolve propriile afaceri în acest sens. Cu toate acestea în minte, iată unde suntem înainte de a ajunge la funcții. În mod similar, scopul este ca un nou control să funcționeze cu setările implicite atunci când o componentă este pentru prima dată aruncată în formular. Dar nu este nevoie de multă lăutari pentru a introduce ciudățenii în amestec. Vom „privi în altă parte” pentru moment și vom presupune doar că dezvoltatorul setează proprietăți la valori care nu distrug lucrurile în mod inutil.

După ce am adăugat toate opțiunile ca proprietăți, iată unde ne aflăm.

 unitate JSFlatPickr;

interfata

utilizări
Clase, WEBLib.Controls, Web, SysUtils;

tip
TJSFPmode = (mdSingle, mdMultiple, mdRange);
TJSFPposition = (poAuto, poAbove, poBelow, poAutoLeft, poAutoCenter, poAutoRight, poAboveLeft, poAboveCenter, poAboveRight, poBelowLeft, poBelowCenter, poBelowRight);
TJSFPmonthselectortype = (msDropDown, msStatic);
TJSFPdefaultdate = (ddAcum, ddToday, ddCustom);

TJSFlatPickr = clasa (TWebCustomControl)
privat
{ Declarații private }
FIinițializat: boolean;
// Proprietăți booleene
FAltInput: boolean;
FAllowInput: boolean;
FAllowInvalidPreload: boolean;
FAnimate: boolean;
FClickOpens: boolean;
FDisableMobile: boolean;
FEnableSeconds: boolean;
FEnableTime: Boolean;
FCalendarInline: Boolean;
FNoCalendar: Boolean;
FShortHandCurrentMonth: boolean;
FCalendarStatic: Boolean;
FTime_24hr: boolean;
FWeekNumbers: boolean;
FWrap: boolean;
// Proprietăți întregi
FDefaultHour: Integer;
FDefaultMinute: Integer;
FHourIncrement: Integer;
FMinuteIncrement: Integer;
FShowMonths: întreg;
// Proprietăți șir
FAltFormat: String;
FAltInputClass: String;
FariaDateFormat: String;
FCconjuncție: șir;
FDateFormat: String;
FNextArrow: șir;
FPrevArrow: șir;
FAppendTo: șir;
FPositionElement: String;
FMode: TJSFPmode;
FPoziție: TJSFPpoziție;
FMonthSelectorType: TJSFPmonthselectortype;
// Proprietăți date
FMinDate: TDate;
FMaxDate: TDate;
FDefaultDate: TJSFPdefaultDate;
FDefaultDateStart: TDate;
FDefaultDateEnd: TDate;
FDisabledStart: TDate;
FDisabledEnd: TDate;
FEnabledStart: TDate;
FEnabledEnd: TDate;
protejat
{ Declarații protejate }
funcția CreateElement: TJSElement; trece peste;
procedura încărcată; trece peste;
public
{ Declarații publice }
publicat
{ Declarații publicate }
// Proprietăți booleene
proprietate AltInput: Boolean citire FAltInput scriere FAltInput implicit Fals;
proprietate AllowInput: Boolean citire FAllowInput scriere FAllowInput implicit Fals;
proprietate AllowInvalidPreload: Boolean citire FAllowInvalidPreload scrie FAllowInvalidPreload implicit Fals;
proprietate Animate: citire booleană FAnimate scriere FAnimate implicită Adevărat;
proprietate ClickOpens: Boolean citire FClickOpens scriere FClickOpens implicit Adevărat;
proprietate DisableMobile: Boolean citire FDisableMobile scriere FDisableMobile implicit Fals;
proprietate EnableSeconds: Boolean citiți FEnableSeconds scrieți FEnableSeconds implicit Fals;
proprietate EnableTime: Boolean citire FEnableTime scriere FEnableTime implicit Fals;
proprietate CalendarInline: Boolean citire FCalendarInline scriere FCalendarInline implicit Fals;
proprietate NoCalendar: Boolean citiți FNoCalendar scrieți FNoCalendar implicit Fals;
proprietate ShortHandCurrentMonth: Boolean citiți FShortHandCurrentMonth scrieți FShortHandCurrentMonth implicit Fals;
proprietate CalendarStatic: Boolean citire FCalendarStatic scriere FCalendarStatic implicit Fals;
proprietate Time_24hr: Boolean citire FTime_24hr scriere FTime_24hr implicit Fals;
proprietate WeekNumbers: Boolean citiți FWeekNumbers scrieți FWeekNumbers implicit Fals;
proprietate Wrap: Boolean citire FWrap scriere FWrap implicit Fals;
// Proprietăți întregi
proprietate DefaultHour: Integer read FDefaultHour scrie FDefaultHour implicit 12;
proprietate DefaultMinute: Integer read FDefaultMinute scrie FDefaultMinute implicit 0;
proprietate HourIncrement: Integer read FHourIncrement scrie FHourIncrement implicit 1;
proprietate MinuteIncrement: Integer read FMinuteIncrement scrie FMinuteIncrement implicit 5;
proprietate ShowMonths: Integer read FShowMonths scrie FShowMonths implicit 0;
// Proprietăți șir
proprietate AltFormat: String citire FAltFormat scrie FAltFormat;
proprietate AltInputClass: String citire FAltInputClass scrie FAltInputClass;
proprietate AriaDateFormat: String citire FariaDateFormat scrie FariaDateFormat;
proprietate Conjuncție: șir citire FConjunction scrie FConjunction;
proprietate DateFormat: String citire FDateFormat scrie FDateFormat;
proprietate NextArrow: String citește FNextarrow scrie FNextArrow;
proprietate PrevArrow: String citește FPrevArrow scrie FPrevArrow;
proprietate AppendTo: String read FAppendTo scrie FAppendTo;
proprietate PositionElement: String citire FPositionElement scrie FPositionElement;
Mod de proprietate: TJSFPMode citește FMode scrie FMode implicit mdSingle;
proprietate Poziție:TJSFPPosition citire FPosiție scriere FPoziție implicită poAuto;
proprietate MonthSelectorType: TJSFPmonthselectortype citește FMonthSelectorType scrie FMonthSelectorType implicit msDropDown;
// Proprietăți date
proprietate MinDate: TDate citește FMinDate scrie FMinDate;
proprietate MaxDate: TDate citește FMaxDate scrie FMaxDate;
proprietate DefaultDate: TJSFPdefaultDate citește FDefaultDate scrie FDefaultDate default ddNow;
proprietate DefaultDateStart: TDate citește FDefaultDateStart scrie FDefaultDateStart;
proprietate DefaultDateEnd: TDate citește FDefaultDateEnd scrie FDefaultDateEnd;
proprietate DisabledStart: TDate citește FDisabledStart scrie FDisabledStart;
proprietate DisabledEnd: TDate citește FDisabledEnd scrie FDisabledEnd;
proprietate EnabledStart: TDate citește FEnabledStart scrie FEnabledStart;
proprietate EnabledEnd: TDate citește FEnabledEnd scrie FEnabledEnd;
Sfârşit;

implementare

funcția TJSFlatPickr.CreateElement: TJSElement;
ÎNCEPE
Rezultat := document.createElement('DIV');

// Valori implicite booleene
FClickOpens := Adevărat;
FAnimate := Adevărat;
// Valori implicite întregi
FDefaultHour := 12;
FDefaultMinute := 0;
FHourIncrement := 1;
FMinuteIncrement := 5;
FShowMonths := 1;
// String Implicit
FAltFormat := 'F j, Y';
FariaDateFormat := 'F j, Y';
FDateFormat := 'Ym-d';
FNextArrow := '>';
FPrevArrow := '<';
FMode := mdSingle;
FPosition := poAuto;
FMonthSelectorType := msDropDown;
// Date implicite
FDefaultDate := ddNow;
Sfârşit;

procedura TJSFlatPickr.Loaded;
var
elDIV: TJSElement;
elINPUT: TJSElement;

jmode: String;
jsposition: String;
jsmonthselectortype: String;

minYear, minMonth, minDay :Word;
maxYear, maxMonth, maxDay :Word;
ddStartYear, ddStartMonth, ddStartDay, ddStartHour, ddStartMin, ddStartSec, ddStartMSec: Word;
ddEndYear, ddEndMonth, ddEndDay, ddEndHour, ddEndMin, ddEndSec, ddEndMSec: Word;

jsdefaultdate: șir;

jsenabled: șir;
enStartYear, enStartMonth, enStartDay: Word;
EndYear, EndMonth, EndDay: Word;

jsdisabled: șir;
disStartYear, disStartMonth, disStartDay: Word;
disEndYear, disEndMonth, disEndDay: Cuvânt;

ÎNCEPE
moștenit Încărcat;

dacă nu (FIinițializat) atunci
ÎNCEPE
FIinițializat := Adevărat;

// Crearea acestei structuri:
// 
// //
elDIV := document.getElementById(ElementID); elINPUT := document.createElement('INPUT'); elDIV.appendChild(elINPUT); // Conversia tipului enumerat Mod în șir dacă FMode = mdSingle atunci jsmode := 'single' altfel, dacă FMode = mdMultiple, atunci jsmode := 'multiplu' else if FMODe = mdRange atunci jsmode := 'range'; // Convertește tipul enumerat de poziție în șir dacă FPosition = poAuto, atunci jsposition := 'auto' altfel, dacă FPosition = poAbove, atunci jsposition := 'mai sus' altfel, dacă FPosition = poBelow, atunci jsposition := 'mai jos' altfel, dacă FPosition = poAutoLeft atunci jsposition := 'auto stânga' altfel, dacă FPosition = poAutoCenter, atunci jsposition := 'auto center' altfel, dacă FPosition = poAutoRight, atunci jsposition := 'auto right' altfel, dacă FPosition = poAboveLeft, atunci jsposition := 'sus stânga' altfel, dacă FPosition = poAboveCenter, atunci jsposition := „deasupra centrului” altfel, dacă FPosition = poAboveRight, atunci jsposition := 'sus dreapta' altfel, dacă FPosition = poBelowLeft, atunci jsposition := 'jos la stânga' altfel, dacă FPosition = poBelowCenter, atunci jsposition := 'sub centru' else if FPosition = poBelowRight atunci jsposition := 'sub dreapta'; // Convertiți tipul enumerat MonthSelectorType în șir dacă FMonthSelectortype = msDropDown, atunci jsmonthselectortype := „dropdown” else if FMonthSelectorType = msStatic atunci jsmonthselectortype := 'static'; // Convertiți MinDate, MaxDate, DefaultStart/End în ceva ce poate folosi JS DecodeDate(FMinDate, minYear, minMonth, minDay); DecodeDate(FMaxDate, maxYear, maxMonth, maxDay); DecodeDate(FDefaultDateStart, ddStartYear, ddStartMonth, ddStartDay); DecodeTime(FdefaultDateSTart,ddStartHour, ddStartMin, ddStartSec, ddStartMSec); DecodeDate(FDefaultDateEnd, ddEndYear, ddEndMonth, ddEndDay); DecodeTime(FdefaultDateEnd,ddEndHour, ddEndMin, DDEndSec, ddEndMsec); // Ocupați-vă de datele dezactivate dacă (FDisabledStart <> FDisabledEnd) atunci ÎNCEPE jsdisabled := 'da'; DecodeDate(FDisabledStart, disStartYear, disStartMonth, disStartDay); DecodeDate(FDisabledEnd, disEndYEar, disEndMonth, disEndDay); Sfârşit altfel ÎNCEPE jsdisabled := 'nu'; Sfârşit; // Ocupați-vă de datele activate dacă (FEnabledStart <> FEnabledEnd) atunci ÎNCEPE jsenabled := 'da'; DecodeDate(FEnabledStart, enStartYear, enStartMonth, enStartDay); DecodeDate(FEnabledEnd, EndYEar, EndMonth, EndDay); Sfârşit altfel ÎNCEPE jsenabled := 'nu'; Sfârşit; // Convertește tipul enumerat defaultDate în șir dacă FDefaultDate = ddNow, atunci jsdefaultdate := 'acum' altfel, dacă FDefaultDate = ddToday, atunci jsdefaultdate := 'azi' else if FDefaultDate = ddCustom atunci jsdefaultDate := 'personalizat'; // Atașarea FlatPickr la elementul INPUT // Setarea proprietăților obiectului așa cum au fost atribuite în IDE asm var fpAppendTo = document.getElementById(this.FAppendTo); var fpPositionElement = document.getElementById(this.FPostionElement); var mindate = new Date(minYear, minMonth-1, minDay, 0, 0, 0, 0); var maxdate = new Date(maxYear, maxMonth-1, maxDay, 0, 0, 0, 0); var defaultDateStart = new Date(ddStartYear, ddStartMonth-1, ddStartDay, ddStartHour, ddStartMin, ddStartSec, ddStartMSec); var defaultDateEnd = new Date(ddEndYear, ddEndMonth-1, ddEndDay, ddEndHour, ddEndMin, ddEndSec, ddEndMSec); var defaultnow = data noua; var disStart = data noua(disStartYear, disStartMonth-1, disStartDay, 0, 0, 0, 0); var disEnd = new Date(disEndYear, disEndMonth-1, disEndDay, 0, 0, 0, 0); var enStart = new Date(enStartYear, enStartMonth-1, enStartDay, 0, 0, 0, 0); var enEnd = new Date(endYear, EndMonth-1, EndDay, 0, 0, 0, 0); flatpickr(elINPUT, { // Proprietăți booleene altInput: this.FAltInput, allowInput: this.FAllowInput, allowInvalidPreload: this.FAllowInvalidPreload, anima: asta.FAnimate, clickOpens: this.FClickOpens, disableMobile: this.FDisableMobile, enableSeconds: this.FEnableSeconds, enableTime: this.FEnableTime, inline: this.FCalendarInline, noCalendar: this.FNoCalendar, shorthandCurrentMonth: this.FShortHandCurrentMonth, static: this.FCalendarStatic, time_24hr: this.FTime_24hr, weekNumbers: this.FWeekNumbers, wrap: this.FWrap, // Proprietăți întregi defaultHour: this.FDefaultHour, defaultMinute: this.FDefaultMinute, hourIncrement: this.FHourIncrement, minuteIncrement: this.FMinuteIncrement, showMonths: this.FShowMonths, // Proprietăți șir altFormat: this.FAltFormat, altInputClass: this.FAltInputClass, ariaDateFormat: this.FAriaDateFormat, conjuncţie: aceasta.FConjuncţie, dateFormat: this.FDateFormat, nextArrow: this.FNextArrow, prevArrow: this.FPrevArrow, ...(!(fpAppendTo === null) && {appendTo: fpAppendTo}), ...(!(fpPositionElement === null) && {positionElement: fpPositionElement}), mod: jsmode, poziție: jsposition, monthSelectorType: jsmonthselectortype, // Proprietăți date minDate: mindate, maxDate: maxdate, ...((jsdefaultdate == 'acum') && {defaultDate: defaultnow}), ...((jsdefaultdate == 'azi') && {defaultDate: defaultnow}), ...((jsdefaultdate == 'personalizat') && {defaultDate: [defaultDateStart, defaultDateEnd]}), ...((jsdisabled == 'da') && {disable: [{de la: disStart, la: disEnd}]}), ...((jsenabled == 'da') && {activare: [{de la: enStart, la: sfârșit}]}), }) Sfârşit; Sfârşit; Sfârşit; Sfârşit.

Funcții

Cu toate astea din drum, cel mai mare lucru rămas este să avem o funcție care să ne spună când s-a schimbat ceva. FlatPickr are o mână (opt la ultimul număr) de „evenimente” diferite care pot fi folosite pentru a obține informații. Principalul care ne interesează este evenimentul onChange. Toate evenimentele FlatPickr trec trei date. Am tratat puțin despre asta data trecută, unde am folosit următoarea funcție:

 procedura TForm1.FlatPickrChanged(selectedDates: matrice de Integer; dateStr: String; instanță: JSValue; tzo:Integer);
var
i: întreg;
ÎNCEPE
console.log('selectedDates: '+IntToStr(Length(selectedDates)));
i := 0;
în timp ce i < Length(selectedDates) do
ÎNCEPE
console.log(intToStr(i)+': '+FormatDateTime('aaaa-mm-zz hh:nn:ss', IncMinute(UnixToDateTime(Trunc(selectedDates[i]/1000)),-tzo)));
i := i + 1;
Sfârşit;
console.log('dateStr: '+DateStr);
Sfârşit;

Deci, de data aceasta, vom dori să facem ceva similar, dar să îl includem automat ca parte a componentei. Pentru a face acest lucru, este definit un nou tip TJSFPOnChange pentru Evenimentul pe care dorim să fie invocat, împreună cu o nouă proprietate OnChange și un câmp FJSFPOnChange care poate fi apoi configurat în IDE. Componenta FlatPickr este apoi configurată să apeleze o funcție separată cu propriii parametri, pe care apoi o formatăm în ceea ce dorim să transmitem evenimentului Delphi.

 ...
TJSFPOnChange = procedura (selectedDates: matrice de Integer; dateStr: String; tzo: Integer) al obiectului;
...
asm {
...
onchanged = this.FlatPickrChanged;
fp = aceasta;
...
// Funcții:
onChange: function(selectedDates, dateStr, instance) {
var d = data noua;
onchanged(fp, selectedDates, dateStr, instance, d.getTimezoneOffset());
...
}

procedura TJSFlatPickr.FlatPickrChanged(FP: TJSFlatPickr; selectatDate: Array of Integer; dateStr: String; instanță: JSValue; tzo: întreg);
...
if Assigned(FP.FJSFPOnChange) atunci FP.FJSFPOnChange(selectedDates, datestr, tzo);
...
Sfârşit;

În aplicația actuală, trebuie doar să faceți dublu clic pe handlerul de evenimente pentru evenimentul onClick și să adăugați ceva de genul acesta.

 procedura TForm1.JSFlatPickr1Change(selectedDates: matrice de Integer; dateStr: șir; tzo: Integer);
ÎNCEPE
showmessage(datestr);
Sfârşit;

La CDN sau nu la CDN.

Și în cele din urmă ajungem la ultimul fragment pe care vreau să-l acopăr. Așa cum am discutat în aproape orice alt articol din această serie, există necesitatea de a conecta la biblioteca JS actuală. Indiferent dacă aceasta este o copie locală, un link furnizat de furnizor sau o versiune CDN generică, va depinde în mare măsură de cât de robustă trebuie să fie aplicația dvs. În acest articol, ne aliniem codul destul de aproape la biblioteca JS de bază. Aceasta înseamnă că s-ar putea face mai multe cazuri pentru găzduirea locală a bibliotecii JS sau, dacă utilizați un CDN, conectarea la o anumită versiune. Din acest motiv, am părăsit pasul de a adăuga biblioteca FlatPickr JS la un proiect ca pas manual.

Există alternative la asta. Există un atribut [JSLibReference] care poate fi adăugat în același loc cu atributul [ComponentPlatforms], care poate fi setat să dețină legăturile JS și CSS necesare. Acest atribut va fi apoi preluat de IDE, care va popula fișierul Project.html atunci când adăugați componenta la un TWebForm. În mod similar, caracteristica Gestionare biblioteci JavaScript a TMS WEB Core poate stoca aceleași legături, dar în cele din urmă trebuie să se ia o decizie cu privire la legăturile să se utilizeze sau dacă să aibă o copie locală, cu linkurile îndreptate spre acea copie. Există câteva exemple de atribut [JSLibReference] care pot fi găsite în folderul Core Source pentru unele dintre componentele livrate cu TMS WEB Core, dacă acest lucru este de interes.

Complicarea puțin este că, în cazul FlatPickr în special, dar și pentru alte biblioteci JS din lista noastră de activități, există și alte părți de CSS sau JS care ar putea fi de dorit să fie incluse. După cum am descris data trecută, pentru FlatPickr sunt disponibile diverse teme prefabricate și le activați pur și simplu incluzând un link către fișierul CSS particular. În cazul CodeMirror (în curând....), există un număr destul de mare de fișiere JS care pot fi incluse care adaugă funcționalitate. Totul pentru a spune că, deși în general este de dorit să existe opțiuni pentru automatizarea a ceea ce ar putea părea greoiul de a adăuga manual biblioteci JS și CSS la un fișier Project.html, probabil că vor exista întotdeauna scenarii în care aceasta este cea mai bună abordare.

Încheiați-l!

Pachetul JSExtend este atașat acestui articol, așa că îl puteți descărca și încerca singur. Codul sursă complet este, de asemenea, disponibil pe GitHub la https://github.com/500Foods/TMS-WEB-Core-JSExtend , astfel încât să îl puteți verifica și acolo, dacă asta este mai mult lucrul dvs. De asemenea, aș dori să primesc un pic mai mult feedback cu privire la părerea dvs. despre această serie de bloguri „Extindeți” până acum. Care a fost partea ta preferată? Cea mai mică parte preferată? Ar trebui să intru în mai multe detalii? Mai puține cuvinte, mai mult cod? Mai puțin cod, mai multe cuvinte? Mai multe capturi de ecran? Videoclipuri? Ne apropiem de jumătatea a ceea ce intenționez să acopăr, așa că acum este șansa de a avea câteva informații despre cum se va desfășura restul.

Mulțumiri!

Andrew Simard.