Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this Javascript code do?

I've been looking at Sharepoint script files and I've come across this bit that I don't get:

function ULSTYE() {
    var o = new Object;
    o.ULSTeamName = "Microsoft SharePoint Foundation";
    o.ULSFileName = "SP.UI.Dialog.debug.js";

    return o;
}

SP.UI.$create_DialogOptions = function() {
    ULSTYE:;   <----------------------------- WTF?
    return new SP.UI.DialogOptions();
}

Actually every function definition in this file starts with the same ULSTYE:; line right after the opening brace. Can anybody explain what does the first line in the second function do?

Firefox/Firebug for instance interprets this function as something that I can't understand either:

function () {
    ULSTYE: {
    }
    return new (SP.UI.DialogOptions);
}

And I thought I knew Javascript through and through... ;) Must be some obscure feature I never used in the past and is obviously seldomly used by others as well.

like image 818
Robert Koritnik Avatar asked Nov 14 '10 09:11

Robert Koritnik


2 Answers

After wondering about this for a long time, I finally sat down and worked it out. It's all part of a relatively sophisticated mechanism for collecting diagnostic information on the client which includes the ability to send a javascript callstack (including function name, and javascript file) back to the server.

Take a look at the first 250 lines of the file init.debug.js which is located at

%Program Files%\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\1033\init.debug.js

This file defines all the functions the 'ULS' implementation on the client.

Of course, you'll need to have SharePoint 2010 installed for the file to exist on your local machine.

UPDATE -- The following is an overview of roughly how the mechanism works. The real implementation does more than this

Consider the following html page with a few js includes, each of which can call out into each other.

<html>
 <head>
   <script type="text/javascript" src="ErrorHandling.js"></script>
   <script type="text/javascript" src="File1.js"></script>
   <script type="text/javascript" src="File2.js"></script>
 </head>
 <body>
   <button onclick="DoStuff()">Do stuff</button>
 </body>
</html>

We have two js include files, File1.js

    function ULSabc() { var o = new Object; o.File = "File1.js"; return o; }
    /* ULSabc is the unique label for this js file. Each function in 
    this file can be decorated with a label corresponding with the same name */

    function DoStuff() {
        ULSabc: ;
        //label matches name of function above
        DoMoreStuff();
    }

and File2.js

    function ULSdef() { var o = new Object; o.File = "File2.js"; return o; }

    function DoMoreStuff() {
        ULSdef: ;
        DoEvenMoreStuff();
    }

    function DoEvenMoreStuff() {
        ULSdef: ;
        try {
            //throw an error
            throw "Testing";
        } catch (e) {
            //handle the error by displaying the callstack
            DisplayCallStack(e);
        }
    }

Now, say our ErrorHandling file looks like this

    function GetFunctionInfo(fn) {
        var info = "";
        if (fn) {
            //if we have a function, convert it to a string
            var fnTxt = fn.toString();

            //find the name of the function by removing the 'function' and ()
            var fnName = fnTxt.substring(0, fnTxt.indexOf("(")).substring(8);
            info += "Function: " + fnName;

            //next use a regular expression to find a match for 'ULS???:' 
            //which is the label within the function
            var match = fnTxt.match(/ULS[^\s;]*:/);
            if (match) {
                var ULSLabel = match[0];

                //if our function definition contains a label, strip off the 
                // : and add () to make it into a function we can call eval on
                ULSLabel = ULSLabel.substring(0, ULSLabel.length - 1) + "()";

                //eval our function that is defined at the top of our js file
                var fileInfo = eval(ULSLabel);
                if (fileInfo && fileInfo.File) {
                 //add the .File property of the returned object to the info
                    info += " => Script file: " + fileInfo.File;
                }
            }
        }
        return info;
    }

    function DisplayCallStack(e) {
        //first get a reference to the function that call this
        var caller = DisplayCallStack.caller;
        var stack = "Error! " + e + "\r\n";

        //recursively loop through the caller of each function,
        //collecting the function name and script file as we go
        while (caller) {
            stack += GetFunctionInfo(caller) + "\r\n";
            caller = caller.caller;
        }

        //alert the callstack, but we could alternately do something 
        //else like send the info to the server via XmlHttp.
        alert(stack);
    }

When we click the button on the page, our script file will call through each of the functions and end at DisplayCallStack, at which point it will recursively loop through and collect the stack trace

    Error! Testing
    Function: DoEvenMoreStuff => Script file: File2.js
    Function: DoMoreStuff     => Script file: File2.js
    Function: DoStuff         => Script file: File1.js
    Function: onclick
like image 160
Paul Lucas Avatar answered Oct 11 '22 14:10

Paul Lucas


The first bit defines a function that creates an object with a couple of properties and returns it. I think we're all clear on that bit. :-)

The second bit, though, is not using that function. It's defining a label with the same name. Although it uses the same sequence of characters, it is not a reference to the function above. Firefox's interpretation makes as much sense as anything else, because a label should be followed by something to which it can refer.

For more about labelled statements, see Section 12.12 of the spec.


Off-topic: I would avoid using code from this source. Whoever wrote it is apparently fairly new to JavaScript and doesn't show much sign that they know what they're doing. For instance, they've left the () off the new Object() call, and while that's allowed, it's fairly dodgy thing to do. They could argue that they were doing it to save space, but if they were, they'd be better off using an object literal:

function ULSTYE() {
    return {
        ULSTeamName: "Microsoft SharePoint Foundation",
        ULSFileName: "SP.UI.Dialog.debug.js"
    };
}

There's never much reason to write new Object() at all; {} is functionally identical.

And, of course, there's no justification for the second bit at all. :-)

like image 45
T.J. Crowder Avatar answered Oct 11 '22 13:10

T.J. Crowder