17

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.

Paul Lucas
  • 1,302
  • 1
  • 12
  • 18
Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404

4 Answers4

21

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
Paul Lucas
  • 1,302
  • 1
  • 12
  • 18
  • 1
    Perhaps you could explain *why* a completely useless label is necessary for this "sophisticated" mechanism, and *how* it's used. It's not helpful to refer to a file a relatively small number of people will have and say "read this." – T.J. Crowder Sep 26 '11 at 10:38
  • Sure... I'm not going to post the js code from Microsoft but I'm adding a simplified example showing the basis for how it works. – Paul Lucas Sep 27 '11 at 07:33
  • 1
    So you're saying that it relies on using `toString` on functions (which has never been standardized and doesn't work on some mobile browsers), and it relies on that string representation of the function not having had the useless label removed by optimization. Interesting, I think I would have gone another way. Still, though, good answer, +1. – T.J. Crowder Sep 27 '11 at 08:28
  • 1
    Thanks. Just a final note though, the actual implementation will do the best it can to collect whatever information the browser can give it and will degrade gracefully if necessary. Remember that this is SharePoint code and as such works best with Internet Explorer. – Paul Lucas Sep 27 '11 at 10:53
14

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. :-)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 6
    Wouldn't be a Microsoft developer, would it? :) – Marko Nov 14 '10 at 10:09
  • 1
    *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.* -> Tell this to Microsoft! The funny bit is that this script has been written by **Microsoft stuff** and is part of Sharepoint Foundation 2010. :) It's the first bit of `SP.UI.Dialog.Debug.js` file... I don't think they're inexperienced. ;) – Robert Koritnik Nov 14 '10 at 10:09
  • 5
    @Robert: Microsoft as a whole may not be inexperienced, but don't think they don't have inexperienced devs and that some of that may not seep through sometimes. The code quoted above was either written by someone who doesn't know what they're doing, created by an auto-generator gone slightly mad (perhaps fed invalid input), or (of course!) is a construct with which I'm unfamiliar. I know a lot about JavaScript, but I don't know everything about it. :-) For example, a line at the top of a function with nothing but `"use strict";` looks non-sensical if you don't know about strict mode. – T.J. Crowder Nov 14 '10 at 10:12
  • Spec doesn't imply any naming conventions. What's the scope of a label definition? A function? A script file? Because as I've said: every function has this same label at the beginning. – Robert Koritnik Nov 14 '10 at 10:19
  • 1
    And you are correct. This is plain stupid. Because no code ever refers to any of these labels. Some inexperienced developer has obviously copied some other guy's function definition he didn't understand himself. I suppose. It's just plain stupid. – Robert Koritnik Nov 14 '10 at 10:21
  • 1
    @Robert: That's a good question about label scope. It is covered in Section 12.12, but the language is so stodgy it's hard to tell what it's saying. Basically, labels are scoped to the statement they label and that statement's contents. Every statement starts with an empty label set, to which a label is added if it labels the statement. Since you can nest statements (a `switch` within a `for`), you can end up with more than one label in the set, but once you're out of the statement the label labels, the label no longer exists. Ex: http://jsbin.com/emavi4 The 2nd loop can't see the 1st's label. – T.J. Crowder Nov 14 '10 at 10:44
  • Actually, this kind of "quality" is apparent in most SharePoint-related JavaScript code that originates under the Microsoft brand. If you think this is bad, check out the code for IMNRC Presence :-/ Makes me wonder about all the *non*-JS code I can't see... Also, if you call new `SP.UI.$create_DialogOptions()` "too quick" after a page-load it isn't defined. Fail. –  Jan 14 '11 at 08:18
  • @TJ: re the downvote. See my answer below. There's a good reason for this javascript. It is SharePoint specific though. – Paul Lucas Sep 26 '11 at 03:08
  • 1
    @pst: You need to wait until sp.dialog.js is loaded before making any calls to SP.UI.$createDialogOptions(). Most of the SharePoint javascript is loaded 'on demand' to improve page loading performance. While it is a great idea, you also need to understand the framework in order to be able make calls to the framework functions. – Paul Lucas Sep 26 '11 at 03:19
  • Re: "There's never much reason to write new Object() at all; {} is functionally identical.", {} is not only functionally identical, but significantly faster in every browser. – BrianFreud Jan 26 '12 at 11:29
  • @BrianFreud: *And* not susceptible to someone replacing `Object` with something else. :-) – T.J. Crowder Jan 26 '12 at 11:38
4

Isn't it just a statement label? The fact the label has the same name as the earlier function doesn't mean anything, I think.

AakashM
  • 62,551
  • 17
  • 151
  • 186
0

it looks, like it creates an empty object which should be filled with some data, but due to code generator that creates this code it is not deleted so it sits there empty

fazo
  • 1,807
  • 12
  • 15
  • Creating an object implies usage of assignment operator (=) which is not present there (colon is). There's also a missing semicolon at the end of that *whatever-it-is*... – Robert Koritnik Nov 14 '10 at 10:02