Copy link to clipboard
Copied
Dear all,
In post Resources for learning framecript Rick says:
6) FrameScript functions are local to each script and not shared in the global FrameMaker session like ExtendScript's functions are. (Yes, I do namespace my ExtendScript scripts to avoid this, but it is not necessary with FrameScript.)
How is namespacing done?
Awaiting some enlightenment ...
Klaus
I will initially write something like this without namespacing:
main ();
function main () {
// This is the main function.
// From here I call other functions.
processDoc (app.ActiveDoc);
}
function processDoc (doc) {
// Call some other function from here.
processTables (doc);
}
function processTables (doc) {
// Do something here.
}
And I use a Python script to convert it to this:
...// Make an object specific to this script.
var CP_ABC = CP_ABC || {};
// Add the functions to
Copy link to clipboard
Copied
I prepend all of my functions with SiD_ (Smart Information Design) so that there is no conflict with scripts from others.
Copy link to clipboard
Copied
I will initially write something like this without namespacing:
main ();
function main () {
// This is the main function.
// From here I call other functions.
processDoc (app.ActiveDoc);
}
function processDoc (doc) {
// Call some other function from here.
processTables (doc);
}
function processTables (doc) {
// Do something here.
}
And I use a Python script to convert it to this:
// Make an object specific to this script.
var CP_ABC = CP_ABC || {};
// Add the functions to the object.
CP_ABC.main = function () {
// This is the CP_ABC.main function.
// From here I call other functions.
CP_ABC.processDoc (app.ActiveDoc);
};
CP_ABC.processDoc = function (doc) {
// Call some other function from here.
CP_ABC.processTables (doc);
};
CP_ABC.processTables = function (doc) {
// Do something here.
};
// Call the functions using the object "namespace".
CP_ABC.main ();
I got this idea out of this book:
Rick
Copy link to clipboard
Copied
So the object itself is global--in this example, CP_ABC--but all of its functions are "hidden" inside of the object. This is important for me because I may have a dozen scripts with a processDoc function and when the scripts are installed, there can only be one processDoc function in the global space. Namespacing through objects solves the problem.
A nice side effect is that you can use this object to store "global" variables, which you normally want to avoid. For example, I will sometimes do this:
// Make a global object for this script.
var CP_ABC = CP_ABC || {};
// Set a version value for this script.
CP_ABC.version = "1.0.1, June 9, 2018";
// Set a constant for points units.
CP_ABC.PT = 65536;
...
CP_ABC.makeAFrame = function (page, doc) {
...
// Set the anchored frame width to 2 inches (144 points).
aframe.Width = 144 * CP_ABC.PT;
...
};
Line 6 is convenient because there may be multiple places in the script where I want to use the PT value for setting offsets and dimensions. It is easy for me to remember the current global object name plus dot PT.
Line 4 is convenient because, while I may only use the version value in one place in the script, it is easier to change the value up at the top of a large script instead of hunting for it when it needs to be changed.
Copy link to clipboard
Copied
Rick, Thank you very much for this extensive explanation.
BRW: I own the mentioned book as e-book - but did not study it yet to that level...
Klaus
Copy link to clipboard
Copied
Hello fans,
Why do I get an error in this line: Semicolon expected (where the period is):
I get the same error if changing line 15 to
var ETB_test = {} ;
I have no clue about this.
Klaus
Copy link to clipboard
Copied
You have already declared the variable with the var keyword on line 15. Leave off the var keyword on line 17 and it should prevent the error.
Copy link to clipboard
Copied
Thanks, Rick - yes this was the error - a hyper-declaration...
Copy link to clipboard
Copied
I've been silently following this thread and I fully support the concepts defined by Rick. The first time I ever wrote an ExtendScript application was the S1000D support hat was built into FrameMaker. It's a reasonably large application with some complex scriptUI dialogs. I was unaware of the visible footprint I was leaving in the global FrameMaker session space. Towards the end of that development I read the excellent book "JavaScript: The Good Parts" by Douglas Crockford. (https://www.amazon.co.uk/JavaScript-Good-Parts-ebook/dp/B0026OR2ZY ) It showed me what I had done wrong and how to fix it. It was too late at that stage to retrofit these improvements into the S1000D application, so many of its functions and objects remain exposed. I offered to fix it for Adobe, but it wasn't seen as a priority.
You may ask does it matter? I would argue strongly that it certainly does. It's never a good idea to have global variables and objects open to accidental or even malicious abuse. I even managed to accidentally name a variable the same as one of the S1000D variables and had the most confusing time trying to debug it all .
I have to disagree with Jang that a simple prefix is adequate. It can prevent errors, but sill leaves a whole heap of detritus in the global space. Let's all be good ExtendScript citizens and keep FrameMaker tidy!
Copy link to clipboard
Copied
Hi Ian, Thanks for your honesty and humility in admitting your mistake. I sent out dozens of client scripts without the namespacing technique before I discovered problems, so you are not alone. I also strongly recommend Crockford's book as it really increased my understanding of JavaScript. Thanks for your feedback! -Rick
Copy link to clipboard
Copied
I used to wrap all my code into a single top-level function that used my prefix (the top-level function has to be exposed in the global space if you want to tie it to a menu command), but as my modular script systems (which implemented a full CCMS at times) tended to become huge and very hard to maintain as singular deliveries, I switched to packing the commonly used functions into a module that creates my Smart Tools menu and adds the generic command handlers. Those handlers call functions which nobody in their right mind would call exactly the same (with the SiD_ prefix). All of the functions in the common module have the same prefix. This basically means that my modular systems are easier to maintain, carry smaller footprints and can be exchanged (when bugs are fixed) without having to reinstall the whole code base. I do not see 1) how that caused debris and problems and 2) how I would be able to do this in a different manner. It is almost like a set of DLLs - you cannot install another DLL with exactly the same name, either. But they do make a lot of sense in keeping down the digital footprint of progams as well as the maintenance burden.
Copy link to clipboard
Copied
Hi Jang, I would have to see exactly how you do it to see if it would work for me. I have a lot of clients as well as my own scripts so I find that the method I use works well. I may have several functions with the same name across multiple scripts, but they may have slightly different functionality. In addition, my object names help me identify the client and script. For example, if I search on my script set and find a function called prefixed with CP_TC, then I know it is mine (CP = Carmen Publishing) and it is in the TableCleaner script. -Rick
Copy link to clipboard
Copied
I find namespacing a bit unnecessary for most scripts. I just wrap each script in an anonymous function which is immediately called.
(function () {
// your script here
})();
This keeps everything declared in your script within the scope of this function, but without the need for any prefixes.