What is #targetengine? - javascript

My only prior experience with #targetengine is when I've used #targetengine "session"; to turn a dialog into a palette when scripting in InDesign. But as I'm trying to figure out how to script a menu, I'm starting to see it pop up being used in other ways and using a term (target?) other than session.
Adobe likes to assume that everyone who wants to script is an experienced programmer sometimes, so I haven't found a clear explanation as to what this is.
So, when I use #targetengine, what am I doing? Can I use any term other than "session"? Some searches suggested this feature has to do with global variables; is that the case? If so, how can I clear them out without restarting InDesign? Is this a JavaScript thing or an ExtendScript/InDesign feature?

#targetengine is specific to the Adobe scripting in InDesign, PhotoShop, Illustrator etc. - it is not a general Javascript feature.
It specifies how to handle all the global 'stuff' - not only variables but also function declarations and any other change to the global status.
If you use the default 'main' engine all the globals disappear as soon as the script completes. If you use the 'session' engine all the globals are preserved as long as the host application keeps running. This means that if you run the script:
#targetengine "session"
var test = "test";
and later run the script:
#targetengine "session"
alert(test);
you get a message box showing test instead than giving an error
Besides the two standard 'main' and 'session' engines you can create your own ones, with arbitrary names - so if you run the script
#targetengine "mine"
var test = "another test";
and then run
#targetengine "mine"
alert(test);
you get a message box showing another test, but if you run again
#targetengine "session"
alert(test);
you still get test: there are two different 'test' global variables, one in the 'session' engine and one in the (newly created) 'mine' one.

This discussion was brought up in a Slack channel I monitor. One long-time developer said the following (cleaned up a bit for clarity):
As far as I know //#targetengine only works on InDesign (probably
including InCopy) and Illustrator.
On InDesign it works properly and on Illustrator it does not. Nevertheless other apps as far as I know all have the ability to use targetengines with C++ and that’s what CEP does with each CEP [extension?] having its own isolated engine.
There are at least 3 types of engine.
main engines, in InDesign it’s a temp engine that forgets everything after completing a scripts execution.
Public Private engines like session that remember and are active after script execution and good for event listeners. These and main can be identified using $.engineName and found on ESTK / vsCode
Private Private $.engineName will show "" can only be created with C++ that what most of the apps use and CEP uses except for InDesign where CEP uses Public Private engines which can be chosen.
He thinks there's also a 4th type he's forgetten.

Related

Browser.ExecScript() stopped working after updating windows

I've set up a simple testbed for WatiN (ver 2.1) which reads:
var browser = new IE();
browser.GoTo("http://www.google.co.il"); // webpage doesn't matter really
browser.RunScript("alert(123)");
This works only if KB3025390 is not installed. Installing it breaks the above test with an UnAuthorizedAccessException which has HRESULT set to E_ACCESSDENIED. What gives? Is there any workaround?
Update: Using IWebBrowser2.Navigate2 along with "javascript:console.log(123)" type of scripts works however
it makes me feel uneasy using such a backchannel
the scripts run through this back-channel of .Navigate2() may only have a max length of about 2070 chars (give or take) otherwise they get forcibly truncated to this length leading to javascript errors upon attempting to run them
using .Navigate2(), even with the most trivial script, will clog the ready state of Internet Explorer for good in the sense that it will be set to READYSTATE_LOADING without any hope of getting rid of it. In simple terms this means that once you use this hack, you either have to perform every single subsequent operation in WatiN in a "dont-wait-for-webpage-to-load" fashion (GoToNoWait, ClickNoWait etc) lest your code freezes upon waiting for the browser to turn back to READYSTATE_COMPLETE (which will never come about ofcourse as already mentioned).
there appears to be a much broader issue here in the sense that I can't even access the properties of an IHtmlWindow2 object p.e. window.document throws an unauthorized exception again making it virtually impossible to transfer over to the C# world the return-values of the scripts I'm running (using Expando etc) for documents other than window.top.document (for the window.top.document window there is IWebBrowser2.Document which does the trick)
Update#2: The folks over at the selenium project have also noticed this issue:
https://code.google.com/p/selenium/issues/detail?id=8302
A bug report has been created as well:
https://connect.microsoft.com/IE/feedback/details/1062093/installation-of-kb3025390-breaks-out-of-process-javascript-execution-in-ie11
Update#3: IHTMLWindow2.setInterval and IHTMLWindow2.setTimeout also throw UnauthorizedAccess exceptions. These methods are not marked as deprecated in:
http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa741505%28v=vs.85%29.aspx
yet they have wounded up suffering from the same cutbacks all the same.
Update#4: I gave the approach recommended in this post a shot:
https://stackoverflow.com/a/18546866/863651
In order to dynamically invoke the "eval" method of the IHTMLWindow2 object (or any other method really). Got the same "System.UnauthorizedAccessException" as above. So no joy here either.
Microsoft recommends using "eval" over "execscript" however after the above experiment I suspect that they are refering to accessing "eval" only from within the browser.
As far as I can tell thus far, when it comes to the full-fledged IE11+ using "eval" out-of-process (via COM) appears to have been completely prohibited along with any other function-invocation of the window object, the only exception being the back-channel of the .Navigate2() mentioned above.
It turns out Microsoft eventually backpedaled on its decision to kill off .execScript at COM-level. Just install the latest updates for Windows including kb3025390: One of the updates for IE that came after kb3025390 brings back .execScript functionality at COM-level
Note, however, that .execScript is not accessible through IE's javascript anymore. In that context it's gone for good.
fyi: this one is also not working
ieInstance.Document.Script.<methodNameString>(<commaSeperatedParameterString>)
try this worked for me at some places but not all places
ieObject.Navigate "javascript:<methodNameString>(<commaSeperatedParameterString>)", Null, "_parent"
or
ieObject.Navigate2 "javascript:"<methodNameString>(<commaSeperatedParameterString>)", Null, "_parent"
now trying to find out solution using eval
I have found a way around the problem of an update installing automatically. You can just create a simple batch file with following content.
{code}
#echo off
wusa /uninstall /kb:3025390/quiet /norestart
END
{code}
Then go to task scheduler, create a new task for this batch file to run every one hour or day as per your requirements. Add it as a system task so it runs in the background and does not affect the running automations.

tracking a javascript found in pagesource

ive tried everything i cud to figure this out, but i cannot track a piece of javascript in a webpage
so, just to give you some context even though my problem is not related to just this scenario. it depends on a much bigger spectrum.
Anyway, im developing on sugarCRM and im trying to edit the default onclick behavior of a slot in calendar module (you dont need to understand this to help me, so please keep reading). when i click on a slot, a modal dialog window opens that lets me log a meeting or a call.
So i tracked down the javascript behind this. ive used firebug and chrome, and they both give a list of all the JS files that are being used on a given webpage
for example i search for "SUGAR.collection" and firebug tells me its located in a file named "sugar_field_grp.js?v=FVh1Z-v5nA6bYov7-aFFqQ" i can see this piece of code resides in sugar_field_grp.js,
but the code im trying to change resides in "index.php?module=Calendar&action=index&parentTab=Activities", firebug actually tells me this is the file that has the javascript i want to change.
I can also right click view page source and i can see that piece of code inside the script tag. so considering this piece of code doesnt reside in a JS file, i cannot change it, its generated at runtime (i think) but there must be some source, there must be a file thats telling sugarCRM to generate this code
tl;dr how to track down a piece of javascript code that resides on pagesource and theres no JS file specified by firebug or chrome save for index.php (this file doesnt have that javascript either)
i know its been a long post
thanks for reading
Learn how to search for strings in files on disk on your machine.
On Linux, MacOS and most unixen the go-to tool for this is grep. This applies to any programming language you work with. For your case simply cd into the directory of your source code and do:
grep -r SUGAR.collection .
If you're using git as your source control tool then git grep is much faster.
On Windows there are various GUI tools you can use to search for text in files. Just google: grep for windows.
If you're using an IDE then just your IDE's find-in-files functionality.
To track down specific code using Chrome / Webkit go through the following two steps:
Client:
1. Search all static text sources
Open the Dev Panel using CTRL + SHIFT + I
Hit CTRL + SHIFT + F for a global search dialog to pop up
Right next to it you can set pretty printing of the JS code to on: button { }
Enter your search term or terms using regular expressions
Optional: Decide if you need a case insensitive search which has a greater searchspace and takes longer
Example:
2. Search the dynamic user-DOM contents
Go to the Tab 'Elements' hit CTRL + F.
Enter your search term (This will also search iframes, svg's etc... within the parent DOM)
3. Recommended:
Cross-reference the results of step 1. and step 2.
If a given string is present in both the DOM and the static sources, then you can assume that the content is not programmatically created on the client-side.
Server:
Many projects perform a media bundling step prior to content-delivery. They pack web-resources into the main file (e.g. index.php) to save HTTP roundtrips.
Use sourcemaps / and or search the entire codebase for a salient static string or a salient keyword near the static string to locate the original source files.
Searching files:
Locally, I generally use the rapid index, and heuristic search of JetBrain's IDE's (IDEA, PHPStorm,...) and Sublime. The grep-command tool can definitely not compete here in terms of performance. On Windows I additionally use Totalcommander and its archive/regex finding abilities.
When quickly looking up code on the server you may use something like:
grep -r -C10 --color=always 'keyword1|keyword2' htdocs/ | less -R
which will also provide you with line-context. two caveats: you may want to filter out binaries first and symlinks outside the scope will be ignored.

Calling a function in a JavaScript file with Selenium IDE

So, I'm running these Selenium IDE tests against a site I'm working on. Everything about the tests themselves is running fine, except I would like to do a bit of clean-up once I'm done. In my MVC3 Razor based site, I have a JavaScript file with a function that gets a JsonResult from a Controller of mine. That Controller handles the database clean-up that Selenium IDE otherwise couldn't handle.
However, I'm having a hard time finding any sort of documentation on how to do this. I know I can do JavaScript{ myJavascriptGoesHere } as one of the Values for a line in the test, but I can't seem to find a way to tell it to go find my clean-up function.
Is it even possible for Selenium IDE to do this sort of thing?
If it comes down to it, I can just make a separate View to handle the clean-up, but I'd really like to avoid that if possible.
Thanks!
If you want to execute your own JavaScript function that exists in your test page from Selenium IDE, you need to make sure you access it via the window object. If you look at the reference for storeEval for instance, it says:
Note that, by default, the snippet will run in the context of the
"selenium" object itself, so this will refer to the Selenium object.
Use window to refer to the window of your application, e.g.
window.document.getElementById('foo')
So if you have your own function e.g. myFunc(). You need to refer to it as window.myFunc().
This can be very handy for exercising client-side validation without actually submitting the form, e.g. if you want to test a variety of invalid and valid form field values.
If you use runScript, that should already run in the window's context.
This works for me.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string title = (string)js.ExecuteScript("myJavascriptGoesHere");
Make sure your javascript works first before using it here!
Actually to access your page javascript space, you need to get the real window of your page : this.browserbot.getUserWindow()
See this statement to get the jQuery entry point in your page (if it has jQuery of course ^^ )
https://stackoverflow.com/a/54887281/2143734

Best way to share JS between browser and node.js when using Google Closure compiler

I'm developing a networked application between the browser and a server running node.js. I'm sharing a lot of code right now, but when I actually deploy this I'd like the client to only get client specific code. My options right now are:
1.) Implement any browser/node.js differences using inheritance. I've tried this in a few places and I end up with a lot of classes that are very, very basic customizations of their parent often only partially specializing a single function. This is not a style I like very much because it means a lot indirection when you're trying to find out what's actually going on.
2.) Define a constant like IS_BROWSER at global scope and then check it whenever I need to change code paths on the browser vs node.js. Then closure compile all js with advanced optimizations to remove dead code on the browser (setting IS_BROWSER = true). Are there any problems with this approach assuming I do whatever I need to do to get advanced optimizations going in closure compiler?
3.) ?? I'm open to suggestions.
If you use advanced compilation, any unused code should be removed; if you use the compiler's export system correctly, any server-side code that your client code does not call will not be in the compiled version of the client code.
You could write all of your code in one big blob then, for your client, add one file with contents like
goog.require('my.client.app');
goog.exportSymbol('my.app.entryPoint', my.client.app.entryPoint);
the compiled code will not include anything that is not in the call tree of my.client.app.entryPoint. Likewise, if your compilation only exports a server entry point, client code will be excluded.
The above style is for writing your script to provide some function which will then get called by an inline script; to make the whole thing into a single script you could do something much simpler:
goog.require('my.client.app');
my.client.app.entryPoint();
To verify that you are not getting a lot of dead code in your compilation output, you could play around with something like this: ScriptCover

How can I manage MSI session state within Javascript Custom Actions?

I have an ISAPI DLL, an add-on to IIS. I build the installer for it using WIX 3.0.
In the installer project, I have a number of custom actions implemented in Javascript. One of them, run at the initiation of the install, stops any IIS websites that are running. Another starts the IIS websites at the end of the install.
This stuff works, the CA's get invoked at the right times and under the right conditions. but the logic is naive. It stops all websites in the beginning (even if they are already stopped) and starts all websites at the end (even if they were previously stopped). This is obviously wrong.
What I'd like to do is keep track in the session of which websites required a stop at the beginning, and then, at the end, only try to restart those websites. Getting the state of a website is easy using the ServerState property on the CIM object. The question I have is, how should I store this information in the MSI session?
It's easy to stuff a single piece of information into a session Property, but what's the best way to store a set of N pieces of information, one for each website? In some cases there can be 1 website, in some cases, 51 websites.
I suppose I could use each distinct website name to create a distinct property name. Just not sure that is the best, most-efficient, most efficacious way to do things. Also, is it legal to use slashes in the name of an MSI Session property? (the website names will have slashes in them)
Suggestions?
You might want to check out:
VBScript (and Jscript) MSI CustomActions suck
C++ or C# is a much better choice. If your application already has dependencies on the framework then adding dependencies in your installer is a good logical choice. WiX has Deployment Tools Foundation ( DTF ) that has a custom action pattern that feels a lot jscript. You could then create a dictionary of websites and their run state and serialize it out to a single property. On the back side you could reconsitute that collection and then act upon it.
Not to mention the debugging story is MUCH better in DTF.
There's a simple solution. I was having a brain cramp.
All of the items I needed to store were strings - actually the names of websites that had been stopped during the installation. I just used the Javascript String.join method to create a single string, and the stuffed that into the session variable. Like this:
Session.Property("CA_STOPPEDSITES") = sitesThatWereStopped.join(",");
Then to retrieve that information later in another custom action, I do
var stoppedSites = Session.Property("CA_STOPPEDSITES");
if (stoppedSites != null) {
var sitesToStart = stoppedSites.split(",");
....
Simple, easy.

Categories

Resources