Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


lynkfs last won the day on May 25

lynkfs had the most liked content!

About lynkfs

Profile Information

  • Gender
  • Location

Recent Profile Visitors

2,009 profile views
  1. lynkfs

    tree walking

    Modern browsers have an enormous number of built-in functions, sometimes very handy These ones, having to do with tree handling, came up the other day : domParsing, nodeIteration and treeWalking The built in domParser function takes a tree in html/dom or xml format : <catalog> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer''s Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> </catalog> which can be used as in var oDOM: variant := new JObject; asm var oParser = new DOMParser(); @oDOM = oParser.parseFromString(@theaboveXMLstring, "application/xml"); end; writeln(oDOM.documentElement.nodeName); // root (catalog) writeln(oDOM.children[0].children[0].attributes[0].name); // id writeln(oDOM.children[0].children[0].attributes[0].value); // bk101 writeln(oDOM.children.item(0).innerHTML); To traverse these types of trees, there are also the following functions available : nodeIterator and treeWalker These functions are largely similar. The nodeIterator : var nodeIterator : variant := new JObject; nodeIterator := oDOM.createNodeIterator( oDOM.documentElement,-1); // NodeFilter.SHOW_ELEMENT : -1 or 0xFFFFFFFF var currentNode := nodeIterator.nextNode(); while currentNode <> null do begin // null = eof // get rid of whitespace text nodes if currentNode.nodeName <> '#text' then begin writeln(currentNode.nodeName); writeln(currentNode.innerHTML); end; currentNode := nodeIterator.nextNode(); end;
  2. lynkfs

    css grid

    2) using css grid to make a responsive 'form' The below component does some simple layouting of controls and also reacts to screen-sizing, both using the css grid : procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var ResponsiveForm : TResponsiveForm := TResponsiveForm.Create(self); ResponsiveForm.SetBounds(40,40,500,220); ResponsiveForm.AutoHeight := true; ResponsiveForm.Add('Name',TW3EditBox); ResponsiveForm.Add('Email',TW3EditBox); ResponsiveForm.Add('Township',TW3EditBox); ResponsiveForm.Add('Comments',TW3Memo); ResponsiveForm.Add('Submit',TW3Button,2); end; Demo here It is not really 100% responsive, as the labels should shift above the controls when screen size becomes small. It doesn't however look too bad and the tediousness of aligning labels and controls is taken care of by the css grid. (Adapted from this article). It's probably as easy though to use anchors creating the same result
  3. lynkfs


    A web application ends up being encoded in html, js and css. php is a language which can be used to create these components, but more importantly can also be used within all 3 of these types of files. That gives some interesting possibilities. To make that happen, php needs to be activated serverside. Many server hosting environments come with php pre-installed. Activating php so that it can be used at the time of serving regular .html, .js or .css files by the browser depends on the type of server. Regular unix based servers make use of a .htaccess file which needs a line like AddHandler application/x-httpd-php5 .html .htm Windows servers have another mechanism 1 - Using php within Smart Php can be invoked like this, where the php statements are inclosed in a <?php block. asm var i = 0; i = <?php echo 35; ?>; alert(i); end; A practical use would be to include server side scripts normally accessed through a POST request (which eliminates a server round trip as well). The below code reads a MySqL database at form init procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var response : variant := new JObject; asm @response = <?php $link = mysql_pconnect("...domain...", "...user...", "...password...") or die("Could not connect"); mysql_select_db("...database...") or die("Could not select database"); $sql_statement = 'Select * from FishFacts'; $arr = array(); $rs = mysql_query($sql_statement); while($obj = mysql_fetch_object($rs)) { $arr[] = $obj; } echo '{"rows":'.json_encode($arr).'}'; mysql_close($link); ?>; end; writeln(response.rows[0].Common_Name); //Clown Triggerfish 2 - Using php within Html files A (possibly) usefull example scenario would be to separate web-pages into a header.html, a regular Smart index.html and a footer file. php has an include mechanism, which can be used like so <body> <?php include "header.html" ?> <script type="text/javascript"> /* This prevents the window being moved by touches, to give the impression of a native app */ document.ontouchmove = function(e) { e.preventDefault(); } </script> <script type="text/javascript" src="main.js.php"></script> </body> 3 - Using php within css files Similarly stylesheets can be scripted, something like this snippet where, within the stylesheet, the current date is checked which sets an image url <?php $month = date('m'); $day = date('d'); if($month=='12' && $day=='25') { $logoSrc = 'images/holidayLogo.png'; } else { $logoSrc = 'images/logo.png'; } ?> h1 { background: url(<?=$logoSrc?>) no-repeat; } Demo (of 1 and 2)
  4. lynkfs

    window component

    found the problem : the js events give a window based coordinate (e.clientX), while the Smart events give a component based coordinate (x as in left relative to component). Solution : just ad water (just ad component.left) if Ctrl.Cursor=crMove then begin x := x + left; y := y + top; or something like that
  5. lynkfs

    window component

    mmm your amended code (when applied to this or any other visual component) makes for very jittery dragging substituting code with this (below) gives a very smooth movement header.OnAllMovement := procedure(Sender: TObject; dx,dy: Integer) begin left := left + dx; top := top + dy; end; but that wasn't the point. Any idea what causes the jitteryness ? Edit1 : the x,y values in OnMouseMove don't make much sense
  6. lynkfs

    window component

    demo works ok here The javascriptisch events used are //Move window Header.handle.onmousedown := procedure(e: variant) begin Header.handle.style.cursor := 'move'; var saveX := e.clientX; var saveY := e.clientY; Header.handle.onmousemove := procedure(e: variant) begin self.left := self.Left - (saveX - e.clientX); self.top := self.top - (saveY - e.clientY); PrevSize := TRect.CreateSized(left, top, width, height); saveX := e.clientX; saveY := e.clientY; end; end; // Header.handle.onmouseup := procedure(e: variant) begin Header.handle.onmousemove := null; //nullify mousemove Header.handle.style.cursor := 'default'; end; // Header.handle.onmouseleave := procedure(e: variant) begin self.Parent.handle.onmousemove := header.handle.onmousemove; self.Parent.handle.onmouseup := procedure(e: variant) begin self.parent.Handle.onmousemove := null; end; end; will be interesting to compare using eventmanager. I agree that will probably be a better solution
  7. lynkfs

    window component

    Thanks. Never had a good look at the event manager. Better do that (problem fixed by the way)
  8. lynkfs

    window component

    no drag racing ... fixable (when time permits)
  9. lynkfs

    window component

    Just in case anyone has a need for a window component. (multiple windows, movable, resizable, bringtofront, minimise, close, maximise) project
  10. lynkfs

    css grid

    The CSS Grid is pretty fast. However the current major browsers have a hard-coded limit of 1000 rows (Chromium) or 10,000 rows (Firefox). See reference issue here Edited project here (better stylesheet handling)
  11. lynkfs

    css grid

    Started to do some experiments with CSS Grid Basically CSS Grid is a grid component built into all modern browsers, including mobile. The good thing about it is it can be used as a simple grid, as a layout mechanism for forms or other components and can be used to be responsive to screen sizes. 1) A simple grid. Since this is based on css, it can only be teased into life by manipulating the stylesheet. Either by just adding css to it manually or doing it in code : //add some styles in code var s1 := #' .TGrid { display: grid; grid-template-columns: repeat(3, auto); grid-gap: 0.8em; }'; document.styleSheets[document.styleSheets.length-1].insertRule(s1, 0); // s1 := #' .afirst { grid-column: 1; }'; document.styleSheets[document.styleSheets.length-1].insertRule(s1, 0); This snippet adds a grid class to the stylesheet and a class for the first column in this grid Fill up the grid, in plain html here, by adding cells as children : var s := '<div class="TGrid" id="mygrid">'; for var i := 0 to 100 do begin s := s + '<div class="afirst">row ' + inttostr(i+1) + '</div>''; end; s := s + '</div>'; This can be made into a regular component : var MyCSSGrid : TCSSGrid := TCSSGrid.Create(self); MyCSSGrid.SetBounds(50,50,500,200); MyCSSGrid.NrofColumns := 4; For var i := 1 to 1000-1 do begin MyCSSGrid.AddCell('row ' + inttostr(i), 1); //column 1 For var j := 2 to 4 do begin MyCSSGrid.AddCell('cell[' + inttostr(i) + ',' + inttostr(j) + ']', j); //column 2-4 end; end; MyCSSGrid.Show; A demo of such a component with 4 columns and 1000 rows
  12. lynkfs


    as @IgorSavkic pointed out, there are many options and use cases for this api. I think this is the most common one. The funny thing is that even doing only step 1 (displaying the widget with the selection of pictures of bridges, buses etc) and not even doing step 2 (the back-end check) gives some kind of spammer protection. I suspect quite a few websites do it that way
  13. lynkfs


    Its actually simpler than I thought - the Google documentation is esoteric at best the reCaptcha widget produces some sort of response when the user clicks the checkbox (g-rechapta-response). This response is POST-sent (either by form or by xmlhttprequest) to a back-end server side script. this script queries the "https://www.google.com/recaptcha/api/siteverify" url, which gives a response either ok or not ok This server-side script can be f.i. node.js or php based In php something like this (recaptchajax.php) <?php $secret="6Lf8I....secret key.....BrulLk"; $response=$_POST["captcha"]; $verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}"); $captcha_success=json_decode($verify); if ($captcha_success->success==false) { //This user was not verified by recaptcha. echo 'false'; } else if ($captcha_success->success==true) { //This user is verified by recaptcha echo 'true'; } ?> and the invocation, with a proper POST xmlhttprequest : unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, System.IOUtils, System.Device.Storage, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Device.Storage, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Panel, SmartCL.Net.Http, ECMA.Json, SmartCL.Controls.Button; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; procedure RetrieveCaptcha(Sender: TW3HttpRequest); Button1 : TW3Button; end; var grecaptcha external 'grecaptcha': Variant; implementation { TForm1 } procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components Var Captcha : TW3Panel := TW3Panel.Create(self); Captcha.SetBounds(50, 100, 304+4, 78+4); Button1 := TW3Button.Create(self); Button1.SetBounds(50, 200, 100, 30); Button1.Caption := 'submit'; var Script := browserapi.document.createElement('script'); Script.src := 'https://www.google.com/recaptcha/api.js'; browserapi.document.head.appendChild(Script); Script.onload := procedure begin Captcha.innerHTML := '<div class="g-recaptcha" data-sitekey="6Lf8I6....site key.....WY5hq"></div>'; Button1.onclick := procedure(sender:TObject) begin var FHttp := TW3HttpRequest.Create; FHttp.OnDataReady := RetrieveCaptcha; FHttp.open("POST","https://www.lynkfs.com/Experiments/reCaptcha/www/lib/recaptchajax.php"); FHttp.RequestHeaders.Add("Content-type","application/x-www-form-urlencoded"); var mycaptcha := "captcha=" +grecaptcha.getResponse(); FHttp.send(mycaptcha); end; end; end; procedure TForm1.RetrieveCaptcha(Sender: TW3HttpRequest); begin writeln(JSON.parse(Sender.ResponseText)); //console : either 'true' or 'false' If JSON.parse(Sender.ResponseText) = true then Button1.Caption := 'OK'; If JSON.parse(Sender.ResponseText) = false then Button1.Caption := 'Spam'; end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end. Demo url as before
  14. lynkfs


    this is a finnicky api, which needs multiple steps to figure this out. Step1 : display the captcha widget It is not just the case of adding the 'https://www.google.com/recaptcha/api.js' file to the index/template file, as it clashes with a standard smart project. Don't know why, something to do with timing So workaround #1 : read the api file in code (maximum control) and set up a TPanel as the widget control procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components Var Captcha : TW3Panel := TW3Panel.Create(self); Captcha.SetBounds(50, 100, 304+4, 78+4); var Script := browserapi.document.createElement('script'); Script.src := 'https://www.google.com/recaptcha/api.js'; browserapi.document.head.appendChild(Script); Script.onload := procedure begin writeln('loaded'); Captcha.innerHTML := #' <form action="?" method="POST"> <div class="g-recaptcha" data-sitekey="6Lf8I...site key ...WY5hq" data-callback="mycallback"></div> <br/> <input type="submit" value="Submit"> </form> '; end; end; The captcha widget is 304 * 78, so we'll embed it in a standard T(W3)Panel. The innerHtml solution is not very elegant (but works). I'll see if this can be changed to a normal post xmlhttprequest later. Demo so far
  15. lynkfs

    How do I use Secure Websockets (WSS)?

    You may be able to have SSL on IP rather than domain name, as long as it is a public IP address. Stackoverflow again