Jump to content

lynkfs

Moderators
  • Content Count

    740
  • Joined

  • Last visited

  • Days Won

    146

Reputation Activity

  1. Like
    lynkfs got a reaction from Czar in file system   
    The original html5 spec had a file api which allowed to read and write files clientside (the File Directories and System Api). This was only fully implemented by Chrome at one point, but even then Chrome needed to be started with a switch (-allow-file-access-from-files).
    Today clientside storage is limited to cookies, local/session storage, indexedDB and the Cache API.
    While I understand the reasons for limiting file handling on the client, it is sometimes annoying. Fortunately some pretty creative solutions have emerged.
    One of them is Filer. This is a nodejs fs filesystem look-a-like which uses indexedDB for storage, and runs in the browser. Basically it allows for a complete filesystem clientside.  Not bad at all.
    To continue stacking : Filer is stacked on top of indexedDB. Stack nohost on top of Filer and you have a web fileserver (based on service workers) in the browser. Amazing.
    Will certainly try this out.
     
  2. Like
    lynkfs got a reaction from IElite in file system   
    The original html5 spec had a file api which allowed to read and write files clientside (the File Directories and System Api). This was only fully implemented by Chrome at one point, but even then Chrome needed to be started with a switch (-allow-file-access-from-files).
    Today clientside storage is limited to cookies, local/session storage, indexedDB and the Cache API.
    While I understand the reasons for limiting file handling on the client, it is sometimes annoying. Fortunately some pretty creative solutions have emerged.
    One of them is Filer. This is a nodejs fs filesystem look-a-like which uses indexedDB for storage, and runs in the browser. Basically it allows for a complete filesystem clientside.  Not bad at all.
    To continue stacking : Filer is stacked on top of indexedDB. Stack nohost on top of Filer and you have a web fileserver (based on service workers) in the browser. Amazing.
    Will certainly try this out.
     
  3. Like
    lynkfs got a reaction from IElite in Favicon   
    The standard generated index file in smart doesn't contain a link tag for a favicon (something like
    <link id="favicon" rel="icon" href="res/favicon.png" type="image/png" sizes="16x16"> However this can be added in code (or add it manually to the default.html file in the template directory, or add it to a Custom Template in the ide)
    In code :
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var link := w3_createHtmlElement('link');   link.id    := 'favicon';   link.href  := 'res/favicon.png';   link.rel   := 'icon';   link.&type := 'image/png';   link.sizes := '16x16';   browserapi.document.getElementsByTagName('head')[0].appendChild(link); end; If you want to change the icon later on, you can do that too
    procedure TForm1.W3Button1Click(Sender: TObject); begin   var favicon := browserapi.document.getElementById('favicon');   favicon.href := 'res/favicon2.png'; end;
  4. Like
    lynkfs got a reaction from jarto in Favicon   
    The standard generated index file in smart doesn't contain a link tag for a favicon (something like
    <link id="favicon" rel="icon" href="res/favicon.png" type="image/png" sizes="16x16"> However this can be added in code (or add it manually to the default.html file in the template directory, or add it to a Custom Template in the ide)
    In code :
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var link := w3_createHtmlElement('link');   link.id    := 'favicon';   link.href  := 'res/favicon.png';   link.rel   := 'icon';   link.&type := 'image/png';   link.sizes := '16x16';   browserapi.document.getElementsByTagName('head')[0].appendChild(link); end; If you want to change the icon later on, you can do that too
    procedure TForm1.W3Button1Click(Sender: TObject); begin   var favicon := browserapi.document.getElementById('favicon');   favicon.href := 'res/favicon2.png'; end;
  5. Like
    lynkfs reacted to IElite in TW3StringGrid is available   
    @tristan
    You will need to create your own / derive your own  column from TW3StringGridColumn located in the unit SmartCL.Controls.StringGrid.
    Take a look at the SmartCL.Controls.StringGrid unit and see how for example, the button column (TW3StringGridButtonColumn)  is created
    TW3StringGridButtonColumn = class(TW3StringGridColumn)   protected     function GetClasses: String; override;   public     constructor Create; override;     function GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String; override;     procedure SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer); override;   end; { TW3StringGridButtonColumn }
    constructor TW3StringGridButtonColumn.Create; begin   FBaseClass := 'TW3Button';   AlignText := taLeft;   VAlign := tvCenter;   BorderType := btLightBorderRight;   BackgroundType := bsNone; end; function TW3StringGridButtonColumn.GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String; begin   var ItemId:=Grid.Handle.id+'_row_'+IntToStr(GridLine.DataIndex)+'_btncol_'+IntToStr(ColumnIndex);   GridLine.ItemIds.Add(ItemId);   result:='<input id="'+ItemId+'" type="button" class="'+GetClasses+'" style="visibility: visible; display: inline-block; overflow: hidden; left: '+IntToStr(CurrentLeft)+'px; position: absolute; width: '+IntToStr(Width)+'px; height: 100%;border-radius: 0px;" value="'+TString.EncodeTags(Grid.Cells[GridLine.DataIndex,ColumnIndex])+'"</input>'; end; function TW3StringGridButtonColumn.GetClasses: String; begin   result:=inherited GetClasses+' TW3ButtonBackground'; end; procedure TW3StringGridButtonColumn.SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer); //  Note: This is used by the combo box too var cHandle: THandle; begin   try     cHandle := GridLine.FixedCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);     if not (cHandle) then cHandle := GridLine.ScrollableCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);     cHandle['oninput'] := @Sender.HandleDataChanged;   except   end; end;  
  6. Like
    lynkfs reacted to jarto in Development updates   
    New update is available in the development-channel:
    IDE:
    Anchors (and other sets) can be set in the Object Inspector Improvements to generated Form implementation code: Wait until created components are ready before setting properties and creating children Set Anchors last Prevent conflicting keyboard shortcuts from being saved Use better default project options (no manifests, do not embed Javascript) Add new units to units defaults and improve formatting RTL:
    Add xml-js to Libraries. New ECMA.Promise unit from api docs System.JSON: Support for adding/setting JSON arrays Add TJSONObject.Delete Set form size to 100% before calling InitializeObject Add missing units to SmartCL.Controls Setting control's angle did not work in Firefox Don't raise an exception while freeing a form which is not registered Themes: default styles were not applied for all elements in Android and iOS Fixes a bug where textarea's size is too big in TW3Memo Note, that while the anchors can be set in the Object Inspector, it does not result in visible changes in the Visual Designer.
  7. Like
    lynkfs got a reaction from IgorSavkic in 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

     
     
  8. Like
    lynkfs got a reaction from IgorSavkic in printing   
    Edited. And then there is IPP : Internet Printing Protocol
    This protocol allows direct access to networked printers, ask for their capabilities, prepare print jobs, manage print queues, execute print jobs and get results.
    Exactly what I was after.
    I read through the documentation on the website of "The Printer Working Group", which looks after the standardisation of this protocol. 
    (http://www.pwg.org/ipp/ippguide.html).
    To actually use this protocol, there are various IPP client libraries available (C, Java, Python). 
    Fortunately there is a node.js variant as well (https://github.com/williamkapke/ipp).
    Both these links give some examples on how to use IPP in real world situations
    However the code examples on both sites contain many errors. 
    Amazing.
    On the plus side, apparently some 98% of all networkable printers have an IPP driver installed by default, and should be adressable this way.
    To test this all out, I selected a printer on my network.
    The first thing to find out is the identification of the printer.
    IPP has its own protocol : ipp(s)://<printer uri> where the printer uri is the printers ip address followed by a path. 
    Example : ipp://192.168.1.233/ipp/print
    Behind the scenes all traffic is actually routed over http(s), and printer uri's can also be specified as http over port 631. 
    Example : http://192.168.1.233:631/ipp/print
    The ip address can usually be found in the OS printer settings somewhere and the path is mostly standardised to be just '/ipp/print'  
    Not too bad. 
    After installing the node.js ipp library (npm install ipp) the following node.js code queries the printers capabilities
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var msg = {   "operation-attributes-tag": {     "requesting-user-name": "John Doe",     "document-format": "image/pwg-raster",     "requested-attributes": ["printer-description", "job-template", "media-col-database"]   } }; printer.execute("Get-Printer-Attributes", msg, function(err, res) {         console.log(err);         console.log(res); }); This produces quite a list.
    To print a textfile to this printer, I got this code working
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var fs = require("fs"); fs.readFile("example.txt", function(err, content) {               if (err) throw err;   var msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "application/octet-stream"              },     data: content   };   printer.execute("Print-Job", msg, function(err, res) {         console.log(err);         console.log(res);   }); });  
    Edited :
    The javascript sources above can be produced by a regular smart project : create a new node project and replace unit1 with
    unit Unit1; interface uses nodeBasics; //https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23115 type   TNodeProgram = class(TObject)   public     constructor Create; virtual;     ipp, msg, printer : variant;     procedure   callback(err, res: variant);     procedure   Execute;   end; implementation constructor TNodeProgram.Create; begin   inherited Create;   ipp := RequireModule('ipp');   printer := ipp.Printer("http://192.168.1.233:631/ipp/print");   msg := new JObject;   asm   @msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "image/pwg-raster",       "requested-attributes": ["printer-description", "job-template", "media-col-database"]     }   };   end; end; procedure TNodeProgram.callback(err, res: variant); begin   console.log(err);   console.log(res); end; procedure TNodeProgram.Execute; begin   printer.execute("Get-Printer-Attributes", msg, @callback); end; end.  
    note : unfortunately we can't make up anonymous classes with hyphens in the classname, otherwise the msg variable could have been constructed as
    var msg = class   operation-attributes-tag = class     requesting-user-name = "John Doe",     document-format = "image/pwg-raster",     requested-attributes : array[0..2] of string =       ["printer-description", "job-template", "media-col-database"];   end; end;  
    Next step is to see if this can be made to work in the browser as well 
     
  9. Like
    lynkfs got a reaction from Czar in printing   
    Edited. And then there is IPP : Internet Printing Protocol
    This protocol allows direct access to networked printers, ask for their capabilities, prepare print jobs, manage print queues, execute print jobs and get results.
    Exactly what I was after.
    I read through the documentation on the website of "The Printer Working Group", which looks after the standardisation of this protocol. 
    (http://www.pwg.org/ipp/ippguide.html).
    To actually use this protocol, there are various IPP client libraries available (C, Java, Python). 
    Fortunately there is a node.js variant as well (https://github.com/williamkapke/ipp).
    Both these links give some examples on how to use IPP in real world situations
    However the code examples on both sites contain many errors. 
    Amazing.
    On the plus side, apparently some 98% of all networkable printers have an IPP driver installed by default, and should be adressable this way.
    To test this all out, I selected a printer on my network.
    The first thing to find out is the identification of the printer.
    IPP has its own protocol : ipp(s)://<printer uri> where the printer uri is the printers ip address followed by a path. 
    Example : ipp://192.168.1.233/ipp/print
    Behind the scenes all traffic is actually routed over http(s), and printer uri's can also be specified as http over port 631. 
    Example : http://192.168.1.233:631/ipp/print
    The ip address can usually be found in the OS printer settings somewhere and the path is mostly standardised to be just '/ipp/print'  
    Not too bad. 
    After installing the node.js ipp library (npm install ipp) the following node.js code queries the printers capabilities
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var msg = {   "operation-attributes-tag": {     "requesting-user-name": "John Doe",     "document-format": "image/pwg-raster",     "requested-attributes": ["printer-description", "job-template", "media-col-database"]   } }; printer.execute("Get-Printer-Attributes", msg, function(err, res) {         console.log(err);         console.log(res); }); This produces quite a list.
    To print a textfile to this printer, I got this code working
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var fs = require("fs"); fs.readFile("example.txt", function(err, content) {               if (err) throw err;   var msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "application/octet-stream"              },     data: content   };   printer.execute("Print-Job", msg, function(err, res) {         console.log(err);         console.log(res);   }); });  
    Edited :
    The javascript sources above can be produced by a regular smart project : create a new node project and replace unit1 with
    unit Unit1; interface uses nodeBasics; //https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23115 type   TNodeProgram = class(TObject)   public     constructor Create; virtual;     ipp, msg, printer : variant;     procedure   callback(err, res: variant);     procedure   Execute;   end; implementation constructor TNodeProgram.Create; begin   inherited Create;   ipp := RequireModule('ipp');   printer := ipp.Printer("http://192.168.1.233:631/ipp/print");   msg := new JObject;   asm   @msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "image/pwg-raster",       "requested-attributes": ["printer-description", "job-template", "media-col-database"]     }   };   end; end; procedure TNodeProgram.callback(err, res: variant); begin   console.log(err);   console.log(res); end; procedure TNodeProgram.Execute; begin   printer.execute("Get-Printer-Attributes", msg, @callback); end; end.  
    note : unfortunately we can't make up anonymous classes with hyphens in the classname, otherwise the msg variable could have been constructed as
    var msg = class   operation-attributes-tag = class     requesting-user-name = "John Doe",     document-format = "image/pwg-raster",     requested-attributes : array[0..2] of string =       ["printer-description", "job-template", "media-col-database"];   end; end;  
    Next step is to see if this can be made to work in the browser as well 
     
  10. Like
    lynkfs got a reaction from jarto in printing   
    Edited. And then there is IPP : Internet Printing Protocol
    This protocol allows direct access to networked printers, ask for their capabilities, prepare print jobs, manage print queues, execute print jobs and get results.
    Exactly what I was after.
    I read through the documentation on the website of "The Printer Working Group", which looks after the standardisation of this protocol. 
    (http://www.pwg.org/ipp/ippguide.html).
    To actually use this protocol, there are various IPP client libraries available (C, Java, Python). 
    Fortunately there is a node.js variant as well (https://github.com/williamkapke/ipp).
    Both these links give some examples on how to use IPP in real world situations
    However the code examples on both sites contain many errors. 
    Amazing.
    On the plus side, apparently some 98% of all networkable printers have an IPP driver installed by default, and should be adressable this way.
    To test this all out, I selected a printer on my network.
    The first thing to find out is the identification of the printer.
    IPP has its own protocol : ipp(s)://<printer uri> where the printer uri is the printers ip address followed by a path. 
    Example : ipp://192.168.1.233/ipp/print
    Behind the scenes all traffic is actually routed over http(s), and printer uri's can also be specified as http over port 631. 
    Example : http://192.168.1.233:631/ipp/print
    The ip address can usually be found in the OS printer settings somewhere and the path is mostly standardised to be just '/ipp/print'  
    Not too bad. 
    After installing the node.js ipp library (npm install ipp) the following node.js code queries the printers capabilities
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var msg = {   "operation-attributes-tag": {     "requesting-user-name": "John Doe",     "document-format": "image/pwg-raster",     "requested-attributes": ["printer-description", "job-template", "media-col-database"]   } }; printer.execute("Get-Printer-Attributes", msg, function(err, res) {         console.log(err);         console.log(res); }); This produces quite a list.
    To print a textfile to this printer, I got this code working
    var ipp = require("ipp"); var printer = ipp.Printer("http://192.168.1.233:631/ipp/print"); var fs = require("fs"); fs.readFile("example.txt", function(err, content) {               if (err) throw err;   var msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "application/octet-stream"              },     data: content   };   printer.execute("Print-Job", msg, function(err, res) {         console.log(err);         console.log(res);   }); });  
    Edited :
    The javascript sources above can be produced by a regular smart project : create a new node project and replace unit1 with
    unit Unit1; interface uses nodeBasics; //https://forums.smartmobilestudio.com/topic/4652-node-ground-zero/?tab=comments#comment-23115 type   TNodeProgram = class(TObject)   public     constructor Create; virtual;     ipp, msg, printer : variant;     procedure   callback(err, res: variant);     procedure   Execute;   end; implementation constructor TNodeProgram.Create; begin   inherited Create;   ipp := RequireModule('ipp');   printer := ipp.Printer("http://192.168.1.233:631/ipp/print");   msg := new JObject;   asm   @msg = {     "operation-attributes-tag": {       "requesting-user-name": "John Doe",       "document-format": "image/pwg-raster",       "requested-attributes": ["printer-description", "job-template", "media-col-database"]     }   };   end; end; procedure TNodeProgram.callback(err, res: variant); begin   console.log(err);   console.log(res); end; procedure TNodeProgram.Execute; begin   printer.execute("Get-Printer-Attributes", msg, @callback); end; end.  
    note : unfortunately we can't make up anonymous classes with hyphens in the classname, otherwise the msg variable could have been constructed as
    var msg = class   operation-attributes-tag = class     requesting-user-name = "John Doe",     document-format = "image/pwg-raster",     requested-attributes : array[0..2] of string =       ["printer-description", "job-template", "media-col-database"];   end; end;  
    Next step is to see if this can be made to work in the browser as well 
     
  11. Like
    lynkfs got a reaction from jarto in printing   
    Printers used to be dumb peripherals. Not so with the latest receipt printers (epson).
    They have actually an apache webserver built in, and the printer can act as the hub for displays, scanners and other (dumb) peripherals.

    amazing.
    Connecting them to Smart looks like not too difficult.
     
  12. Like
    lynkfs got a reaction from Czar in printing   
    Printers used to be dumb peripherals. Not so with the latest receipt printers (epson).
    They have actually an apache webserver built in, and the printer can act as the hub for displays, scanners and other (dumb) peripherals.

    amazing.
    Connecting them to Smart looks like not too difficult.
     
  13. Like
    lynkfs got a reaction from jorn in 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

     
     
  14. Sad
    lynkfs got a reaction from Czar in reserved project name   
    I accidentally gave a project a reserved name ('implementation').
    Not a good idea: compiles then crashes
  15. Like
    lynkfs got a reaction from jarto in 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

     
     
  16. Like
    lynkfs got a reaction from Czar in 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

     
     
  17. Like
    lynkfs got a reaction from Daniel Eiszele in 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

     
     
  18. Like
    lynkfs got a reaction from DavidRM in 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

     
     
  19. Like
    lynkfs got a reaction from DavidRM in 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
     
  20. Like
    lynkfs got a reaction from jarto in 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
     
  21. Like
    lynkfs got a reaction from Czar in 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)
     
     
     
     
  22. Like
    lynkfs got a reaction from IElite in 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)
     
     
     
     
  23. Like
    lynkfs got a reaction from jarto in 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)
     
     
     
     
  24. Like
    lynkfs got a reaction from jarto in 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;
     
     
  25. Like
    lynkfs got a reaction from IElite in 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;
     
     
×
×
  • Create New...