Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by warleyalex

  1. warleyalex

    window component

    OFF TOPIC - "SMS Component design" Just things that crosses my mind, and I want to discuss. Please don’t see that as an attack to someones's work. I really like SMS and the new possibilities. We all want the best possible development experience result. While the visual widgets/UI in SMS still is customizable (by user and developer). I often spend more time on UI parts to realize the look and feel i want to have. I have to say here, one think that is very frustating for me is the SMS form designer I've spent a few minutes reflecting on this RAD approach and its form designer to create web app. Just drop components onto a form and set up at the objector inspector, the events and the properties. All of the above is great and it will no doubt give us the same benefits as Delphi developers currently enjoy. The compiler will auto generate the components for you, such as: var btn1: TButton; btn1 := TButton.Create(Self); btn1.Width := 121; btn1.Top := 16; btn1.Left := 536; btn1.Height := 25; btn1.Name := 'btn1'; btn1.OnClick := Self.btn1Click; The UI part could be implemented on top of TCustomComponent, both visual or non-visual components could be used. "the window component" - it's great candidate hein! ...but what I really don't like this approach is when i.e. you drop "a visual component" onto form, you see "rectangule" drawing which represents the component itself you dropped. I can't seem to find anyway how to get the "live preview" on the SMS designer on those components I've created. other thing is the "objector inspector" support for some custom properties. For instance, if the user choose 'Material' from the list, the Material CSS style should be applied to the component. type TCustomStyle = array[1..3] of string; const CustomStyle : TCustomStyle = ('iOS','Android','Material'); type TMystyle = (cssIOS, cssAndroid, cssMaterial); TToggleComponent = class(TW3CustomControl) private fMyStyle: TMystyle; fCustomStyle : TCustomStyle; published property Mystyle: TMystyle Read fMyStyle Write fMyStyle default cssAndroid; property CustomStyle: TCustomStyle Read fCustomStyle Write fCustomStyle; ...when I see at Object Inspector the property MyStyle : 0 (set to zero?). For the boolean type it shows the dropdown list. How can I create a property of type String that will show a combo box in the object inspector with a predefined set of values the user could choose? This is very frustating for me It seems there's just a bit too much work involved to meet even baseline expectations.
  2. warleyalex

    How do I use Secure Websockets (WSS)?

    Could you help to comment that can Websockets work on mobile phones devices? I remember we may be able to use them with SMS applications with mORMot weksockets, built-in using nterface SOA callbacks . But we can seious limitation over a 3G connection or security requirements (like explicit SLL certificates), connections dropping out on mobile phones. Desktops and laptops are a different story of course.
  3. warleyalex

    layout, wordwrap and label nightmare

    We simply cannot open your project at labelissue.zip, missing "Form1.sfm"! It's an old married, TW3Label does not like the TW3Layout. Anyway, I think the unfinished widget SimpleLabel (TW3SimpleLabel => SmartCL.Controls.SimpleLabel.pas) works "almost" as expected. projTeste.zip
  4. warleyalex

    vendor prefix

    The CSS browser prefixes that you can use are: Android: -webkit- Chrome: -webkit- Firefox: -moz- Internet Explorer: -ms- iOS: -webkit- Opera: -o- Safari: -webkit- Please, fix the smartCL.System --> unitFCSSToken := 'Moz'; ---> I think should be lowecase w3_setStyle(FParticles.Handle, BrowserAPI.PrefixDef('transform'), 'scale(0.5,0.5)'); w3_setStyle(FParticles.Handle, BrowserAPI.PrefixDef('transform-origin'), 'left top');
  5. warleyalex

    Beware of box shadows!

    I think box-shadow CSS will need 3 things to work on iOS: 1) Vendor Prefix on the box-shadow -webkit-box-shadow: {...} 2) Border Radius set, example to 1px border-radius: 1px 3) disabled appearance -webkit-appearance: none; //--> remember to put it before box-shadow, not after
  6. warleyalex

    async / await keywords

    look this following procedure: procedure main; begin Sleep(5000); console.log('A'); Sleep(3000); console.log('B'); end; when we run this code, it will immediately output 'A' and 'B' - JS the asyncronous nature. ...but I want our program to log 'A' after 5 seconds then log 'B' after 3 seconds... that why we, we need the async / await native keywords in SMS. In a "synchronous" manner. Await and Async are just syntactic sugar for working with promises. It would be cool if we can declare a method like: procedure main; async; The compiler can check whether the encompassing function has async() in then and emit expectd JS, for instance: (async function(){ })(); Yeah, we need to to wrap it inside an async function and add "await" before the method "Sleep" to work in synchrounous manner.ther await keyword native in SMS would be nice. await Sleep(5000); I found out an ugly workaround for the "Immediately Invoked Function Expression (IIFE) - async function" to work at SMS. { global functions } procedure async(fn: Variant = nil); external '(async function(){' ; procedure &end; external '})'; function await(promise: Variant): JPromise; external 'await '; function Sleep(ms: Integer): JPromise; begin Result := JPromise.Create( procedure(resolve,reject : TCallBack) begin window.setTimeout( procedure() begin console.log('Done waiting'); resolve(ms); end, ms); end); procedure main; begin async; await( Sleep(5000) ); console.log('A after 5s'); await (Sleep(3000)); console.log('B after 3s'); &end; end; end; the compiler will emit expected JS at least: function main() { (async function(){(null); await (Sleep$1(5000)); console.log("A after 5s"); await (Sleep$1(3000)); console.log("B after 3s"); })(); }; but it would super awesome if we could // define procedure as async function procedure main: async; procedure main; begin await Sleep(5000); console.log('A after 5s'); await Sleep(3000); console.log('B after 3s'); end;
  7. warleyalex

    Assigning a Record Type Function Result to a Variant

    I'll try to mimic your example... type TTeamXfer = record TeamID: integer; external 'teamID'; Name: string; external 'name'; Desc: string; external 'desc'; Web: string; external 'web'; Bonus: integer; external 'bonus'; Shots: integer; external 'shots'; Splats: integer; external 'splats'; BonusCurrent: integer; external 'bonusCurrent'; ShotsCurrent: integer; external 'shotsCurrent'; SplatsCurrent: integer; external 'splatsCurrent'; end; type TTeamStruct = class public r: TTeamXfer; function Save(Value: TTeamXfer): TTeamXfer; end; function TTeamStruct.Save(Value: TTeamXfer): TTeamXfer; begin Result.TeamID := Value.TeamID; Result.Name := Value.Name; Result.Desc := Value.Desc; Result.Web := Value.Web; Result.Bonus := Value.Bonus; Result.Shots := Value.Shots; Result.Splats := Value.Splats; Result.BonusCurrent := Value.BonusCurrent; Result.ShotsCurrent := Value.ShotsCurrent; Result.SplatsCurrent := Value.SplatsCurrent; end; type TPXMessageCallback = procedure; procedure test; begin console.log('testing...'); end; procedure PXSend(v: integer; aData: Variant; aCallback: TPXMessageCallback); begin console.log( aData.obj.r ); end; procedure PXTeamCreate(aTeam: TTeamStruct; aCallback: TPXMessageCallback); begin var aData: Variant := new JObject; aData.obj := aTeam; aData.team := @aTeam.Save; PXSend(200, aData, @aCallback); end; var Team: TTeamStruct; Team := TTeamStruct.Create; Team.r.TeamID := 10; Team.r.Name := 'warleyalex'; PXTeamCreate(Team, @test); the compiler emittes this: function PXTeamCreate(aTeam, aCallback) { var aData; aData = {}; aData.obj = aTeam; aData.team = $Event1(aTeam,TTeamStruct.Save); PXSend(200,aData,aCallback); };
  8. warleyalex

    Hoping for a Better Way: Delphi Objects to JS Objects

    to match/map the JSON fieldname, you have to declare the record definition is type TFishRecord = record Category: String; external 'Category'; Common_Name: String; external 'Common_Name'; Length_Cm: String; external 'Length_Cm'; Length_In: String; external 'Length_In'; Notes: String; external 'Notes'; Species_Name: String; external 'Species_Name'; Species_No: String; external 'Species_No'; end; to emit this JS Object, for instance: { Category : "Snapper", Common_Name : "Red Emperor", Length_Cm : "60", Length_In : "23.6220472440945", Notes : "Called seaperch in Australia.", Species_Name : "Lutjanus sebae", Species_No : "90030" }
  9. warleyalex

    Hoping for a Better Way: Delphi Objects to JS Objects

    I think you should use the record type to store/retrieve the JSON data. type TFishRecord = record Category: String; Common_Name: String; Length_Cm: String; Length_In: String; Notes: String; Species_Name: String; Species_No: String; end; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} fishRecord: TFishRecord; protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation var fishJsonData = #'[ {"Species_No":"90020","Category":"Triggerfishy","Common_Name":"Clown Triggerfish","Species_Name":"Ballistoides conspicillum","Length_Cm":"50","Length_In":"19.6850393700787","Notes":"Also known as the big spotted triggerfish. Inhabits outer reef areas and feeds upon crustaceans and mollusks by crushing them with powerful teeth. They are voracious eaters, and divers report seeing the clown triggerfish devour beds of pearl oysters.\r\n\r\nDo not eat this fish. According to an 1878 account, \"the poisonous flesh acts primarily upon the nervous tissue of the stomach, occasioning violent spasms of that organ, and shortly afterwards all the muscles of the body. The frame becomes rocked with spasms, the tongue thickened, the eye fixed, the breathing laborious, and the patient expires in a paroxysm of extreme suffering.\"\r\n\r\nNot edible.\r\n\r\nRange is Indo-Pacific and East Africa to Somoa."}, {"Species_No":"90030","Category":"Snapper","Common_Name":"Red Emperor","Species_Name":"Lutjanus sebae","Length_Cm":"60","Length_In":"23.6220472440945","Notes":"Called seaperch in Australia. Inhabits the areas around lagoon coral reefs and sandy bottoms.\r\n\r\nThe red emperor is a valuable food fish and considered a great sporting fish that fights with fury when hooked. The flesh of an old fish is just as tender to eat as that of the very young.\r\n\r\nRange is from the Indo-Pacific to East Africa."}, {"Species_No":"90050","Category":"Wrasse","Common_Name":"Giant Maori Wrasse","Species_Name":"Cheilinus undulatus","Length_Cm":"229","Length_In":"90.15748031496059","Notes":"This is the largest of all the wrasse. It is found in dense reef areas, feeding on a wide variety of mollusks, fishes, sea urchins, crustaceans, and other invertebrates. In spite of its immense size, divers find it a very wary fish.\r\n\r\nEdibility is considered poor.\r\n\r\nRange is the Indo-Pacific and the Red Sea."} ]'; function getList: variant; begin result := JSON.parse(fishJsonData); end; function JSON2TFishRecord(const Value: variant): TFishRecord; begin result.Category := Value.Category; result.Common_Name := Value.Common_Name; result.Length_Cm := Value.Length_Cm; result.Length_In := Value.Length_In; result.Notes := Value.Notes; result.Species_Name := Value.Species_Name; result.Species_No := Value.Species_No; end; function TFishRecord2JSON(const Value: TFishRecord): variant; begin result := new JObject; result.Category := Value.Category; result.Common_Name := Value.Common_Name; result.Length_Cm := Value.Length_Cm; result.Length_In := Value.Length_In; result.Notes := Value.Notes; result.Species_Name := Value.Species_Name; result.Species_No := Value.Species_No; end; ( TWEdit widget ) categoryEd.Text := fishRecord.Category;
  10. warleyalex

    Shortcut already exists.

    humm, I rememeber this minor bug y can see on the old SMS. I can not see this ugly message anymore on the 3.x, anyway you could try this: Tools --> IDE Settings... --> Preferences | Keyboard -> Edit editor shortcuts --> Reset List
  11. warleyalex

    Declaring Record Type Constants

    Solution as JObject base class Type TT = Class(JObject) TableName: string; CreateFunc: TFn; end; var Regist: array of TT; initialization var rr : TT; rr := new TT; rr.TableName := 'devil_report'; rr.CreateFunc := @CreateServer; Regist.Add(rr); rr.TableName := 'flowers_report'; rr.CreateFunc := @CreateServer; Regist.Add(rr); (...) // Display the object for var i:= Regist.Low to Regist.High do console.log(Regist[i]);
  12. warleyalex

    Declaring Record Type Constants

    Another solution using record type; type TModelClassRegistration = record TableName: string; external "TableName"; CreateFunc: function : JPromise; external "CreateFunc"; end; var RegisteredModelClasses: array of TModelClassRegistration; initialization var rec :TModelClassRegistration; rec.TableName := 'devil_report'; rec.CreateFunc := @CreateServer; RegisteredModelClasses.Add(rec); rec.TableName:= 'flowers_report'; rec.CreateFunc := @CreateServer; RegisteredModelClasses.Add(rec); rec.TableName := 'cards_report'; rec.CreateFunc := @CreateServer; RegisteredModelClasses.Add(rec); (...) for var i:= RegisteredModelClasses.Low to RegisteredModelClasses.High do console.log(RegisteredModelClasses[i])
  13. warleyalex

    What happened to VarIsValidRef?

    Yes. they removed the VarIsValidRef method. hum, at the System.types unit, there's a helper class TW3VariantHelper where lives a method Valid. if TW3VariantHelper.Valid(str) then ; I would prefer a global big unit with all methods instead of helper class approach.
  14. warleyalex

    Declaring Record Type Constants

    solution I: =========== var // _TableList: array[0..0] of variant = [ _TableList:= [ CLASS TableName:= 'Server'; external 'TableName'; CreateFunc:= @CreateServer; external 'CreateFunc' END ]; // This works ========================================================== var _TableList2: array[0..0] of TMySqlCreateTable = [ ( TableName: 'Server'; CreateFunc: @CreateServer ) ]; // Syntax Error: Constant expression expected [line: 85, column: 52, file: unit2] ========================================================== _TableList2[0].TableName := 'Server'; _TableList2[0].CreateFunc := @CreateServer; // This works
  15. warleyalex

    SMS 3 + mORMot = Error

    I download the mORMot_and_Open_Source_friends_234301_06b24ae728 today and patched some needed SynCrossPlatform units and mORMotWrappers (generate mORMot cross-platform clients code from the server). and some changes at the project 27 and 29, Now, it compiles and works in both SMS (lastest WinXP compatible) and SMS (development version)! download link: mORMot with SMS 2x and 3x
  16. warleyalex

    SMS 3 + mORMot = Error

    The crazy AB apparently he's out of the time or holidays since december. I do perform the tests on the mORMot lastest trunk (december/2018) and it compiles and works in both SMS (the lastest WinXP compatible) and SMS (development version)! I have to download mORMot again(jan/2019) and submit the changes of the SynCrossPlatform units to AB.
  17. warleyalex

    Endpoints & Resources ?

    A lot of RTL work and especially bug fixes was done, but Jon Lennart did pretty much all the NodeJS work. In one of his posts https://jonlennartaasenden.wordpress.com/2019/01/19/quartex-web-os-a-cloud-os-in-takes-form/ he said: "Also, fixed more bugs in the Smart RTL than I can count..." These fixes are available just for top supporters, you have to pay to become a patron. My intuition is that a quick and deep overdue of the Smart NJ part is required!
  18. warleyalex


    The unit ECMA.Promise is broken. I use this definition Using Promises in SMS unit uPromises; interface uses W3C.Console, W3C.DOM, W3C.XMLHttpRequest; type TVariantDynArray = array of Variant; JDeferred = class; TJPromiseCallback = procedure(Value: Variant); TJDeferredObject_fn = function(d: TJPromiseCallback): Variant; TJDeferredObject = procedure(resolve: TJPromiseCallback; reject: TJPromiseCallback); TJPromiseCallback_fn = function(Value: Variant): Variant; TJDeferredEventHandler = function(event: Variant): Variant; JPromise = class external 'Promise' constructor Create(fn: TJDeferredObject_fn { = nil}); overload; constructor Create(resolve: TJDeferredObject_fn; reject: TJDeferredObject_fn); overload; constructor Create(fn: TJDeferredObject); overload; function always(alwaysCallbacks: TVariantDynArray): JPromise; function done(doneCallbacks: TVariantDynArray): JPromise; overload; function done(doneCallbacks: Variant): JPromise; overload; function fail(failCallbacks: TVariantDynArray): JPromise; function progress(progressCallbacks: TVariantDynArray): JPromise; function state(): string; function &then(doneCallbacks: Variant; failCallbacks: Variant{ = undefined}; progressCallbacks: Variant { = undefined}): JPromise; external 'then'; function &then(onFulfilled: TJPromiseCallback_fn = nil): JPromise; overload; external 'then'; function &then(onFulfilled: TJPromiseCallback_fn; onRejected: TJPromiseCallback_fn): JPromise; overload; external 'then'; function &then(onFulfilled: TJPromiseCallback; onRejected: TJPromiseCallback): JPromise; overload; external 'then'; function catch(rejecTJPromiseCallback: Variant = nil): JPromise; overload; function catch(rejecTJPromiseCallback: TJPromiseCallback_fn): JPromise; overload; class function promise(target: Variant): JPromise; end; type JDeferred = class external 'Promise'(JPromise) function notify(args: TVariantDynArray): JDeferred; function notifyWith(context: Variant; args: TVariantDynArray): JDeferred; function reject(args: TVariantDynArray): JDeferred; overload; function reject(args: Variant): JDeferred; overload; function reject(args: TJDeferredEventHandler): JDeferred; overload; function rejectWith(context: Variant; args: TVariantDynArray): JDeferred; function resolve(args: TVariantDynArray): JDeferred; overload; function resolve(value: Variant = nil): JPromise; overload; function resolveWith(context: Variant; args: TVariantDynArray): JDeferred; function all(iterable: TVariantDynArray): JPromise; overload; function race(iterable: TVariantDynArray): JPromise; end; { global external functions } function Promise : JDeferred; external 'Promise' property; function queue: JPromise; external 'Promise.resolve()'; function Error(message: variant): variant; external 'Error'; function document: variant; external "document" property; function window : Variant; external 'window' property; function &typeof(obj:variant): variant; overload; external "typeof"; function wait(ms: Integer): JPromise; function getURI(url: string): Variant; function getFile(url: string): variant; //function myRequire(url: string): Variant; implementation function wait(ms: Integer): JPromise; function setTimeout(ahandler : TJPromiseCallback; aTimeout : Integer): Integer; external 'window.setTimeout'; begin result := JPromise.Create( procedure (resolve, reject: TJPromiseCallback) begin setTimeout(resolve, ms); end); end; function getURI(url: string): Variant; var request: JXMLHttpRequest; procedure p(resolve: TJPromiseCallback; reject: TJPromiseCallback); // Standard XHR to load an image procedure doOnLoad; begin // This is called even on 404 etc // so check the status if (request.status = 200) then begin // If successful, resolve the promise by passing back the request response resolve(request.response); end else begin // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error('File didn''t load successfully; error code: ' + request.statusText)); end; end; procedure doOnError; begin // Also deal with the case when the entire request fails to begin with // This is probably a network error, so reject the promise with an appropriate message reject(Error('There was a network error.')); end; Begin request := JXMLHttpRequest.Create; request.open('GET', url); // When the request loads, check whether it was successful request.addEventListener('load', @doOnLoad); // Handle network errors request.addEventListener('abort', @doOnError); // Send the request request.send(); End; begin // Create new promise with the Promise() constructor; // This has as its argument a function // with two parameters, resolve and reject Result := JPromise.Create(@p); end; function getFile(url: string): variant; begin // Create new promise with the Promise() constructor; // This has as its argument a function // with two parameters, resolve and reject Result := JPromise.create( procedure(resolve: TJPromiseCallback; reject: TJPromiseCallback) // Standard XHR to load an image var request: JXMLHttpRequest; begin request := new JXMLHttpRequest(); request.open('GET', url); // When the request loads, check whether it was successful request.onload := lambda begin // This is called even on 404 etc // so check the status if (request.status = 200) then begin // If successful, resolve the promise by passing back the request response resolve(request.response); end else begin // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error("File didn't load successfully; error code: " + request.statusText)); end; end; end; // Handle network errors request.onerror := lambda // Also deal with the case when the entire request fails to begin with // This is probably a network error, so reject the promise with an appropriate message reject(Error('There was a network error.')); end; // Send the request request.send(); end); end; /* function myRequire( url: string): Variant; function ev(win: Variant; arr: array of Variant): Variant; external 'eval.apply'; var ajax: JXMLHttpRequest; function onReady(event: JEvent): Variant; var script: Variant; begin script := ajax.response; // ?? ajax.responseText; if (ajax.readyState = 4) then begin case( (ajax.status)) of 200: begin //eval.apply( window, [script] ); ev( window, [script] ); console.log('script loaded: '+ url); end else console.log('ERROR: script not loaded: '+ url); end; end; end; begin ajax := JXMLHttpRequest.Create; ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous ajax.onreadystatechange := @onReady; ajax.send(null); end;*/ end.
  19. warleyalex

    stable x unstable IDE

    I don't want to interrupt your holidays. I thought I was going crazy. Crazy about smart. I have SMS 2.2.2 (last winXP), SMS 3.0.2 (stable release) and SMS (development) installed. It was exactly the same project, same source, but I forgot to copy the SynCrossPlatform units ( SynCrossPlatformCrypto.pas | SynCrossPlatformREST.pas | SynCrossPlatformSpecific.pas ) into SMS3.0.20/Libraries folder and the issue has vanished, the designer worked as expected in SMS - without any error.
  20. warleyalex

    stable x unstable IDE

    I've got different tastes between SMS and SMS The latter is works as expected. When I open a simple project in the stable version 3.0.2, and I click in button in the project, it displays "Program has errors. Operation might not be completed." It says in the 3.0.2 (this version contains all the fixes and improvements from the development-channel).
  21. warleyalex

    mORMot with SMS

    In fact, there is an bug on older SMS versions 1.2 | 2.0 | 2.0.1 | 2.2 and 2.2.2 - the TObject::Destroy method would just delete the property named "prop" rather than the actually all the properties of the object itself. For instance, obj.Free is doing nothing because the method Destroy was buggy // old SMS version var TObject={ (...) Destroy: function (s) { for (var prop in s) if (s.hasOwnProperty(prop)) delete s.prop }, Destroy$: function(s) { return s.ClassType.Destroy(s) }, (...) } On newer SMS version 3.x, they fixed the TObject::Destroy method.
  22. warleyalex

    mORMot with SMS

    Smart Mobile Studio 3.1 with mORMot Nowadays, the synchronous methods are deprecated is most modern browsers, that "false" makes the request synchronous (i.g. request.open('GET', '/bar/foo.txt', false)), besides the message it works. Note: Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), Blink 39.0, and Edge 13, synchronous requests on the main thread have been deprecated due to the negative effects to the user experience. Anyway, both synchronous and asynchronous methods are available, depending on use case. For instance, you can invoke a method to calculate both in syn or async ways. The synchronous, are methods starting with underscore _*() methods will block the browser execution, so won't be appropriate for long process - on error, they may raise EServiceException. It could be useful in order to interact in background with the server or the preload some content. You shouldn't use sync methods in the future, because it's deprecated. They work but shouldn't be there. I don't pretty sure, but I think the mORMot authentication scheme uses synchronous method for the handshaking process. You must create a service method on the server side and simply typing to generate smartmobilestudio wrapper client, and use the generated unit inside SMS client, like proj 27. I spent hours debugging an issue because in SMS 3.1x I couldn't detect why it couldn't work like in the previous version 2.2x. I realized a lot of optimizations was done in the 3x, like the direct implementation without the intermediary Result variable in the function returning. Anyway, I realized something was bit different from the previous version: In version 3.1x, it emits this piece: var TObject={ $ClassName: "TObject", $Parent: null, ClassName: function (s) { return s.$ClassName }, ClassType: function (s) { return s }, ClassParent: function (s) { return s.$Parent }, $Init: function (s) {}, Create: function (s) { return s }, Destroy: function (s) { for (var prop in s) if (s.hasOwnProperty(prop)) delete s[prop] }, Destroy$: function(s) { return s.ClassType.Destroy(s) }, Free: function (s) { if (s!==null) s.ClassType.Destroy(s) } } I propose this little change be made is SMS 3.1x: Destroy: function (s) { for (var prop in s) if (s.hasOwnProperty(prop)) delete s.prop }, This little issue fixed we can use Smart 3.1x with mORMot with no more errors. According to mORMot documentation, since there is no true file system API available under a HTML5 sand-boxed application, logging to a local file is not an option. Even when packaged with PhoneGap, local log files are not convenient to work with. Generated logs will have the same methods and format as with Delphi or FreePascal - see Local or remote logging. TSQLRest.Log(E: Exception) method will also log the stack trace of the exception! Our LogView tool - Logview - is able to run as a simple but efficient remote log server and viewer, shared with regular or cross-platform units of the framework. A dedicated asynchronous implementation has been refined for Smart Mobile Studio clients, so that several events will be gathered and sent at once to the remote server, to maximize bandwidth use and let the application be still responsive. It allows even complex mobile applications to be debugged with ease, on any device, even over WiFi or 3G/4G networks. Your support could ask your customer to enable logging for a particular case, then see in real time what is wrong with your application. You can use remote logging with smart Mobile Studio! It's cool. I'll have to submit the CrossPlatform units to AB to generated the correct wrapper. smartms_mormot.rar
  23. warleyalex

    stable x unstable IDE

    The download link from SMS 3.0.2 stable release: https://smartmobilestudio.com/download/3.0.2/setup.exe There is no issue when I drag n' drop a new widget/TWButton onto designer then double click at the button in SMS 3.0.2. This is an old SMS project, created with SMS 2.0.1 - packed with winrar 5.50. SMS 3.0.2 can open it but we can not jump to the W3Button1Click procedure like 3.1.x.
  24. warleyalex

    stable x unstable IDE

    SMS (from the development channel) works as expected! The issue is from the SMS (stable release). When I click at the widget button/W3Button2 for instance, it would go to the code editor W3Button2Click procedure in the 3.1x, but fails at 3.0x. <object type="TW3Button"> <Caption>W3Button</Caption> <Width>128</Width> <Top>272</Top> <Left>272</Left> <Height>32</Height> <Name>W3Button2</Name> <OnClick>W3Button2Click</OnClick> </object> ver3x.rar
  25. warleyalex

    Smart Mobile Studio 3.0.2 is released!

    SMS 3.0.2 portable version a) Simple click at https://smartmobilestudio.com/download/3.0.2/setup.exe to install SMS 3.0.2 and install at "C:\smartms" b) move all files and directories from "C:\Users\All Users\The Smart Company\Smart Mobile Studio" to the folder "C:\smartms" c) create a file called "settings.ini" at the directory "C:\smartms" [Settings] Channel=DEVELOPMENT RelativePaths=1