Browse Source

* Merging revisions 1101,1102,r1103 from trunk:
------------------------------------------------------------------------
r1101 | michael | 2021-03-09 14:58:42 +0100 (Tue, 09 Mar 2021) | 1 line

* flatpickr lib
------------------------------------------------------------------------
r1102 | michael | 2021-03-13 12:36:45 +0100 (Sat, 13 Mar 2021) | 1 line

* StringStream.ReadString/WritString. Fix TMemoryStream.LoadFromStream.
------------------------------------------------------------------------
r1103 | michael | 2021-03-14 09:50:50 +0100 (Sun, 14 Mar 2021) | 1 line

* Amended fix from Bruno Fierens to handle CR/LF in GetNextLineBreak
------------------------------------------------------------------------

michael 4 years ago
parent
commit
716eda5ffd
2 changed files with 380 additions and 20 deletions
  1. 293 0
      packages/flatpickr/libflatpickr.pas
  2. 87 20
      packages/rtl/classes.pas

+ 293 - 0
packages/flatpickr/libflatpickr.pas

@@ -0,0 +1,293 @@
+unit libflatpickr;
+
+{$mode objfpc}
+{$modeswitch externalclass}
+
+interface
+
+uses types, js, web, libjquery;
+
+Type
+  TJSDateDynArray = Array of TJSDate;
+  TJSHTMLElementDynArray = Array of TJSHTMLElement;
+  TJSHTMLInputElementDynArray = Array of TJSHTMLInputElement;
+  TJSNodeDynArray = Array of TJSNode;
+  TJSHTMLDivElement = TJSHTMLElement;
+  TJSHTMLSpanElement = TJSHTMLElement;
+  TFPRevFormat = JSValue;
+  TFPFormats = JSValue;
+  TFPTokenRegex = JSValue;
+
+  TFPLocaleKey = string;
+
+  TFPDateOption = jsValue;
+  TFPDateOptionArray = array of TFPDateOption;
+  TFPPositionFunction = reference to procedure(aSelf: TJSObject; customElement: TJSHTMLElement);
+
+  TFPErrorHandler = reference to procedure (e: TJSError);
+
+  TFPWeekdayNames = Class external name 'Object' (TJSObject)
+    shorthand : array[0..6] of string;
+    longhand : array[0..6] of string;
+  end;
+  TFPMonthNames = Class external name 'Object' (TJSObject)
+    shorthand : array[0..11] of string;
+    longhand : array[0..11] of string;
+  end;
+  TFPDaysInmonth = Array [0..11] of Integer;
+  TFPOrdinalFunction = reference to function (nth: integer) : string;
+  TFPAMPMArray = array[0..1] of string;
+
+  TFPLocale = Class external name 'Object' (TJSObject)
+    weekdays : TFPWeekDayNames;
+    months : TFPMonthNames;
+    daysInMonth : TFPDaysInMonth;
+    firstDayOfWeek: Integer;
+    ordinal: TFPOrdinalfunction;
+    rangeSeparator: string;
+    weekAbbreviation: string;
+    scrollTitle: string;
+    toggleTitle: string;
+    amPM: TFPAMPMArray;
+    yearAriaLabel: string;
+    monthAriaLabel: string;
+    hourAriaLabel: string;
+    minuteAriaLabel: string;
+    time_24hr: boolean;
+  end;
+
+  TFPDateFormatHandler = reference to function (date: TJSDate; format: string; locale: TFPLocale) : String;
+  TFPDateParserHandler = reference to function (date: string; format: string) : TJSDate;
+  TFPHook = reference to Procedure (dates : TJSDateDynArray; CurrentDateString : String; aSelf : TJSObject; Data : JSValue);
+  TFPHookDynArray = Array of TFPHook;
+  TFPDateToWeekHandler = reference to function (adate: TJSDate) : string;
+
+  TFlatPickrOptions = Class external name 'Object' (TJSObject)
+    allowInput: boolean;
+    allowInvalidPreload: boolean;
+    altFormat: string;
+    altInput: boolean;
+    altInputClass: string;
+    animate: boolean;
+    appendTo: TJSHTMLElement;
+    ariaDateFormat: string;
+    autoFillDefaultTime: boolean;
+    clickOpens: boolean;
+    closeOnSelect: boolean;
+    conjunction: string;
+    dateFormat: string;
+    defaultDate: TFPDateOption;
+    defaultDateArray : TFPDateOptionArray; external name 'defaultDate';
+    defaultHour: Integer;
+    defaultMinute: Integer;
+    defaultSeconds: Integer;
+    disable: JSValue;
+    disableMobile: boolean;
+    enable: JSValue;
+    enableSeconds: boolean;
+    enableTime: boolean;
+    errorHandler: TFPErrorHandler;
+    formatDate: TFPDateFormatHandler;
+    getWeek : TFPDateToWeekHandler;
+    hourIncrement: integer;
+    ignoredFocusElements: TJSHTMLElementDynArray;
+    inline_: boolean; external name 'inline';
+    locale: string;
+    maxDate: TFPDateOption;
+    maxTime: TFPDateOption;
+    minDate: TFPDateOption;
+    minTime: TFPDateOption;
+    minuteIncrement: integer;
+    mode: string;
+    monthSelectorType: string;
+    nextArrow: string;
+    noCalendar: boolean;
+    now: TFPDateOption;
+    onChange: TFPHook;
+    onChangeArray : TFPHookDynArray; external name 'onChange';
+    onClose: TFPHook;
+    onCloseArray : TFPHookDynArray; external name 'onClose';
+    onDayCreate: TFPHook;
+    onDayCreateArray : TFPHookDynArray; external name 'onDayCreate';
+    onDestroy: TFPHook;
+    onDestroyArray : TFPHookDynArray; external name 'onDestroy';
+    onKeyDown: TFPHook;
+    onKeyDownArray : TFPHookDynArray; external name 'onKeyDown';
+    onMonthChange: TFPHook;
+    onMonthChangeArray : TFPHookDynArray; external name 'onMonthChange';
+    onOpen: TFPHook;
+    onOpenArray : TFPHookDynArray; external name 'onOpen';
+    onParseConfig: TFPHook;
+    onParseConfigArray : TFPHookDynArray; external name 'onParseConfig';
+    onReady: TFPHook;
+    onReadyArray : TFPHookDynArray; external name 'onReady';
+    onValueUpdate: TFPHook;
+    onValueUpdateArray : TFPHookDynArray; external name 'onValueUpdate';
+    onYearChange: TFPHook;
+    onYearChangeArray : TFPHookDynArray; external name 'onYearChange';
+    onPreCalendarPosition: TFPHook;
+    onPreCalendarPositionArray : TFPHookDynArray; external name 'onPreCalendarPosition';
+    parseDate: TFPDateParserHandler;
+    plugins: TJSValueDynArray;
+    position: String;
+    positionFunction : TFPPositionFunction; external name 'position';
+    positionElement: TJSHTMLElement;
+    prevArrow: string;
+    shorthandCurrentMonth: boolean;
+    static_: boolean; external name 'static';
+    showMonths: Integer;
+    time_24hr: boolean;
+    weekNumbers: boolean;
+    wrap: boolean;
+  end;
+
+  TFlatPickr = Class external name 'Object' (TJSObject)
+    // Formatting
+
+    revFormat: TFPRevFormat;
+    formats: TFPFormats;
+    tokenRegex: TFPTokenRegex;
+
+    // elements
+    element: TJSHTMLElement;
+    input: TJSHTMLInputElement;
+    altInput: TJSHTMLInputElement;
+    _input: TJSHTMLInputElement;
+    mobileInput: TJSHTMLInputElement;
+    mobileFormatStr: string;
+
+    selectedDateElem: TJSHTMLElement;
+    todayDateElem: TJSHTMLElement;
+
+    _positionElement: TJSHTMLElement;
+    weekdayContainer: TJSHTMLDivElement;
+    calendarContainer: TJSHTMLDivElement;
+    innerContainer: TJSHTMLDivElement;
+    rContainer: TJSHTMLDivElement;
+    daysContainer: TJSHTMLDivElement;
+    days: TJSHTMLDivElement;
+
+    weekWrapper: TJSHTMLDivElement;
+    weekNumbers: TJSHTMLDivElement;
+
+    // month nav
+    monthNav: TJSHTMLDivElement;
+
+    monthsDropdownContainer: TJSHTMLSelectElement;
+
+    yearElements: TJSHTMLInputElementDynArray;
+    monthElements: TJSHTMLSpanElement;
+
+    // month nav getters
+    currentYearElement: TJSHTMLInputElement;
+    currentMonthElement: TJSHTMLSpanElement;
+
+    // month nav arrows
+    _hidePrevMonthArrow: boolean;
+    _hideNextMonthArrow: boolean;
+    prevMonthNav: TJSHTMLElement;
+    nextMonthNav: TJSHTMLElement;
+
+    timeContainer: TJSHTMLDivElement;
+    hourElement: TJSHTMLInputElement;
+    minuteElement: TJSHTMLInputElement;
+    secondElement: TJSHTMLInputElement;
+    amPM: TJSHTMLSpanElement;
+
+    pluginElements: TJSNodeDynArray;
+
+    minRangeDate: TJSDate;
+    maxRangeDate: TJSDate;
+    now: TJSDate;
+    latestSelectedDateObj: TJSDate;
+    _selectedDateObj : TJSDate;
+    selectedDates: TJSDateDynArray;
+    _initialDate: TJSDate;
+
+    // State
+    config: TJSObject;
+    loadedPlugins: TJSstringDynArray;
+    l10n: TFPLocale;
+
+    currentYear: integer;
+    currentMonth: integer;
+
+    isOpen: boolean;
+    isMobile: boolean;
+
+    minDateHasTime: boolean;
+    maxDateHasTime: boolean;
+
+    // Methods
+    procedure changeMonth (value: Integer; isOffset: boolean; fromKeyboard: boolean);
+    procedure changeMonth (value: Integer; isOffset: boolean);
+    procedure changeMonth (value: Integer);
+    procedure changeYear (year: integer);
+    procedure clear (emitChangeEvent: boolean; toInitial: boolean);
+    procedure clear (emitChangeEvent: boolean);
+    procedure clear ();
+    procedure close ();
+    procedure destroy ();
+    function isEnabled (date: TFPDateOption; timeless: boolean) : boolean;
+    function isEnabled (date: TFPDateOption) : boolean;
+    procedure jumpToDate (date: TFPDateOption; triggerChange: boolean);
+    procedure open (e: TJSEvent; positionElement: TJSHTMLElement);
+    procedure open (e: TJSEvent);
+    procedure redraw ();
+    procedure set_ (option: string; value: JSValue) ; external name 'set';
+    procedure setDate (date: TFPDateOption; triggerChange: boolean; format: string) ;
+    procedure setDate (date: TFPDateOption; triggerChange: boolean) ;
+    procedure setDate (date: TFPDateOption) ;
+    procedure setDate (date: TFPDateOptionArray; triggerChange: boolean; format: string) ;
+    procedure setDate (date: TFPDateOptionArray; triggerChange: boolean) ;
+    procedure setDate (date: TFPDateOptionArray);
+    procedure toggle;
+
+    function pad (num: string ) : string;
+    function pad (num: integer ) : string;
+    function parseDate (adate: TJSDate; givenFormat: string; timeless: boolean) : TJSDate;
+    function parseDate (adate: string; givenFormat: string; timeless: boolean) : TJSDate;
+    function parseDate (adate: integer; givenFormat: string; timeless: boolean) : TJSDate;
+    function parseDate (adate: TJSDate; givenFormat: string) : TJSDate;
+    function parseDate (adate: string; givenFormat: string) : TJSDate;
+    function parseDate (adate: integer; givenFormat: string) : TJSDate;
+    function formatDate (dateObj: TJSDate; frmt: string) : string;
+  end;
+  TFlatPickrArray = array of TFlatPickr;
+
+  { JQueryFlatPickrHelper }
+
+  JQueryFlatPickrHelper = class helper for TJQuery
+    Function flatpickr (aOptions : TFlatPickrOptions) : TFlatPickr; external name 'flatpickr';
+    Function flatpickr () : TFlatPickr; external name 'flatpickr';
+  end;
+
+  { JJSElementFlatPickrHelper }
+
+  JJSElementFlatPickrHelper = class helper for TJSElement
+    Function _flatpickr : TFlatPickr;
+  end;
+
+
+Function flatpickr(aElement : TJSHTMLElement) : TFlatPickr; external name 'flatpickr';
+Function flatpickr(aElement : TJSHTMLElement; aOptions : TFlatPickrOptions) : TFlatPickr; external name 'flatpickr';
+Function flatpickr(aElementID : String) : TFlatPickr; external name 'flatpickr';
+Function flatpickr(aElementID : String; aOptions : TFlatPickrOptions) : TFlatPickr; external name 'flatpickr';
+Function multiflatpickr(const aSelector : String) : TFlatPickrArray; external name 'flatpickr';
+Function multiflatpickr(const aSelector : String; aOptions : TFlatPickrOptions) : TFlatPickrArray; external name 'flatpickr';
+
+
+implementation
+
+
+
+{ JQueryFlatPickrHelper }
+
+{ JJSElementFlatPickrHelper }
+
+function JJSElementFlatPickrHelper._flatpickr: TFlatPickr;
+begin
+  Result:=TFlatPickr(Self.Properties['_flatpickr']);
+end;
+
+end.

+ 87 - 20
packages/rtl/classes.pas

@@ -868,6 +868,8 @@ type
     function GetDataString : String;
   public
     constructor Create(const aString: String); virtual; overload;
+    function ReadString(Count: Integer): string;
+    procedure WriteString(const AString: string);
     property DataString: String read GetDataString;
   end;
 
@@ -1435,6 +1437,10 @@ procedure ObjectBinaryToText(aInput, aOutput: TStream);
 procedure ObjectBinaryToText(aInput, aOutput: TStream; aEncoding: TObjectTextEncoding);
 procedure ObjectTextToBinary(aInput, aOutput: TStream);
 Function SetLoadHelperClass(aClass : TLoadHelperClass) : TLoadHelperClass;
+// Create buffer from string. aLen in bytes, not in characters
+Function StringToBuffer(aString : String; aLen : Integer) : TJSArrayBuffer;
+// Create buffer from string. aPos,aLen are in bytes, not in characters.
+Function BufferToString(aBuffer : TJSArrayBuffer; aPos,aLen : Integer) : String;
 
 Const
   // Some aliases
@@ -1471,6 +1477,31 @@ begin
     Raise EInOutError.Create('No support for loading URLS. Include Rtl.BrowserLoadHelper in your project uses clause');
 end;
 
+Function StringToBuffer(aString : String; aLen : Integer) : TJSArrayBuffer;
+
+var
+   I : Integer;
+
+begin
+  Result:=TJSArrayBuffer.new(aLen*2);// 2 bytes for each char
+  With TJSUint16Array.new(Result) do
+    for i:=0 to aLen-1 do
+      values[i] := TJSString(aString).charCodeAt(i);
+end;
+
+function BufferToString(aBuffer: TJSArrayBuffer; aPos, aLen: Integer): String;
+
+var
+  a : TJSUint16Array;
+
+begin
+  Result:=''; // Silence warning
+  a:=TJSUint16Array.New(aBuffer.slice(aPos,aLen));
+  if a<>nil then
+    Result:=String(TJSFunction(@TJSString.fromCharCode).apply(nil,TJSValueDynArray(JSValue(a))));
+end;
+
+
 type
   TIntConst = class
   Private
@@ -1499,28 +1530,47 @@ end;
 
 constructor TStringStream.Create(const aString: String);
 
-  Function StrToBuf(aLen : Integer) : TJSArrayBuffer;
-
-  var
-     I : Integer;
-
-  begin
-    Result:=TJSArrayBuffer.new(aLen*2);// 2 bytes for each char
-    With TJSUint16Array.new(Result) do
-      for i:=0 to aLen-1 do
-        values[i] := TJSString(aString).charCodeAt(i);
-  end;
-
 var
   Len : Integer;
 
 begin
   inherited Create;
   Len:=Length(aString);
-  SetPointer(StrToBuf(len),Len*2);
+  SetPointer(StringToBuffer(aString,Len),Len*2);
   FCapacity:=Len*2;
 end;
 
+function TStringStream.ReadString(Count: Integer): string;
+
+
+Var
+  B : TBytes;
+  Buf : TJSArrayBuffer;
+  BytesLeft : Integer;
+
+begin
+  // Top off
+  BytesLeft:=(Size-Position);
+  if BytesLeft<Count then
+    Count:=BytesLeft;
+  SetLength(B,Count);
+  ReadBuffer(B,0,Count);
+  Buf:=BytesToMemory(B);
+  Result:=BufferToString(Buf,0,Count);
+end;
+
+procedure TStringStream.WriteString(const AString: string);
+
+Var
+  Buf : TJSArrayBuffer;
+  B : TBytes;
+
+begin
+  Buf:=StringToBuffer(aString,Length(aString));
+  B:=MemoryToBytes(Buf);
+  WriteBuffer(B,Length(B));
+end;
+
 constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
   AIntToIdent: TIntToIdent);
 begin
@@ -3174,19 +3224,34 @@ end;
 
 function TStrings.GetNextLinebreak(const Value: String; out S: String; var P: Integer): Boolean;
 
-Var
-  PP : Integer;
+var
+  PPLF,PPCR,PP,PL: Integer;
 
 begin
   S:='';
   Result:=False;
   If ((Length(Value)-P)<0) then
-    exit;
-  PP:=TJSString(Value).IndexOf(LineBreak,P-1)+1;
-  if (PP<1) then
+    Exit;
+  PPLF:=TJSString(Value).IndexOf(#10,P-1)+1;
+  PPCR:=TJSString(Value).IndexOf(#13,P-1)+1;
+  PL:=1;
+  if (PPLF>0) and (PPCR>0) then
+    begin
+    if (PPLF-PPCR)=1 then 
+      PL:=2;
+    if PPLF<PPCR then
+      PP:=PPLF
+    else
+      PP:=PPCR;
+    end
+  else if (PPLF>0) and (PPCR<1) then
+    PP:=PPLF
+  else if (PPCR > 0) and (PPLF<1) then
+    PP:=PPCR
+  else 
     PP:=Length(Value)+1;
   S:=Copy(Value,P,PP-P);
-  P:=PP+length(LineBreak);
+  P:=PP+PL;
   Result:=True;
 end;
 
@@ -6340,9 +6405,11 @@ end;
 procedure TMemoryStream.LoadFromStream(Stream: TStream);
 
 begin
+  Position:=0;
   Stream.Position:=0;
   SetSize(Stream.Size);
-  If FSize>0 then Stream.ReadBuffer(MemoryToBytes(FMemory),FSize);
+  If (Size>0) then
+    CopyFrom(Stream,0);
 end;
 
 procedure TMemoryStream.SetSize(const NewSize: NativeInt);