I'm struggling to call this unusually structured Javascript function from XUL - javascript

(function(aLeftPane) { ... }) ("History").
The complete function is here: pastebin.com
I haven't been able to get my head round how the contents of the seconds set of brackets gets passed into the functions in the first set.
I want to make the hard-coded "History" into a variable. I've tried wrapping the whole thing in a more regular function, but I haven't been able to pass parameters to it successfully.
The XUL that calls the function currently looks like this: oncommand="madeUpWrapperName('history');"

(function(aLeftPane) { ... }) ("History")
Is not an unusually structured function, it's a common pattern to encapsulate code in JS. What it does is declare an anonymous function and then immediately call it. It is used very often by libraries to create the lib entry point and cleanly separate private from public code without polluting the global namespace.
In your case, you actually want to unwrap the function :
function unwrapped(aLeftPane)
{
/**
* Select left panel in Library.
*
* #param aBrowser Browser object in selected tab.
...
}
then, in your xul or somewhere else:
oncommand="unwrapped('History');"

Related

Getting "All SuiteScript API Modules are unavailable while executing your define callback" When Creating NetSuite Script With Custom Module

When trying to create a new script record within NetSuite, I get the error "Fail to evaluate script: All SuiteScript API Modules are unavailable while executing your define callback". I can't find any real information on what may cause this, and I can't see anything in my custom module that looks suspicious. I can't post the code here as the module is nearly 2,000 lines in length and has some proprietary code in it. As it was with another custom module I built that had issues at the "Upload Script File" stage, if I remove reference to the module in the script the process continues, and then I can go back to the script and return the module reference, wherein everything seems to work correctly afterward.
The only information I found that seemed useful was that the error could be caused by referencing a module outside of the define callback, but that isn't the case. The module has two large objects constructed within, and they're returned from the callback. The only other thing I can think of is that this module calls the other custom module, but I haven't seen anything that says I can't do that.
So, overall, what should I look for to resolve this error? I really cn't seem to find anything useful or that applies to this situation.
EDIT
Ok, so I believe that I discovered the cause is due to the calling of a search function outside of an object/function being returned for the callback. Here's a simplified version of what's happening, since a lot of fields and values are managed:
/**
* custom.module.js
* #NApiVersion 2.x
* #NModuleScope Public
*/
define(['N/search'],
/**
* #param {search} search
*/
function(search) {
var fields = new Array("a","b","c","d","e");
var lValues = search.lookupFields({
type : "customrecord_ng_cs_settings"
, id : "1"
, columns : fields
});
var _values = {
a : lValues.a
, b : lValues.b
, c : lValues.c
, d : lValues.d
, e : lValues.e
};
var _funcs = {
func_a : function() {
// do stuff
}
, func_b : function() {
// do stuff
}
, func_c : function() {
// do stuff
}
};
return {
value : _values
, func : _funcs
};
});
I need to maintain this kind of structure as not everything that gets returned in _values is actually a search/lookup result. Am I going to be forced to encapsulate the construction of this object within a function? And would that cause the lookup to occur every time a value is needed? This is a conversion from a 1.0 script, and this gets loaded and set only once at the beginning so the data is all there the entire time without having to be repeatedly fetched.
So, I see the following options:
Convert the callback output to a function and doing something like
the following at the start of every script:
var _values = customModule.values();
Find some way to rework the code so that any script using the module
can still access values in the following way:
var _a = customModule.values.a;
I'd very much prefer option #2. Is it possible?
You cannot run any SuiteScript module code outside of an entry point. You will need to encapsulate your data retrieval in a function, then invoke that function at the beginning of your entry point.
If you want to avoid multiple fetches, you can leverage memoization in your function, or perhaps N/cache or N/session to store the data.

Overriding core JS commands?

I'm trying to modify/limit/prevent access to certain JS commands of my browser. For example commands like navigator.clipboard; However, I'm not sure how to approach this.
Is it possible to override these commands with user-defined javascript injected in the page, or do i have to edit the browser's javascript compiler and re-compile it from source for this?
I'm not really familiar with browsers and want to save time by knowing a general direction to follow. Thanks
First of all navigator.clipboard is not a function, but here is an example using the read function of navigator.clipboard:
navigator.clipboard.read = function (originalFunction) {
return function (yourParamsYouWantForThisFunction) {
// Do Stuff you wanna do before the real call. For example:
console.log(yourParamsYouWantForThisFunction);
// Call the original function
return originalFunction.call();
};
}(navigator.clipboard.read); // Pass the original function reference as a parameter
You may wonder, why there are two function statements:
The first one is there, so that we can pass the original function at runtime. If we would not do that, we would not be able to access the original navigator.clipboard.read function.
The second function is the actual function, that you will be using later, when you call navigator.clipboard.read().

What is this window["obvInit"] ({...}) doing in a script?

I'm attempting to extract some information from Medium URLs and I notice that each page has the entire post contents stored in JSON format. The content looks like this on the page:
<script>// <![CDATA[
window["obvInit"]({"value":{"id":"e389ba1d8f57","versionId":"1b74...
How do I easily extract this JSON from the page? What does the preface of window["obvInit"] before the JSON mean? Can I call the function obvInit in my Chrome console and get the JSON output somehow?
What this does is call a function. It's probably (but not necesarrily) been declared like function obvInit(...){...} on the global window namespace. Now for your problem: You can easily extract the passed object by overwriting the function like this:
var _oldObvInit = window.obvInit;
window.obvInit = function(){
console.log(arguments[0]); //use this to extract the object
console.log(JSON.stringify(arguments[0])); //use this to extract JSON
return _oldObvInit.apply(window, arguments);
}
Put this before the script tag you've posted here and after the declaration of the function obvInit.
A bit context: inside every javascript function there's an implicit variable arguments which stores the arguments to the function as an array. And apply calls a function, sets the context (this) and takes the arguments as an array. Exactly what you need to wrap it.
This is a technique known as JSONP. Basically, since some older browsers don't have great support for cross-origin AJAX using XMLHttpRequest, you can insert a <script> tag into the page that gets the resource you want, except wrapped like this:
functionName({ /* ...data... */ });
So it calls a function known as functionName with the data as an argument. You would provide this function in your own code before inserting that script, like so:
function functionName(data) {
// use the data
}
window["obvInit"]() is equivalent to window.obvInit() which is equivalent to calling a function defined as obvInit at the global level.
As scripts are not subject to the same-origin policy, you can now get JSON-like data from any domain that will return it in this format.

extend a javascript option to add functionality

I need to call "MyOtherFunction" when "MyFunction"(which creates an element) completes, without MyFunction knowing what MyOtherFunction is.
The reason I need this is for extension of a jquery powered fileupload User Control that is used in several places with different functionality. A specific page shows a header and file count for it, and when the upload completes, I need to modify the file count according to how many files are displayed(by created elements) I thought :
$(UserControl).on(MyFunction, UploadElem, MyOtherFunction);
but this route is not accomplishing anything. The most I can alter the User Control is add in a function call, but without effecting the original user control functionality.
I'm not sure if because MyFunction isn't an event and doesn't bubble up or if it just isn't possible to use a defined function as a parameter of .on() is the reason I cannot get this code to work. Any suggestions?
Easiest way I can think of, is duck punching respectively hooking that method:
var _oldMyFunction = MyFunction;
MyFunction = function() {
_oldMyFunction.apply( this, arguments );
MyOtherFunction();
};
I managed to solve my own issue, but the context is important for the answer:
// Using a Global JavaScript object I created:
GlobalNameSpace.ExtensionFunction = function(oParam1, oParam2, oParam3)
{
/// <summary>All parameters are optional</summary>
return; // For instances when it is not being overwritten, simply return
}
//In the Code for the user control:
GlobalNameSpace.UploadControl.UploadComplete(oSender, oArgs)
{
///<summary>Handles the Upload process</summary>
// process the upload
GlobalNameSpace.ExtensionFunction(oSender, oArgs);
}
//and finally in the code to extend the functionality
GlobalNameSpace.Page.Init
{
///<summary>Initializes the page</summary>
// redefine the extension function
GlobalNameSpace.ExtensionFunction = function(oSender, oArgs)
{
GlobalNameSpace.Page.Function(oSender, oArgs);
}
}
This allows me to extend anything I need it to without polluting my objects, and having something generic already existing to call on to make my changes. This solution solves my problem of needing a onCreate function for the elements I create to represent my uploaded items to trigger the header displaying the number of files. Very useful

send data to JS file without using global variables

I need to send data in a HTML page to a script file that is loaded in that page. The simplest way i can think of is to use a global variable which is defined in the page and accessed in the script file.
We all know global state is bad, so i started thinking about the options available for passing data from HTML page to script file without using global state. I cant find (or think of) any.
I am curious whether this is possible. Any ideas?
It really depends what you're doing. In general, I wouldn't advise this methodology, but it's something to consider depending on your circumstances. For the sake of this example, I'll assume you're using jQuery (if not, replace the document.ready with whatever you want to use for onDOMReadyStateChange monitoring).
In the HTML:
<script type='text/json-data' id='some_data_set'>
{ 'foo': 'bar', 'baz': 1 }
</script>
In the JavaScript:
$(function() {
var myData = JSON.parse($('script#some_data_set').html());
// YOUR CODE GOES HERE
});
Nope. All the javascript scope starts from a global level, therefore you must have at least one global reference to your data.
Let's say you wanted to store a list of products and events:
var myGlobalData = { "products":<products>, "events":<events> };
Where <products> and <events> are two different data blocks.
If you're paranoid on global objects, you can simply delete the reference point (thus it's contents) after you finished using it, as follows:
delete window.myGlobalData;
One option is to scope your data. For example, in JS file you can define an object like:
var processor = {
function setData(o) { // do stuff
}
};
Then in your HTML you know that the data is scoped to the processor. So you can do something like:
processor.setData({someData});

Categories