Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation since 08/04/2014 in all areas

  1. 6 points
    jarto

    Smart Mobile Studio 3.0 is released!

    One year of hard work, lots of changes, new features and bug fixes. But here it is! Release announcement: https://smartmobilestudio.com/2018/07/20/smart-mobile-studio-3-0-released/ Most of you have already been using beta-versions, that are really, really close to this release. The last bit was to fix the cors-problem in the Images and to add the Smart Desktop source code to the Featured Demos. We've also set up a live demo of the Desktop to showcase what Smart Mobile Studio and JavaScript can do: desktop.smartmobilestudio.com Big thanks to everybody here, who have helped by testing, suggesting improvements and reporting bugs.
  2. 5 points
    jarto

    Smart Mobile Studio 3.0.1 is released!

    Smart Mobile Studio 3.0.1 is released This is the first release since 3.0. Biggest new feature is TW3LeafletMap, which lets you use OpenStreetMap. As it does not need API keys (like TW3GoogleMaps), it’s really fast and easy to use: – Create a project – Add a TW3LeafletMap -control on the form – Set AutoCreateMap to true on the map control Changes since 3.0 8.11.2018 RTL: – EventManager: – Add procedure AllowDefaultAction, that can be called from OnClick when the default action should happen. For example: To let the virtual keyboard to pop up from OnTouch. – Bug fixes: – Native scrolling was prevented if scrolling was done from an unknown element. – Prevent an extra OnClick from being fired on mobile devices. – TW3ListView: Bug fix to resizing of items. – Bug fixes to GeoLocation. Also update the Geolocation demo. – Deprecate PhoneGapAPI’s JGeolocation functions. SmartCL.GeoLocation.pas should be used instead. – Fix slider so that OnMouseDown, OnMouseUp and OnMOuseMove can be used. – TW3TabControl Tab’s OnShow was sent twice for the first tab – SmartCL.RegEx moved to System.RegEx. Also fixed TW3RegEx.Exec to return a proper empty array instead of nil. – Bug fix to Chart: TSeriesData.Refresh now also updates the X axis – TW3Grid: – Added TW3ImageColumn – Add Alignment-property to TW3ColumnHeader – Added a new OnCellControlCreated-event, which fires when a button, toggle, progress bar or image is created. Makes it possible to change properties of the control easily. – Added support for OpenStreetMap using the Leaflet library: – New control: TW3LeafletMap – New featured demo: LeafletMap IDE/Compiler: – Fixed search path compilation issues – Relative and absolute paths are working now – Compiler is updated when search path is modified in options – $I will look for include file in the project folder first – $R supports absolute paths, wildcards, folder name extension and ($Libraries) macro – Fix exceptions in Search – Upgrade to UPX 3.95 23.7.2018 – SmartCL.Effects: Properly handle padding and margins while doing effects. 22.7.2018 – Fix to css-files for selected text in TW3Edit and TW3Memo Release notes and installers: https://smartmobilestudio.com/2018/11/08/smart-mobile-studio-3-0-1-released/ Note that you can also use SmartUpdate to keep your portable installation up to date. Instructions on using that are in the link above.
  3. 5 points
    lynkfs

    Font Demo

    in project options add a webfont (see https://jonlennartaasenden.wordpress.com/2017/10/04/webfonts-in-smart-mobile-studio/) W3Memo1.Font.Name := 'Tangerine'; W3Memo1.Font.Style := [fsItalic]; W3Memo1.Font.Size := 48; W3Memo1.Font.Weight := 'bold'; In this case I added Font 'Tangerine' (see also https://developers.google.com/fonts/docs/getting_started)
  4. 5 points
    Daniel Eiszele

    Google Maps API

    It took quite a bit of trial and error due to some case sensitivity errors but I finally have a working google map which utilises Google's javascript API. I know this has been touched on in other topics on the forum but none of them had a full blown working example; so I include this here for those who come after! Just create a new Visual Components project and replace everything in the form1 unit with the below code. Note that you will also need to obtain an API Key from Google (https://developers.google.com/maps/documentation/javascript/) and replace the dummy one in the code below. Note that I have only included a few partial classes and objects as far as the maps API is concerned but hopefully this is enough to get newcomers started. As an aside, the reference section on the above linked URL is very helpful in getting things up and running. unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Elements, W3C.HTML5, W3C.DOM, SmartCL.Require, System.JSON; type JMap = partial Class external; JLatLngLiteral = record Property lat : Double; Property lng : Double; end; JMapOptions = record property Zoom : Integer; property Center : JLatLngLiteral; end; JMarkerOptions = record property position : JLatLngLiteral; property map : JMap; property title : String; end; JMarker = partial class external 'google.maps.Marker' Public Constructor Create(options:JMarkerOptions); external 'Marker'; end; JMap = partial class external 'google.maps.Map' public Constructor Create(mapDiv:JElement; options : JMapOptions); external 'Map'; end; TForm1 = class(TW3Form) private {$I 'Form1:intf'} FMap : JMap; FMapDIV : TW3DIVHtmlElement; protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; procedure InitMap; end; implementation { TForm1 } procedure TForm1.InitializeForm; begin inherited; end; procedure TForm1.InitializeObject; var APIKey : String; begin inherited; {$I 'Form1:impl'} FMapDIV := TW3DIVHtmlElement.Create(Self); FMapDiv.SetBounds(5,5,450,400); //Enter a valid API Key here. It can be obtained from //https://developers.google.com/maps/documentation/javascript/ APIKey := 'YOUR API KEY HERE'; Require(['https://maps.googleapis.com/maps/api/js?key=' + APIKey],procedure() begin InitMap; end); end; procedure TForm1.Resize; begin inherited; end; procedure TForm1.InitMap; var LUluru : JLatLngLiteral; LMapOptions : JMapOptions; LMarkerOptions : JMarkerOptions; LMarker : JMarker; LMapElement : JELement; begin LUluru.lat := -25.3444; LUluru.lng := 131.0369; LMapOptions.Zoom := 13; LMapOptions.Center := LUluru; LMapElement := Document.getElementById(FMapDIV.Handle.id); FMap := JMap.Create(LMapElement,LMapOptions); LMarkerOptions.position := LUluru; LMarkerOptions.map := FMap; LMarkerOptions.title := 'Woo Hoo!'; LMarker := JMarker.Create(LMarkerOptions); end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
  5. 5 points
    lennart

    Database Examples

    Sorry for the delay we are working non-stop on the next update, so its hectic! First, let me explain a bit where we are, so we can pick the right storage mechanism: The past months we have focused solely on the visual aspect of the RTL. We had to start somewhere and since the visual aspect is what most people care about first, that seemed like the best place. So as you have no doubt seen, we have gone through the RTL with a fine tooth comb, removing things that didnt work, rewriting controls from scratch and testing each part to make sure that everything works. But that is just 1/3 of the path we are on. We are now moving into the non-visual aspects of the RTL. Here we have things like databases, non-visual controls (TComponent in Delphi and Lazarus), filesystems and ultimately node.js - which by nature is UI less and runs on the server (or the shell). We have also brushed up Phonegap and removed the wrongs we found there. The Phonegap API has not stood still and have evolved, so it was due for an overhaul. So that is a quick "status". We are completing 1/3 of the planned system, which covers the visual aspects. DB typically falls under "non-visual", with bindings back to visual later. DB for browsers, what is what? Modern browsers actually have 3 DB engines built into them: WebSQL IndexDB Microsoft Access (*) (*) Only supported by Microsoft and relies on COM (so not for mobile). It must be mentioned that WebSQL, which is the only really good option here, has been deprecated. But it wont vanish tomorrow. The W3C (world wide web consortium) is a bit like the vatican; they move in decades and code will linger in the codebase for ages before it changes. So I wouldnt worry too much about using WebSQL. Secondly, there are shim's for everything these days. A "shim" is a JS re-implementation of something. What a shim does is check if a feature is supported, and if it's not then the shim installs itself and delivers the missing functionality. In other words, you can safely use websql and just download a shim if suddenly google or firefox lacks it. Here is a nice shim for websql: https://github.com/agershun/WebSQLShim Then there is IndexDB. This is a no-sql database and is designed to store JS structures (or objects) in a typical name-value pair style. I think JS people like this a lot since they can easily stuff raw JS objects into it, using a string key. And while it does have its uses, its not a table/row/column solutions. And finally there is access. Which is a pure Microsoft solution, only runs in Edge or Internet Explorer and requires the onslaught of COM. This might have changed in the later versions of edge but either way - this is Microsoft only. So I doubt that is interesting. Thinking outside the box, Smart approach Facing this typical JavaScript mess (sorry but it's true, the browser wars were not kind to JS) I decided we needed to become independent. Browsers change all the time and JS have little standards to speak of compared to Delphi, C# or C++; So coming from Delphi JS will be hell to work with unless you do a long and serious study. Our role is in many ways to "tame" JS and force it to behave inside object pascal's rules. So we needed some structure, something that only change when we allow it! So that people can write programs without being afraid that it will vanish in six months. So we created two solutions: TW3Dataset for simple, single table work SQLite compiled from C to JavaScript Note: Some bugs sadly crept into TW3Dataset, but these have been fixed. So the next update will remedy the situation profoundly. The second option, SQLite, is awesome. It is a pure, 1:1 compile from the original C code, so it contains everything WebSQL has "and then some". The reason it havent been wrapped more rigidly is because it's destined to become a part of our "DataSnap" like API later. Like mentioned above we are on a journey here, and we have to deal with things in the right order. So each DB engine will be isolated in a "driver" like class and then register with a common API. That way people can use classes like TDatabase, TQuery, TStatement and similar high-level components to access any database they like. IndexDB is the oddball in all of this, so we might write a shim/proxy to leverage that. Picking an engine OK, with a situation rapport out of the way, lets pick a database. Our options are thus: WebSQL SQLite TW3Dataset Since TW3Dataset needs the update, I have excluded that. SQLite is awesome but could perhaps need more solid wrappers. So for this I will use WebSQL since that has more clearly defined classes. Picking a storage point Browsers only have cache storage. This is basically a sandboxed file that is saved in the cache folder. Under phonegap this is likewise sandboxed and stored in the "yourname.app/cache" folder if im not mistaken (not sure about that one, please check the Phonegap docs if you need the absolute path). But you dont need a path to load or save into the cache. The browser maps your data into the file-region automatically. Also worth mentioning: When you run in the browser you have a limit of 10-15 megabytes (depends on the browser) for cache storage. When you link the project with Phonegap this limit goes away and you have the same storage rights as native applications. So you dont need to worry about running out of space if you plan to link with phonegap. For pure browser work, you are not expected to make huge databases - but rather cache info before shipping that to a server. A bit like what you would use TClientDataset for under Delphi. But ok, let's use normal cache storage for now. WebSQL is excellent because this will store itself automatically! You dont need to do anything in particular to load or save it. It all boils down to you creating or dropping the database. DB example Right! So fire up Smart and create a new visual project. Our first business is to create the database object and I typically put that into the application class. That way it can be accessed by any form in the program. A nice helper function is also good to have. Here is how it looks so far: unit Unit1; interface uses Pseudo.CreateForms, System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms, SmartCL.Application, SmartCL.DbSql, Form1; type TApplication = class(TW3CustomApplication) private FDatabase: TW3WebSQLDatabase; public procedure ApplicationStarting; override; published Property Database: TW3WebSQLDatabase read FDatabase; end; // global easy-access function to DB layer function Datastore: TW3WebSQLDatabase; implementation function Datastore: TW3WebSQLDatabase; begin Result := TApplication(Application).database; end; procedure TApplication.ApplicationStarting; begin //setup database engine FDatabase:=TW3WebSQLDatabase.Create; FDatabase.DBName:={$I 'app:name'}; FDatabase.DBDescription:='Database for ' + {$I 'app:name'}; FDatabase.DBSize:=(1024 * 1024) * 4; inherited; end; end. This creates a websql database that can hold 4 megabytes of data. Which in browser terms is huge (I mean, you are not doing your taxes here are you). Then there is the main form and actually making something happen. So drop a TW3Button on the form and set the title to "Create Database". We then need some code to create a table and insert some records. For brewity here is the whole code for Form1: unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.DbSql, SmartCL.Controls.Button; type TForm1 = class(TW3Form) procedure W3Button1Click(Sender: TObject); private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation { TForm1 } uses unit1; procedure TForm1.W3Button1Click(Sender: TObject); var Transaction: TW3WebSQLCustomTransaction; begin // activate database try if not Datastore.Active then Datastore.Active := True; except on e: exception do begin writeln("Failed to activate database: "); writeln(e.message); exit; end; end; // Get new write transaction if Datastore.GetWriteTransaction(Transaction) then begin // Create our table try Transaction.Execute("create table if not exists customers (id integer primary key asc, name string);",[]); finally if Transaction.LastFailed then WriteLn(Transaction.LastError); Transaction.Free; end; end else raise Exception.Create('Failed to create write transaction error'); // Get new write transaction if Datastore.GetWriteTransaction(Transaction) then begin try // Populate the table with some records for var x := 1 to 10 do begin var MyData := 'John Doe #' + x.ToString(); Transaction.Execute("insert into customers (name) values (?);",[MyData]); end; finally if Transaction.LastFailed then WriteLn(Transaction.LastError); Transaction.Free; end; end else raise Exception.Create('Failed to create write transaction error'); // Get a new read transaction if DataStore.GetReadTransaction(Transaction) then begin // Setup the OnSuccess event handler. Transaction.OnSuccess := procedure (Sender: TObject) begin var Reader := TW3WebSQLReadTransaction(Sender); if Reader.Dataset <> nil then begin var Dataset := Reader.Dataset; for var x := 0 to Dataset.rows.Length - 1 do begin var Row := Dataset.rows.item(x); WriteLn(Row['name']); end; end; // All done, kill the transaction Reader.free; end; // Setup the OnFailed event handler TransAction.OnFailed := procedure (Sender: TObject) begin var Reader := TW3WebSQLReadTransaction(Sender); writelnF("Read transaction failed: %s", [reader.LastError]); // Kill the transaction Reader.free; end; // OK lets execute the SQL Query! try Transaction.Execute("select * from customers;",[]); finally if Transaction.LastFailed then WriteLn(Transaction.LastError); end; end; end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end. Now you are going to notice something -- namely that the database is persistent (!) So if you run this example 10 times, it will actually create 10 new records every time. The key here is the SQL that creates the database: Transaction.Execute("create table if not exists customers (id integer primary key asc, name string);",[]); This basically says "Create this database UNLESS it already exists". Manual storage with SQLite I am bit pressed for time right now. I will be away from the office for about a month pending surgery. I will be busy with forum duty etc. as much as I can, but sadly a secondary example with SQLite will have to wait a little. But I hope this one has given you an easy path to store things in the cache. Also remember: You can look at the data using the Browser Devtools I will do an article on SQLite when time allows
  6. 5 points
    Czar

    New forum software version

    So far working fine for me - an improvement over the previous forum. BTW I am loving the activity of users and admins in the forum. Hopefully it will continue to grow.
  7. 4 points
    lynkfs

    console override

    redirecting 'console.log' or 'writeln' output proves to be very simple : have a form with a Memo component : procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} W3Memo1.Text := 'Console.log : ' + #10; browserapi.console.log := procedure(text:variant) begin W3Memo1.Text := W3Memo1.Text + #10 + text; end; writeln('aaa'); browserapi.console.log('bbb'); end; all subsequent calls to writeln and/or console.log are now redirected to the Memo component.
  8. 4 points
    jarto

    Development updates

    17.11.2018 RTL: Changes to handling of Cursor: Style definitions moved from basic html elements to control styles GetCursor and SetCursor can now be overridden Bug fixes to how many controls handle cursor. Especially TW3Label. Themes: Add missing styles TW3CheckBox, TW3CheckMark, TW3RadioButton, TW3RadioToggle and TW3RadioGroup Two new backgrounds: TW3DecorativeListItemBackground and TW3TransparentBackground RTL optimizations to creation of controls, GetBoundsRect, SetBounds, MoveTo and SetSize. Bug fix to SmartCL.Graphics.pas: Changing of canvas font, size and styles did not work. Bug fix to System.DateUtils.DecodeDate. IDE: Delete key works now Search dialog and other dialogs. Bug fix: Internal Browser Window showed only a white screen if Execute was clicked while it was open. Compiler: Now(), EncodeDate() and EncodeTime() returns now the same values as Delphi and FPC All time/date -functions fixed to work with the new TDateTime-values
  9. 4 points
    jarto

    DayOf reporting false value

    I dug around and found out that I actually can fix those "buggy" functions in the compiler without having to upgrade to a newer version of DWScript. I only have IncMonth to fix any more. The root cause of the problem is the way javascript dates work. When you build a date from day, month and year, the result depends on your time zone. I guess it builds the date as UTC and then views it from your location. So, while it's 01.12.2018 at 00:00:00 in London, it's still 30.11.2018 in USA. And when you call DayOf on that, you get 30 instead of 1. This affects about 10 other functions as well, including FormatDateTime and DateTimeToStr and TimeToStr. I'll make sure to test this all properly and then release an update. Once it's done, I'm super happy to get rid of these problems.
  10. 4 points
    jarto

    Yikes!!!

    I'm sad to see Jon leave his baby like this, but I do respect his decision. What I can say is, that SMS is not dying here. I've been waiting a few weeks already to push a new update, but have not been able to get any answers from Jon, if he'd also want to include some changes. I believe things look worse to you guys than they really are. A lot of RTL work and especially bug fixes was done by me during the last year and almost all the IDE improvements and bug fixes by Primoz. Jon did pretty much all the NodeJS work, so we'll miss him most there. If I look at this optimistically, Jon's donating his shares to two young and talented Delphi programmers is a very nice thing and may give them a possibility to spend more time on SMS. But hey, hang on there and lets hope that this divorce will not be too ugly.
  11. 4 points
    I'd rather do it like Delphi and Lazarus: Keycode as a var parameter and setting it to #0 would cancel. However, that would break backwards compatibility of SMS code just as any other new parameters would do. If you guys don't see it as a big problem, we could do it in a future version. Let me know what your thoughts are.
  12. 4 points
    jarto

    Scroll bar bug

    This was a weird bug that required changes in SynEdit code itself. May be a Delphi bug even. But I got it fixed and it will be in 3.0
  13. 4 points
    @rshotbolt Here are some resources that might help you out. I like the first one as it explains the precedence and how each overrides the others. Playing with the design 03.06.2013 https://smartmobilestudio.com/2013/06/03/playing-with-the-design/ Smart Mobile Studio and CSS: part 1 October 9, 2017 https://jonlennartaasenden.wordpress.com/2017/10/09/smart-mobile-studio-and-css-part-1/ Smart Mobile Studio and CSS: part 2 https://jonlennartaasenden.wordpress.com/2017/10/11/smart-mobile-studio-and-css-part-2/ Smart Mobile Studio and CSS: part 3 https://jonlennartaasenden.wordpress.com/2017/10/12/smart-mobile-studio-and-css-part-3/ Smart Mobile Studio and CSS: part 4 https://jonlennartaasenden.wordpress.com/2017/10/18/smart-mobile-studio-and-css-part-4/ Themes and styles https://smartmobilestudio.com/documentation/getting-started/themes-and-styles/ Working with controls, the boxing model 05.01.2012 https://smartmobilestudio.com/2012/01/05/working-with-controls-the-boxing-model/ Hidden stylesheets with Smart Pascal August 13, 2014 https://jonlennartaasenden.wordpress.com/2014/08/13/hidden-stylesheets-with-smart-pascal/ HTML5 Attributes, learn how to trigger conditional styling with Smart Mobile Studio November 8, 2017 https://jonlennartaasenden.wordpress.com/2017/11/08/html5-attributes-learn-how-to-trigger-conditional-styling-with-smart-mobile-studio/
  14. 4 points
    lennart

    databases and applications

    This is taken into account with the framework we are researching / making now. The objects you use to access data act more as "front-ends" to the mechanisms behind it, and just like the filesystem classes the operations are all async. This has the benefit of decoupling the consumer-part (i.e controls + bindings) from the producer aspect. To the consumer parts the database can be resident - or on the other side of the planet, it cares not where the data originates, only that its made available in a format that it can use. A typical middleware entity would be a node.js server that is connected to X number of databases. The client will use the framework and connect to the node.js endpoint, but neither the controls or bindings will have any clue about the data originating from a server. It will simply see a driver and issue calls to it. When the driver (or class) gets the data it will validate and dispatch it via its internal mechanisms. The nice part about this is that, a datasource can be almost anything. As long as someone implements the 3 core classes, it can be anything from a hardcoded file, local database or remote data server for that matter. I will go into more detail about these classes when we are a little closer, but you are quite right that old-school 1:1 endpoints is useless in the new paradigm
  15. 4 points
    We're getting closer to the official release. The first beta is out! https://smartmobilestudio.com/2018/02/12/smart-mobile-studio-3-0-0-beta1-released/
  16. 4 points
    A new update is available (in both alpha- and beta-channels on SmartUpdate) aand it's a big one: IDE: - Added TStrings-support to Object Inspector, which allows editing of: - TW3ListBox.Items - TW3ComboBox.Items - TW3RadioGroup.Items - TW3TabControl.Tabs - NodeJS background executions are stopped when project is closed. - Bug fixes to OmniXML - Updated Datasnap proxy generator dll to latest - Fixed problem with Datasnap access interface importer RTL: - New control: TW3GoogleMaps - TW3TabControl can use Forms as Tab contents (Check TabForms -demo) - Updated node.js headers to version 8.10.0 LTS compatible with stable v9.8.0) - Isolated node.js EventEmitter in separate unit (NodeJS.Events) as per specification (node.js v6.9.1) - Implemented System.IOUtils with storage independent TPath class - Implemented a synchronous node.js filesystem API, TW3NodeSyncFileAPI class in SmartNJ.System - Implemented abstract directory parser (TW3DirectoryParser in System.IOUtils) - Implemented standard system file and folder functiction in SmartNJ.System - Upgraded our virtual, BTree based in-memory filesystem to use TPath - Changed TW3VirtualFileSystem to store data as TByteArray rather than variant - Implemented directory parser for Linux, Unix and Windows - Implemented abstract storage device driver (System.Device.Storage) - Implemented storage device driver for browsers (SmartCL.Device.Storage) - Implemented storage device driver for node.js (SmartNJ.Device.Storage) - Implemented TW3DirectoryWatch class for node.js (SmartNJ.Device.Storage) - Implemented TApplication object for node.js, exposing traditional properties and process info - Updated our message api (SmartCL.Messages) to support javascript messagechannel ports - Added full support for socket.io clients (SmartCL.Net.Socketio) - Updated TW3Memo control to initialize states for autocorrect, autocapitalize etc. - Added GetIsRunningInBrowser function to system.types - TStreamReader and TStreamWriter moved to System.Reader and System.Writer units. This deprecates the System.StreamReader and System.StreamWriter units. - Implemented new string parser functions for recognizing intrinsic types (TDataType in System.Types.Convert) - Updated TW3DatasetFilter to use new parser framework - Fixed string-to-intrinsic-type (TryStrToInt, TryStrToBoolean etc) functions - Full re-implementation of our parser framework (System.Text.Parser) - Partial class TBinaryData, under node has functions for consuming and emitting data as a node buffer - Fixed bug in our node.js http server (SmartNJ.Server.HTTP) where the response object would not release if an error occured, causing the server to drop the connection. - Cleaned up multiple declarations for JBuffer and JNodeBuffer, now isolated in unit nodejs.core - Changed default creation flags for node.js files to R+W as opposed to R+W+E (only affects Linux) - Fixed bug where TNJHttpRequest.GetHeaders function returned null - Removed use of JError under node where applicable, now use TJSErrorObject from system.types unit - Updated bytecode assembler and virtual machine project to latest - Removed TFileNameHelper class from SmartCl.Legacy unit, this is now handled by TPath in System.IOUtils - Updated codec manager (system.codec unit) - Implemented RC4 encryption codec and binding (System.Codec.RC4) - Updated Base64.js to latest revision (libraries/base64.js) which is added by the linker on demand - Full re-implementation of base64 codec (System.Codec.base64 unit) - Changed TString.ToBase64() function to use new codec - TW3GroupBox header fixed, now uses TW3Label rather than mapping the unreliable <legend> tag - Improved AutoCreateForm routine, this now performs better checking before construction - TW3Grid control now uses TW3ScrollControl as a container, adding momentum scrolling and better touch handling - Fixed important problem with TString helper class, function missing @ for result caused exception Demos: - Full reimplementation of our websocket server, replacing websocket.io with the standard ws package - Updated all node.js demos to use our high-level classes - Updated WebSQL demo to use correct names - Updated "Binary data" demo to use TBinaryData class (System.Memory.Buffer unit) - Fishfacts demo updated to use new functionality - Fixed problems with advanced demos (biotopia in particular) to work with latest RTL
  17. 4 points
    IElite

    Google Maps API

    the google map, defaults to the roadmap view, so I added the MapTypeId to the code i posted above just add the following to the interface section const HYBRID = 'hybrid'; ROADMAP = 'roadmap'; SATELLITE = 'satellite'; TERRAIN = 'terrain'; JMapOptions = record property Zoom : Integer; property Center : JLatLngLiteral; property mapTypeId: String; end; change the following procedure to include the MapType param procedure InitMap(AAPIKey, ATitle: String; AMapType: String; ALat, ALong: Double; AControl: TW3CustomControl); and then in the implementation section, modify the require to include the mapTypeId option Require(['https://maps.googleapis.com/maps/api/js?key=' + AAPIKey],procedure() begin ... LMapOptions.mapTypeId:= AMapType; ... end); In my case, i needed my map to default to the TERRAIN view so, i used the TERRAIN const InitMap('myApiKey', Mountain, TERRAIN, Latitude, Longitude, FMap); e.g.
  18. 4 points
    jarto

    Creating a mobile app for Android and iOS

    Phonegap has a lot of plugins, that let you access your phone's features. As a quick example, here's how you can make your phone purr: Add to your Phonegap project's config.xml : <plugin name="cordova-plugin-vibration" source="npm" spec="~2.1.6" /> Cool thing about Phonegap Desktop is, that that environment automatically downloads and installs the plugins. When you run the project in Phonegap Desktop, you'll notice how the new plugin appeared in the Plugins- folder. In Smart Mobile Studio, after the Phonegap has been initialized: PhoneGap.Notification.vibrate(1000); When you deal with Phonegap, make sure that you wait for that signal, that it's been properly initialized. The example I posted above expects that the form will be initialized before Phonegap is ready. In general, you should wait for the initialization once, while your app is starting and make sure to always check before calling Phonegap: if PhoneGap.Ready then PhoneGap.Notification.vibrate(1000);
  19. 4 points
    Dennis07

    New forum software version

    Dear Smart community! we are proud to announce that we finished updating the software of our forums, as you might have noticed. If you encounter bugs, please let us know about them so that we can take care of them as soon as possible. Stuff like clearing notifications, editing profile settings, setting profile pics should work now without problems. Wishing you all the best!
  20. 4 points
    lynkfs

    Pagespeed ranking 98/100

    Googles PageSpeed tool (https://developers.google.com/speed/pagespeed/insights/) checks any website or webapp on various speedfactors, and returns a rating both for desktop and mobile. Most of these factors are easy to implement. Just tick the relevant minifying, packing, obfuscation boxes in the "Compiler-Code generation" section of the Project Options. The PageSpeed tool also flags un-optimised images and even optimises them to download. The more difficult option is the rule about "prioritising visible content". This is obviously difficult to do in regular SMS projects. Both the CSS and JS files generated by the compiler don't make any distinction between 'above' or 'below' the fold. To circumvent this, the following works for me : Get the generated HTML code for the first form. Easiest is execute the project in the IDE, go to the "Console section" in DevTools and type 'copy(document.body.innerHTML);' This copies the generated HTML to the clipboard. Insert this code in the HTML template in the top of the <body> section Insert the keyword 'async' in the <script> section where the main.js file is loaded This basically quickly renders the first page in HTML only and the user will see it pretty quickly. It won't do anything until the js file has loaded but that's generally ok. CSS files, unless really really big, usually don't pose a problem as they can fit into the initial congestion window (typically 14.6kB compressed) Doing this gives me a 98/100 rating both for mobile and desktop. The remaining 2% is about 'leveraging browser caching' which doesn't bother me too much. Haven't checked yet what the sms manifest file options may do to this rule.
  21. 4 points
    krolikbest

    simple game

    Hi, there is simple game i've written for my children. Hope you enjoy this game too probably a code is not mastery but it works guessing game for children.7z
  22. 4 points
    Czar

    simple game

    Either that or support this great product
  23. 3 points
    New update available with SmartUpdate in both alpha- and beta-channels: 1.7.2018 Range checking caused apps not to start due to an error in Base64 lookup tables. Update TW3AceEditor. TW3TabControl: If PrepareTab was called for the visible tab, it was moved to the wrong place. TW3Label: Fix vertical alignment to work with older browsers. TW3ComboBox: Allow values to be set during ObjectReady. Bug fix to TMemoryStream.WriteBuffer. Bug fix to WaitFor.
  24. 3 points
    lynkfs

    OAUTH reading gmail account

    To get my head around OAUTH2 I bought a book with the same title by Matt Biehl. This gives a good overview on the internals and use of OAUTH2 This post is about accessing Gmail accounts using Googles OAUTH2 authorisation process. Essentially this is a conversation involving multiple parties/servers and goes something like this : register app with google app sends request to googles oauth2 server : I would like to get access to emails from a specific account oauth server sends mail to email account owner : do you agree in general y/n oauth server sends mail to email account owner : do you agree this app specifically y/n oauth server sends authorisation code to app app sends to oauth/token : authorisation code, client id and client secret code oauth server sends an access token to app app sends access token to Gmail server Gmail server checks with oauth server if all ok y/n Gmail server send email info to app 1 Register app (manual) go to https://console.developers.google.com and start a new project. Select this project and enable the Gmail API. Next steps are to create the credentials for this project. Set type of project to 'call Gmail API from webbrowser' and give it a re-direct uri (http://www.lynkfs.com/oauth2callback) which is used to receive the access token later on. Also supply the gmail account. Output of this process is a client-id and client-secret code. The json output looks something like this client_id.json: {"web":{"client_id":"**********54-g488vat18lh9letonlclj82mpisso25o.apps.googleusercontent.com","project_id":"sms-gmail-******","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"**********fbob3FiixcNkGO"}} 2-5 Request permissions (browser) This process uses the generated codes from the previous step : https://accounts.google.com/o/oauth2/auth? redirect_uri=http%3A%2F%2Fwww.lynkfs.com%2Foauth2callback&response_type=code&client_id=**********54-g488vat18lh9letonlclj82mpisso25o.apps.googleusercontent.com&scope=https%3A%2F%2Fmail.google.com%2F&approval_prompt=force Note that the redirect_uri and scope are in urlencoded format (use https://www.urlencoder.org to get this encoding) This generates a warning that the app is not verified yet by Google, which can be ignored for now. It also asks the gmail account owner if it is ok to give permission to access emails. When all good, it generates an access code directed to the specified endpoint, where 'code' is the access code : http://www.lynkfs.com/oauth2callback/?code=**********oOs4d1E5Ud-uFIUGocpqJLNGvEz07_pWXEHbJzAe-XfhRa3oqb_iSa3KfavmhS96m2dfW30RxgVG9bo# 6-10 Getting emails (app) Access code, client ID and client secret are used for a verification process by Googles OAUTH server. This is initiated by the app through a normal XMLHTTPRequest, specifying 'POST', a header ('application/x-www-form-urlencoded') and specific form-fields for access-code, client ID and client secret. The below curl command emulates this post request. (cURL is embedded in windows since Win10 and can be used from a terminal window (cmd). curl -X POST -H "content-type: application/x-www-form-urlencoded" -d "grant_type=authorization_code&code=**********oOs4d1E5Ud-uFIUGocpqJLNGvEz07_pWXEHbJzAe-XfhRa3oqb_iSa3KfavmhS96m2dfW30RxgVG9bo#&redirect_uri=http%3A%2F%2Fwww.lynkfs.com%2Foauth2callback&client_id=**********54-g488vat18lh9letonlclj82mpisso25o.apps.googleusercontent.com&client_secret=**********fbob3FiixcNkGO" "https://accounts.google.com/o/oauth2/token" The response to this request is an access token { "access_token" : "**********ZUMtl3tRxBaubj7CkGohXnKyqZetVwgd-PDEBBdXwsQyS6OMlYw7EVUgsI31KpZ-d0FRGD3uF6P-A4qHLbE_zEaIS5t0ypHon8Ujr4SY2-qGZgvayHETa_u", "expires_in" : 3600, "token_type" : "Bearer" } which then is used to access the actual Gmail server : curl -H "Authorization: Bearer **********ZUMtl3tRxBaubj7CkGohXnKyqZetVwgd-PDEBBdXwsQyS6OMlYw7EVUgsI31KpZ-d0FRGD3uF6P-A4qHLbE_zEaIS5t0ypHon8Ujr4SY2-qGZgvayHETa_u" "https://www.googleapis.com/gmail/v1/users/lynkfs@gmail.com/messages" The response is a list of email-id's : "threadId": "16365b4d517c6efb" }, { "id": "1636587e232e2b8d", "threadId": "1636587e232e2b8d" }, { "id": "16364296ff92443a", "threadId": "16364296ff92443a" }, { "id": "1636420869e48b44", "threadId": "1636420869e48b44" }, { "id": "16363f9ada40efd7", "threadId": "16363f9ada40efd7" }, which can be individually accessed by appending the id to the previous request (.....@gmail.com/messages/16363ac8731244e4) and the final email details is a json structure looking like { "id": "16363ac8731244e4", "threadId": "16363ac8731244e4", "labelIds": [ "CATEGORY_PROMOTIONS", "UNREAD", "INBOX" ], "snippet": "Hey LynkFS, Since the Community Facebook Group was launched last year, we've grown, found our voice, and watched our customers find theirs. It's an amazing experience, and for those of", "historyId": "4398240", "internalDate": "1526385618000", "payload": { "partId": "", "mimeType": "multipart/alternative", "filename": "", "headers": [ { "name": "Delivered-To", "value": "lynkfs@gmail.com" }, etc etc. OAUTH2 can not only be used to access Gmail accounts, but also all 30-odd other Google services. And Facebook, LinkedIn and many more service providers. Takes a bit of doing but once set up it is quite easy to use.
  25. 3 points
    IElite

    Google Maps API

    Thank You! I needed this for an app I was currently working on However, for me, I needed to place the API code in its own unit... unit GoogleMaps; interface uses System.Types, System.Types.Convert, SmartCL.System, SmartCL.Components, SmartCL.Require, System.JSON, W3C.HTML5, W3C.DOM; type JMap = partial Class external; JLatLngLiteral = record Property lat : Double; Property lng : Double; end; JMapOptions = record property Zoom : Integer; property Center : JLatLngLiteral; end; JMarkerOptions = record property position : JLatLngLiteral; property map : JMap; property title : String; end; JMarker = partial class external 'google.maps.Marker' Public Constructor Create(options:JMarkerOptions); external 'Marker'; end; JMap = partial class external 'google.maps.Map' public Constructor Create(mapDiv:JElement; options : JMapOptions); external 'Map'; end; procedure InitMap(AAPIKey, ATitle: String; ALat, ALong: Double; AControl: TW3CustomControl); var Map : JMap; implementation procedure InitMap(AAPIKey, ATitle: String; ALat, ALong: Double; AControl: TW3CustomControl); var LUluru : JLatLngLiteral; LMapOptions : JMapOptions; LMarkerOptions : JMarkerOptions; LMarker : JMarker; LMapElement : JElement; begin Require(['https://maps.googleapis.com/maps/api/js?key=' + AAPIKey],procedure() begin LUluru.lat := ALat; LUluru.lng := ALong; LMapOptions.Zoom := 10; LMapOptions.Center := LUluru; LMapElement := Document.getElementById(AControl.Handle.id); Map := JMap.Create(LMapElement,LMapOptions); LMarkerOptions.position := LUluru; LMarkerOptions.map := Map; LMarkerOptions.title := ATitle; LMarker := JMarker.Create(LMarkerOptions); end); end; end. Then I could call it on any form and Control I want unit Form1; interface uses System.Types, SmartCL.Application, SmartCL.System, SmartCL.Forms, SmartCL.Controls.Elements; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} MapDIV : TW3DIVHtmlElement; protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation uses GoogleMaps; { TForm1 } procedure TForm1.InitializeForm; begin inherited; end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} MapDIV := TW3DIVHtmlElement.Create(Self); end; procedure TForm1.Resize; begin inherited; MapDiv.SetBounds(0,0,ClientWidth,ClientHeight); InitMap('My API Key Here!', 'Mt Marcy', 44.112917, -73.923, MapDIV); end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
×