Jump to content

lynkfs

Moderators
  • Content Count

    612
  • Joined

  • Last visited

  • Days Won

    83

lynkfs last won the day on June 15

lynkfs had the most liked content!

About lynkfs

  • Rank

Profile Information

  • Gender
    Male
  • Location
    Australia

Recent Profile Visitors

2,606 profile views
  1. lynkfs

    web design system usa

    Reading up a bit on web design systems Basically web design systems are a collection of rules, components, tools etc helping developers to create a consistent look and feel for the websites or apps they are developing. This link links to the design system of the us gov. Whether or not one likes this system, it is certainly comprehensive. As an example I quite like f.i this site which conforms to these rules.
  2. lynkfs

    menu component

    Probably not the most inspiring topic, but just sharing a menu component I needed for some project. There are quite a few css based menu components around, but I wanted to have a pure smart one. This one has an unlimited number of submenus and is instantiated as a hamburger menu on a toolbar Hamburger := TCHMenu.Create(self); //nodes : id,parent,description,procedure Hamburger.Add('root','','Hamburger menu'); //root Hamburger.Add( 'projects','root','Projects'); Hamburger.Add( 'project0','projects','New project'); Hamburger.Add( 'project1','projects','Open project'); Hamburger.Add( 'project2','projects','Delete project'); Hamburger.Add( 'designers','root','Designer'); Hamburger.Add( 'designer0','designers','Domain info',clickproc); //<== execproc Hamburger.Add( 'designer1','designers','Data development'); ... Hamburger.Add( 'designer5','designers','Goal Metrics'); //some test cases below Hamburger.Add( 'test','project0','test3'); // test level 3 Hamburger.Add( 'designer5','designers','Goal Metrics'); //test on double entries Hamburger.Add( 'test0','root','test',procedure begin writeln('clickproc'); end); //test on no children Hamburger.Add( 'designer6','designers','extra test'); //test on out of order demo and project files on the .../Menu subdir
  3. lynkfs

    Promises revisited

    Full kudo's to @warleyalex, he was the first one to come up with a working promise unit (see link in post) My posts are usually a personal discovery journey, so I started with the api docs and went from there. There are a couple of differences I've noticed, probably because of different source material or for other reasons. I've asked him.
  4. lynkfs

    Promises revisited

    Promises are a javascript construct enabling async processes to be written in a synchronous manner (sort of). The status quo at this stage : - Promises are part of javascript since Ecmascript 6 - Promises are enabled in all major browsers - Promises work in node.js too (require('promise')) - Promises are not used in the rtl, or described in Smart documentation - There have been some posts on the forum re implementing promises (the best one : ) - The ecma.promise unit in the rtl is based on an older, incompatible, version of the current spec The subject of this post is to try and make the ecma.promise unit usable again and provide some examples A promise is a way to combine an asynchronous action, its possible outcomes and the actions associated with these outcomes in a single construct. Reading through the API documents (see bottom of this post), the basic syntax to create a promise is : var promise : variant := new JPromise(resolver) where resolver is a function with as arguments a resolve and reject function, which resolves the promise or rejects it on error. The return value of the resolver itself is ignored. (so we might as well type it as a procedure rather than a function) The above is covered by type TPromiseCallback = function(Value: Variant): Variant; JPromise = class external 'Promise' public constructor Create(resolver: procedure(resolve,reject: TPromiseCallback)); end; The most important functions of the Promise object are the "then" and the "catch" functions. Basically these are used to process actions when the promise is either resolved or rejected. So we need to add at least this to the type info type JPromise = class external 'Promise' public ... function &then(onFulFilled: TPromiseCallback): Variant; function catch(onRejected: TPromiseCallback): Variant; end; Some examples The most quoted example is an external httprequest for some data (1), wait for the request to come back and see if it was succesfull or not (2) and perform the necessary actions (3) or (4). function example1(url:string):variant; begin var q : variant := new JPromise(procedure(resolve,reject: TPromiseCallback) begin var FHttp := TW3HttpRequest.Create; FHttp.GET(url); //1 do something asynchronous FHttp.ondataready := lambda resolve(FHttp.responseText); end; //2 resolve (and pass 'responseText' on to the then function) FHttp.onerror := lambda reject(FHttp.statusText); end; reject (and pass 'statusText' on to the catch function) end) .then(function(x:variant):variant begin writeln(x); end) //3 do something when succesful .catch(function(x:variant):variant begin writeln(x); end); //4 do something when unsuccesfull result := q; end; Example1('res/textfile.txt'); Really not that different from a normal ajax call : procedure example2(url:string); begin procedure OnDataReady(x: variant); begin writeln(x) end; //3 procedure OnError(x: variant); begin writeln(x) end; //4 var FHttp := TW3HttpRequest.Create; FHttp.GET(url); //1 FHttp.ondataready := lambda OnDataReady(FHttp.responseText) end; //2 FHttp.onerror := lambda OnError(FHttp.statusText) end; end; Example2('res/textfile.txt'); The differences being here that promises allow all code in the one construct. The other main advantage is that a single promise can be accessed multiple times and at multiple code locations: Suppose we have a promise which reads an accountname from a db, and the accountname is say displayed on a window title and a report. In both places this can be simply referred to as AccountName = AccountPromise.then(*function*) without having to check if data is actually available. The promise api also provides a shortcut to create a promise in the resolved or rejected state immediately without going through its constructor : Promise.resolve('resolved'); Promise.reject('rejected'); For this we need access to the global Promise object, and have to add the next line : type ... var Promise external 'Promise': variant; A possible use is if we have a process consisting of multiple steps, and we want to use the chaining mechanism of the "then" functions of the promise object to tie these steps together : Promise.resolve('life') //life .then(function(x:variant):variant begin result := x + "'s"; //life's end) .then(function(x:variant):variant begin writeln(x + ' good'); //life's good end); The two remaining api functions are promise = Promise.all(array or set) promise = Promise.race(array or set) These functions are initially typed as JPromise = class external 'Promise' public ... function all(Iterable: variant): Variant; function race(Iterable: variant): Variant; end; Both can be used when running asynchronous tasks in parallel. Suppose there are say 3 tasks running concurrently which execute a query to Google, Bing and Yahoo The "all" function returns a promise when all 3 promises have been resolved, and the "race" function as soon as one of the promises has been resolved Promise.all(requests:array[0..2] of string) .then(function(outcome:variant):variant begin writeln('All ' + requests.length + ' query outcomes received'); end); .catch(function(error:variant):variant begin writeln('Error occurred ' + error); end); Adding it all up, the typed info as per below works perfectly fine for the type of examples listed above type TPromiseCallback = function(Value: Variant): Variant; JPromise = class external 'Promise' public constructor Create(resolver: procedure(resolve,reject: TPromiseCallback)); function &then(onFulFilled: TPromiseCallback): Variant; function catch(onRejected: TPromiseCallback): Variant; function all(Iterable: variant): Variant; function race(Iterable: variant): Variant; end; var Promise external 'Promise': variant; To complicate matters a bit, and usually unnecessarily so : The function header of the "then" function above is the most used format. "Then" is however actually a function with 2 arguments, both of which are optional. Which means that the possible formats of this function are function &then: Variant; overload; function &then(onFulFilled: TPromiseCallback): Variant; overload; function &then(onFulfilled, onRejected: TPromiseCallback): Variant; overload; Mozilla : "If one or both arguments are omitted or are provided non-functions, then they will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, a new Promise is created with no additional handlers, simply adopting the final state of the original Promise on which then was called". My thoughts exactly () By the way this also means that catch(onRejected) is the same as &then(undefined, onRejected); Another (usually unnessary) detail is that the static resolve function (Promise.resolve) comes in different flavours as well : Promise.resolve(promise); Returns promise (only if promise.constructor == Promise) Promise.resolve(thenable); Make a new promise from the thenable. A thenable is promise-like in as far as it has a `then() method. Promise.resolve(obj); Make a promise that fulfills to obj. in this situation. This however is handled by the reference to the global Promise object, and doesn't require any changes to the typed info Finally, Mozilla also lists a "finally" function, which is not described in other api documents API documentation http://definitelytyped.org/docs/es6-promises--es6-promises/classes/promise.html https://tc39.github.io/ecma262/#sec-promise-constructor https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://promisesaplus.com/ https://developers.google.com/web/fundamentals/primers/promises#promise-api-reference https://github.com/tildeio/rsvp.js Note: In principal there are 3 ways to extract and type the functions, procedures and variables from any API : - find an API declaration file and convert this programmatically into object Pascal syntax - find a reference to a global object representing the API methods (if available) - read through the API specs The first option would involve finding a relevant API declaration file (f.i. this one) and convert this into pascal syntax. The results of using ts2pas (see posts) have been not very 'promising' The second option, when using promises in a browser environment, is to simply forget about typing, but have a reference to the global window object, and reference the promise object from there : var window external 'window': variant; ... var promise := window.Promise.resolve('something'); promise.then(function(x:variant):variant begin writeln(x); end); The post above has used the last option (read the API docs) Surprisingly, it is actually somewhat difficult to find the latest/most comprehensive/most agreed upon spec. The promise api has gone through various iterations, starting from an idea to external libraries (Q, when, rsvp.js) and finally becoming part of the javascript language in Ecmascript 6. Even then there have been some changes . Please let me know if you know of relevant use cases for this API requiring other changes to the ECMA.Promise unit
  5. lynkfs

    TIniFile Question

    (edited ) I would say either one of the following : if you execute this from file, you will get an error message in the dev console something like this (on chrome) "Access to XMLHttpRequest at 'file:///C:/.../res/apps.ini' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https" and/or your get call should be replaced by something like var FHttp := TW3HttpRequest.Create; FHttp.OnDataReady := lambda writeln(FHttp.responsetext); end; FHttp.open('GET','res/textfile.txt'); FHttp.send(); Edited : your get call is quite ok, it wraps to open/get-writeheader/send anyway if necessary, you might want to add a cors header Access-Control-Allow-Origin: *
  6. lynkfs

    fetching files

    @warleyalex posted another variant a while ago using his (working) promises unit question : is the ECMA.Promise unit fixed ?
  7. lynkfs

    fetching files

    There are afaik 3 ways to read external files directly from the client : using ajax / xmlhttprequest using the filereader using the fetch api 1: get xmlhttprequest var FHttp := TW3HttpRequest.Create; FHttp.OnDataReady := lambda writeln(FHttp.responsetext); end; FHttp.open('GET','res/textfile.txt'); FHttp.send(); 2: file input W3EditBox1.InputType := itFile; W3EditBox1.Handle.ReadyExecute( procedure () begin W3EditBox1.OnChanged := procedure(sender:TObject) begin var reader: variant; asm @reader = new FileReader(); end; reader.onload := lambda writeln(reader.result); end; reader.readAsText(W3EditBox1.handle.files[0]); end; end); 3: fetch api var window external 'window': variant; window.fetch('res/textfile.txt') .then(function(response:variant):variant begin result := response.text(); end) .then(procedure(myText:variant) begin writeln(myText); end); these fetch calls return a promise and the promise returns a response The fetch api is a mechanism which can replace the usual ajax calls. This api is primarily designed to act on network events. (see this post), but works for simple file fetching as well 4: Variations of the above, see f.i. this one using webworkers var FileReader : variant := new JObject; asm @FileReader = new Worker('filereader.js'); end; FileReader.onmessage := procedure(e: variant) begin writeln(e.data); end; FileReader.postMessage('res/textfile.txt'); //read file through webworker (filereader.js) demo / project (demo output is to console : ctrl+shift+i)
  8. 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;
  9. 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
  10. lynkfs

    php

    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)
  11. 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
  12. 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
  13. 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
  14. lynkfs

    window component

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

    window component

    no drag racing ... fixable (when time permits)
×