123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- program demowebsocket;
- {$mode objfpc}
- {$modeswitch externalclass}
- uses
- browserconsole, browserapp, JS, Classes, SysUtils, Web, strutils;
- type
- TServerConfig = Class External name 'Object' (TJSObject)
- url : string;
- end;
- Var
- ServerConfig : TServerConfig; external name 'serverConfig';
- Type
- { TMyApplication }
- TMsgKind = (mkIncoming,mkOutgoing,mkSystem);
- TMyApplication = class(TBrowserApplication)
- btnSend: TJSHTMLButtonElement;
- EdtSender : TJSHTMLInputElement;
- EdtMessage : TJSHTMLInputElement;
- EdtRecipient : TJSHTMLInputElement;
- divMessages : TJSHTMLDivElement;
- btnConnect : TJSHTMLButtonElement;
- WS : TJSWebSocket;
- procedure doRun; override;
- private
- function AppendIcon(aParent: TJSHTMLElement; aName: String): TJSHTMLElement;
- function CreateMessageEl(aKind : TMsgKind): TJSHTMLElement;
- procedure DisplayClose;
- procedure DisplayOpen;
- function DoClosed(Event: TEventListenerEvent): boolean;
- procedure doConnect;
- function DoIncomingMessage(Event: TEventListenerEvent): boolean;
- procedure DisplayMessage(Sender, Msg: String; Incoming: Boolean=True);
- function DoOpen(Event: TEventListenerEvent): boolean;
- function DoReconnect(aEvent: TJSMouseEvent): boolean;
- function DoSendClick(aEvent: TJSMouseEvent): boolean;
- function DoToggleConnectClick(aEvent: TJSMouseEvent): boolean;
- procedure SendMessage(const aRecipient, aMessage: String);
- end;
- procedure TMyApplication.doRun;
- begin
- edtRecipient:=TJSHTMLInputElement(GetHTMLElement('edtRecipient'));
- edtSender:=TJSHTMLInputElement(GetHTMLElement('edtSender'));
- edtMessage:=TJSHTMLInputElement(GetHTMLElement('edtMessage'));
- btnConnect:=TJSHTMLButtonElement(GetHTMLElement('btnConnect'));
- btnConnect.onclick:=@DoToggleConnectClick;
- btnSend:=TJSHTMLButtonElement(GetHTMLElement('btnSend'));
- btnSend.onclick:=@DoSendClick;
- divMessages:=TJSHTMLDivElement(GetHTMLElement('messages'));
- DoConnect;
- Terminate;
- end;
- procedure TMyApplication.doConnect;
- Var
- URL,aHost : string;
- begin
- URL:='';
- if Assigned(ServerConfig) and isString(serverConfig.URL) then
- URL:=serverConfig.URL;
- if URL='' then
- begin
- aHost:=window.location.host;
- aHost:=ExtractWord(1,aHost,[':']);
- URL:='ws://'+aHost+':8080/';
- end;
- try
- WS:=TJSWebsocket.New(url);
- WS.onmessage:=@DoIncomingMessage;
- WS.onclose:=@DoClosed;
- WS.onopen:=@DoOpen;
- except
- on TJSError do
- Window.Alert('Could not connect to websocket server at '+URL);
- end;
- end;
- function TMyApplication.DoOpen(Event: TEventListenerEvent): boolean;
- begin
- btnSend.disabled:=False;
- DisplayOpen;
- btnConnect.InnerText:='Disconnect';
- end;
- function TMyApplication.DoClosed(Event: TEventListenerEvent): boolean;
- begin
- btnSend.disabled:=true;
- btnConnect.InnerText:='Connect';
- DisplayClose;
- end;
- function TMyApplication.DoIncomingMessage(Event: TEventListenerEvent): boolean;
- Var
- Msg: TJSMessageEvent absolute Event;
- JS : TJSObject;
- begin
- if isString(Msg.Data) then
- begin
- JS:=TJSJSON.parseObject(String(Msg.Data));
- DisplayMessage(String(JS['from']),String(JS['msg']),True)
- end
- else
- DisplayMessage('','<<unknown data arrived>>',True);
- end;
- function TMyApplication.CreateMessageEl(aKind : TMsgKind): TJSHTMLElement;
- Var
- ImgDiv,ImgEl,msgEl : TJSHTMLElement;
- begin
- MsgEl:=TJSHTMLElement(Document.createElement('DIV'));
- if aKind=mkSystem then
- begin
- MsgEl.className:='text-center my-2';
- end
- else
- begin
- msgEl.className:='d-flex align-items-center'+Ifthen(aKind=mkIncoming,'',' text-right justify-content-end');
- ImgDiv:=TJSHTMLElement(Document.createElement('DIV'));
- ImgDiv.ClassName:='text-left pr-1';
- ImgEl:=TJSHTMLElement(Document.createElement('IMG'));
- ImgEl['Src']:=IfThen(aKind=mkIncoming,'guest','you')+'.png';
- ImgDiv.AppendChild(ImgEl);
- if aKind=mkIncoming then
- msgEl.AppendChild(ImgDiv);
- end;
- Result:=TJSHTMLElement(Document.createElement(IfThen(aKind=mkSystem,'span','div')));
- if aKind=mkSystem then
- Result.className:='between'
- else
- Result.className:='pr-2'+IfThen(aKind=mkIncoming,' pl-1','');
- msgEl.AppendChild(Result);
- if aKind=mkOutgoing then
- msgEl.AppendChild(ImgDiv);
- divMessages.appendChild(msgEl);
- msgEl.scrollIntoView;
- end;
- function TMyApplication.AppendIcon(aParent: TJSHTMLElement; aName: String
- ): TJSHTMLElement;
- begin
- Result:=TJSHTMLElement(Document.createElement('i'));
- Result.className:='fas fa-'+aName+' mr-3';
- aParent.AppendChild(Result);
- end;
- procedure TMyApplication.DisplayClose;
- Var
- iEl,pEl : TJSHTMLElement;
- begin
- Pel:=CreateMessageEl(mkSystem);
- iEl:=AppendIcon(Pel,'plug');
- iEl.onclick:=@DoReconnect;
- pEl.AppendChild(Document.createTextNode('Connection closed, click icon to reconnect'));
- end;
- procedure TMyApplication.DisplayOpen;
- Var
- pEl : TJSHTMLElement;
- begin
- Pel:=CreateMessageEl(mkSystem);
- AppendIcon(Pel,'link');
- pEl.AppendChild(Document.createTextNode('Connection open, you can start messaging'));
- end;
- procedure TMyApplication.DisplayMessage(Sender,Msg: String; Incoming: Boolean = True);
- Const
- kinds : Array[Boolean] of TMsgKind = (mkOutgoing,mkIncoming);
- Var
- pEl,pEl2 : TJSHTMLElement;
- begin
- pEl:=CreateMessageEl(Kinds[Incoming]);
- if (Sender<>'') then
- begin
- pEl2:=TJSHTMLElement(Document.createElement('span'));
- pEl2.className:='name';
- pEl2.innerText:=Sender;
- pEl.appendChild(pEl2);
- end;
- pEl2:=TJSHTMLElement(Document.createElement('p'));
- PEL2.className:='msg';
- PEL2.AppendChild(Document.createTextNode(Msg));
- pEl.AppendChild(pEL2);
- end;
- function TMyApplication.DoReconnect(aEvent: TJSMouseEvent): boolean;
- begin
- DoConnect;
- end;
- procedure TMyApplication.SendMessage(const aRecipient,aMessage: String);
- Var
- JS : TJSObject;
- begin
- JS:=New(['from',EdtSender.Value,'msg',aMessage,'to',aRecipient]);
- WS.send(TJSJSON.Stringify(JS));
- DisplayMessage('you',aMessage,False);
- end;
- function TMyApplication.DoSendClick(aEvent: TJSMouseEvent): boolean;
- begin
- SendMessage(EDTRecipient.Value, EdtMessage.Value);
- end;
- function TMyApplication.DoToggleConnectClick(aEvent: TJSMouseEvent): boolean;
- begin
- if btnConnect.InnerText='Connect' then
- doConnect
- else
- begin
- WS.close;
- WS:=nil;
- end;
- end;
- var
- Application : TMyApplication;
- begin
- Application:=TMyApplication.Create(nil);
- Application.Initialize;
- Application.Run;
- end.
|