Is it possible to call a function ONLY on the first run? - javascript

I am developing an app using Telerik's Nativescript. I would like to know whether it's possible to call a function the first time the app is ran, but not for each consecutive run.
My first thoughts were to ship a one line text file with the content false. On the first run I would check this file and get the value. If it were false I'd run the function and then update the text file content to true, otherwise I'd let the app continue as normal.
I think there must be a better, more efficient way to do this. Any ideas folks?

I've no idea why you're getting a all these browser technology answers but as you're using NativeScript you most probably want to take a look at the Application Settings module.
A value set with Application Settings will persist for as long as the app is installed on the device. If the user is re-installing the app it'll (of course) be reset.
It's as easy as:
var appSettings = require("application-settings");
if(!appSettings.getBoolean("hasRunned", false)) {
// Do the stuff you want to do on first run
// and then set it to true
appSettings.setBoolean("hasRunned", true);
}

Related

Event like "DOMLastNodeRemoved" to prevent multiple executions of code

First of all: I know that there are some questions similar to this, but I could not found any alternative to it, but to ask.
Hello!
Is there any event like "DOMLastNodeRemoved" (or FirstNode, since u can't know for sure when it will be the last node removed) to prevent multiple executions of code?
Here's the deal, I'm using Genexus. The only way to make an event work in this weird SPA concept is using DOMNodeRemoved event.
But whenever you click a button, it will insert a lot of nodes, making the function execute like 25 times instead of just one.
Let's go to an example:
I'm currently with this code:
$(document).on("DOMNodeRemoved", function() {
$(".Button").click(function() {
setTimeout(
function() {
toastrgx();
$('.gx-warning-message').css('display', 'none');
}, 800);
});
function toastrgx() {
var meuLoader = new Loader($);
meuLoader.Insert();
setTimeout(function() {
meuLoader.Remove();
var text = $('.gx-warning-message').text();
toastr.error(text, '');
}, 500);
};
});
I need to use timeout because the DOM is still loading up the message.
Anyways, with this code I'll get this result presented in the image:
If i use something like preventPropagation (at least the way I used) it will run my code only once, but returns a lot of errors in the console (one for each execution) and also breaks my loader.
BTW, I have power only over one custom script, everything else is generated by Genexus.
So, if I use any other normal event like document.ready, it will fire the first time I load a page within my MasterPage, but, if I click in any other page, it will not fire the event again.
So, my question is:
There is any way to execute a code only once in my case?
Is it something that I'm not seeing clearly like another event or another way to make the code work?
If the question sounds silly, sorry, i'm a newbie in JS.
The way to go in this case is creating a User Control and using its show function, that is executed by the generated application every time the control should update (for example, when the page is loaded or when a property of the control is modified).
Why a User Control?
User Controls offer a standard interface to interoperate with GeneXus generated applications. This interface is well documented and abstracts you from the inner workings of the generated applications.
If you try to extend GeneXus by including scripts, you will be exposed to unexpected behavior and changes without previous notice.
How to create a User Control
To create a User Control I recommend using the GeneXus User Control Generator, for Atom. Using this Atom package you can easily create a GeneXus User Control.
Follow the steps to create a User Control and choose Web when prompted for the supported platforms by the package.
How to have code execute only once, when the page is loaded
After creating the User Control, open the src/<YourUserControlName>Render.js file and edit the show function this way:
this.show = function() {
if (!this.IsPostBack) {
// This code will be executed only, when the page is loaded.
}
}
Inside the if you can code whatever you need to execute only once per page.
How to deploy a User Control
To build and deploy the User Control to your GeneXus installation directory, follow the build process steps described in the package documentation.
Once you have deployed your User Control, you should include it in the master page object, to start using it, instead of the script you are using now.

Is there a way to have a web application continue running even when it is closed?

Suppose I want to build someone similar to an alarm, except every hour it performs a list of tasks. For the sake of this example, suppose it is to send notifications. I want the inner function to look something like this:
$scope.performTasks = function(){
emailUserWeb();
emailUserPhone();
postToFacebook();
postToTwitter();
postToWherever();
}
So, assume everyday, this sends a notification at exactly ##:37pm. If I want something like this to run even when I am not on the site, how can I build something like that? Is it even possible?
Your Javascript is client-sided. That means it can only be executed as long as it is executed by the client's browser.
If you want to execute scheduled tasks, you need a server that runs the code (e.g., NodeJS).
You can build it as Chrome App/Extension which will have a backgroud process, If you keep Chrome running, even if not on the app webpage, it will work.
Check: https://developer.chrome.com/extensions/background_pages

selenium + chrome.fileSystem.chooseEntry = invalid calling page error

I am writing a Selenium script to test a Chrome app that uses the Chrome.fileSystem.chooseEntry API to select a directory. When I do this manually, it works fine. But when I do this in a Selenium script, I get back this error:
Unchecked runtime.lastError while running fileSystem.chooseEntry: Invalid calling page. This function can't be called from a background page.
Any ideas on how to make Selenium and chooseEntry play nicely together?
I updated to the latest Chromedriver, but still no luck. I also looked at ChromeOptions, but didn't see anything that looked like it would be helpful. The interwebs doesn't seem to have much to say about Selenium and chooseEntry. I'm on version 51 of Chrome.
I'm down to thinking I'll need a special javascript entry point to set the path values for testing instead of using chooseEntry. But I would strongly prefer to not have a separate code execution path for my tests. Anybody have a cleaner solution?
EDIT: per commenter's request, here's the offending code:
chrome.fileSystem.chooseEntry({type:'openDirectory'},function(entry) {
chrome.fileSystem.getWritableEntry(entry,function(writeable_entry) {
console.log("got writeable entry");
});
}, function(e) { errorHandler(e); });
EDIT #2: I've gone with the special javascript entry point hack. In manual mode -- i.e., not running under Selenium -- I run code that executes chooseEntry, and then use the retainEntry API to get the entry id. I added an entry point in my javascript to take an entry id and call the restoreEntry API to turn it back into an entry. I also modified my code so if this entry object is set, then use that as the file instead of calling chooseEntry. Lastly, I modified my Selenium script to call the restoreEntry entry point before running the rest of the script.
This is not ideal, since now my test code execution path is somewhat different from my actual live-human-being-at-the-controls code execution path. But at least it lets me use Selenium scripts now. Of course, if anyone can think of a non-horrible way to solve this solution, I'd love to hear about it.
EDIT #3: Per #Xan's comment, corrected my terminology from "extension" to "Chrome App."
I can only offer this horrible hack. For Chrome Apps under OSX I created folder favorites and use Robot keyPress to navigate and select the 'favorite' folders needed for the App. The only possible redeeming factor is that it does mirror a valid/possible actual human interaction with the file interface.
private void selectOSXFolderFavorite(int favorite) {
// With an OSX file folder dialog open, Shift-Tab to favorites list
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_SHIFT);
// move to the top of favorites list
int i = 40;
while (i-- > 0) {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
while (favorite-- > 0) {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
// Send an enter key to Select the selected folder
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
}

What is the recommended way to persist the data in background task? [UWP/W/WP apps]

The question is quite simple, but I seriously couldn't find any sample that would demonstrate something I'm trying to achieve, maybe it's me who is didn't get the concept of background tasks in uwp applications (or windows / windows phone 8).
I'm creating an application that is polling some data (traffic incidents) and would like to be able to notify the user about the closes ones even if he is not using the application. So I reckon I would use the background task. (I hope I get that part right).
So in the background task, which I've set to run on timer of 15 minutes, under the condition of "InternetAvailable", I fetch the data asynchronously and once it's done, I'm completing the deferral object as it's required. All works ok.
The question is, what object shall I use in order to persist the data so I could read the data once the application is opened?
I've tried the WinJS.Application.sessionState but that gets lost once the application is ready (opened).
I've tried the Windows.Storage.ApplicationData.current.localSettings but it says there is a type mismatch, apparently I'm trying to put in there the object, if String is expected (I reckon)...
So does anyone know what is the best practice here ?
Thank you
You have full acess to the WinRT API, so you can write a file (and read the same file once the application is opened):
function saveData(dataObj) {
var applicationData = Windows.Storage.ApplicationData.current;
var localFolder = applicationData.localFolder;
return localFolder.createFileAsync("dataFile.txt", Windows.Storage.CreationCollisionOption.replaceExisting).then(function (sampleFile) {
return Windows.Storage.FileIO.writeTextAsync(sampleFile, JSON.stringify(dataObj));
});
}

how do you allow javascript communications with Flex/Flash/Actionscript

Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player

Categories