“Please wait while scripts are loaded…”

Hello again,

Some of Sharepoint developers might be familiar with this kind of message. It appears in the status bar of Internet Explorer when some action is executed. If the message disappears, fine, but what if it remains there and the desired behavior isn’t executed?

There are a couple of blog entries over the net that describe possible reasons for this issue. What actually causes this behavior are either errors in a masterpage (wrong or missing ID’s of elements that are later referenced), or defective javascript. Well, to be clearer, defective javascript from Internet Explorer’s point of view. And it may take w while to debug and find out at which point the javascript is failing.

I was getting this “Please wait while scripts are loaded” message on a web part page with one particular web part, which had some custom verbs defined. Web part verbs are kind of menu items for a web part, that allow to perform some actions on it. For each verb, one can define server-side and client side action to be performed when the verb / menu item is clicked. And this client side code of the verb was the crux of the matter.

The idea was simple: to open a window via javascript. For the window.open() method two arguments were used, the URL and the name of the new window. The client side code was generated dynamically and the window’s name was put up together, amongst others, from personalizable properties of the web part. Everything worked fine until the property used as part of window’s name contained a hyphen (-). Then, after clicking on web part menu, the message described above appeared, and nothing happened, new window hasn’t been opened.

I replaced the string with an underscore and the problem was solved. At this time I thought that maybe the names or ID’s in aren’t allowed to contain characters like hyphen. But no, according to W3C, hyphens are allowed since they’re not the first character of ID or name. Probably Internet Explorer tries to evaluate the expression, treating the hyphen as a minus sign. And reaches a deadlock at some point (please wait while scripts are loaded…)

Hope this helps,
Lukasz

Grouping nodes by date in XSL

Hello,

a while ago I stumbled upon a task to display a list of entries (let’s call them events) grouped by date. The requirement was to transform the data which I got from a web service via XSL. The source data was not grouped in any way, each node had its own sub-element with the date information (let’s call the field EventDate). So the desired output had ought to look like this:

  • 15.03.2009
    • Event A
    • Event B
  • 21.03.2009
    • Event C
    • Event D

…and so forth. There is a technique in XSL which allowed me to achieve the goal. First of all, we have to define a key for the style sheet, which will include the dates, by which we want to group our data:

<xsl:key name="dateGroup" match="Event"
                          use="substring-before(EventDate,'T')"/>

So, we name the key dateGroup, it has to match nodes of type Event, and its value should be set to a part of the EventDate value (the substring-before function). Since our date format looks like that:

2009-03-15T15:30:00

, and we don’t want to take exact time into consideration (only the date), we shall use the sub-string of the value. So far, so good. Note that the key declaration is a top-level element in XSL.

In the next step, we shall select only the nodes with unique dates:

<xsl:template match="/ArrayOfEvent">
  <xsl:for-each select="Event[generate-id(.)=generate-id(
    key('dateGroup',substring-before(EventDate,'T')))]">
    <ul>
      <li>
        <xsl:value-of select="substring-before(EventDate,'T')" />
      </li>
    </ul>
  </xsl:for-each>
</xsl:template>

A couple of words of explanation: two additional XSL functions have been used here. The key() function uses the key defined before in order to find a node (an event in this case) with a given date. The generate-id() function creates and returns an unique identifier for a node. The dot (.) represents a current item in the for-each loop. Hence, the loop goes only over those Event-nodes, for which the equation is true, therefore for those which have an unique date.

OK, but that’s the first part. We already got first level of our desired list – the dates. Still we have to get a list of events for each of those unique dates. And again, the key() function comes to rescue. Within the previous loop, for example after displaying the date as in the previous snippet, we use another for-each loop and go over the nodes/events which have in fact the date:

<ul>
  <xsl:for-each select="key('dateGroup',substring-before(EventDate,'T'))">
    <li>
      <xsl:value-of select="Title" />
    </li>
  </xsl:for-each>
</ul>

Assuming that our event nodes have an element called Title, we display here its value. The function used here selects only the events which have the date equal to the date in the first level’s loop current iteration. The final code could look like this:

<xsl:template match="/ArrayOfEvent">
  <xsl:for-each select="Event[generate-id(.)=generate-id(
    key('dateGroup',substring-before(EventDate,'T')))]">
    <ul>
      <li>
        <xsl:value-of select="substring-before(EventDate,'T')" />
        <ul>
          <xsl:for-each select="key('dateGroup',
             substring-before(EventDate,'T'))">
            <li>
              <xsl:value-of select="Title" />
            </li>
          </xsl:for-each>
        </ul>
      </li>
    </ul>
  </xsl:for-each>
</xsl:template>

Hope this helps. Happy XSLTransforming!

Single element array initialization with an integer value (javascript)

When initializing a javascript array (with a known number of its elements), one does normally write a simple line of code:

var myArray = new Array("string1", "string2", 123);

This works fine when we have more than one element of the array. However, when we want to declare an array with one element, and the element is of an integer type, we could encounter an odd behavior. The reason behind is that a following command:

var mySecondArray = new Array(12);

…initializes an array with twelve elements, which aren’t filled at this time. And not, as expected, a single-element one. So, in order to declare a single-element array with an integer value, let’s consider a following “workaround”:

var myThirdArray = new Array(1);
myThirdArray[0] = 12;

Declaring an array with a length of 1 element, then assigning the value of the element by finding it by its index should solve the problem.

Best regards,

lukasz

Maintain selected tab position upon postback (jQuery UI Tabs)

Hello,

jQuery UI is a very nice add-on to the standard jQuery library. It provides us with out-of-the-box interactions and client side effects for a rich web application experience. One of the interesting effects are the jQuery tabs. They’re used to split the content into sections and be able to switch between them without having a postback, and also to spare some space within our web page.

The interaction is purely on the client side, so after reloading the page the tab which we selected as last isn’t maintained. What if we have, for example, a file upload control within one of our tab sections? After uploading a file (postback), we lose the focus on the tab in which we were previously.

But the developers of jQuery UI provide us with a couple of methods and events, which we can use to do some kind of workaround for this issue.

We need to have a document element which could store the selected tab index. We can use an input hidden field, value of which would be posted together with other data during page postback. So, let’s put it into our page, setting it’s value declaratively to 0 (the index of the first tab – default selection):

<input type="hidden" value="0" id="theHiddenTabIndex" />

Having the ID of the element, we can set its value from the client side script. Using the show event of the jQuery Tabs (fired when the tab is changed), we can do this at runtime:

$('#tabElmtId').tabs( {
  show: function() {
    var newIdx = $('#tabElmtId').tabs('option','selected');
    $('#theHiddenTabIndex').val(newIdx);
  }
 });

As you can see, when the event is triggered, the currently selected index of our tabs is being stored in a variable (line 3), then assigned as a value of the hidden input field. Now the postback can be performed but the next question is how to tell the tabs control to start from another tab index than the default 0.

First, on the server side, we can use the language which we prefer in order to fetch the value of the submitted hidden input field. For example, in ASP.net, it could look like this:

String hiddenFieldValue = Request.Form["theHiddenTabIndex"] ?? "0";

Now we can put javascript into our page’s source in order to tell have this variable also available for client side scripts:

   1: StringBuilder js = new StringBuilder();
   2: js.Append("<script type='text/javascript'>");
   3: js.Append("var previouslySelectedTab = ");
   4: js.Append(hiddenFieldValue);
   5: js.Append(";</script>");
   6: this.Header.Controls.Add(new LiteralControl(js.ToString()));

The one thing important about this is that it should be injected before the jQuery Tabs are initialised. Now the remaining task is to tell jQuery to use the javascript variable in order to set the selected tab upon loading the controls after postback. We can use the selected option of jQuery UI Tabs in order to assign this value:

   1: $('#tabElmtId').tabs( {
   2:     show: function() {
   3:         var newIdx = $('#tabElmtId').tabs('option','selected');
   4:         $('#theHiddenTabIndex').val(newIdx);
   5:     },
   6:     selected: previouslySelectedTab
   7: });

The only thing that changed from the previous Tabs initialisation is the line 6, where we assign the javascript variable to the selected option.
Now the tabs position should be postback-proof.

Happy jQuerying!

Use command prompt to control remote desktop connections on Windows Server

Hello,

while working on Sharepoint applications running on Windows Server machines, we often need to connect to the server via Remote Desktop (e.g. in order to perform debugging). Those who work this way often are probably familiar with the standard limitations of Windows Server systems: only two concurrent remote desktop connections at a time. If you’re working alone, this shouldn’t be a problem, however, in teams, it may sometimes happen that you’re denied logging in onto the system with the warning:

„The terminal server has exceeded the maximum number of allowed connections.”

This may happen not only when your work mates are busy doing their job, but sometimes also you are the one who is occupying one or two sessions, without actually being working on the server. Such situations occur, for example, if your local remote desktop connection window doesn’t get closed properly, or due to instable local operating system.

What then? We are not physically on the server and we cannot log on. If you are one of the “blocked” server’s administrators, the command prompt comes to rescue.

First of all, we can check who is logged on on the server. To do this, first we have to perform authentication in order for the server to allow us actually do this. The simple solution is to map a share on the server: either via accessing the share in Windows Explorer ( \servernameshare ) and entering your username and password, or, the same but using command line:

net use /user:MyUsername \servernameshare

After successful authentication, we can now check who is actually logged on with the query session command:

query session /server:MyServerName

The server name can be replaced by the IP address of the machine. The output of this command could look like this:

command_terminal

Seeing such list, we now know who is logged on, so we can contact the proper person. But what if we ourselves are the ones who occupy the sessions? Then we can disconnect the sessions remotely, too. Having noted the ID of the session which we received via previous method, we can use it in the reset session command:

reset session 1 /server:MyServerName

Now the session is free and we can log on to the machine again.

“Could not find default endpoint element that references contract”

Hello,

recently, while developing a web application which uses quite a lot of ASP.Net web services, I ran across a following problem.

The application uses also a few C# class libraries, and I wanted one of those libraries to retrieve some data from a web service (let’s call it service A). So, within the class library, I added web reference to the desired web service, downloaded all needed definitions and wrote a method in order to check whether the connection to the web service was working. I also checked whether the app.config file of the class library has been modified. Positive – the Service Model section has been added, the binding has been configured. So far, so good. I compiled the assembly, and wanted to use it in another web service (service B), which serves some specific information to the presentation layer of my web application.

However, the instantiation of the SOAP client method threw the following exception:

Could not find default endpoint element that references contract ‘Client.ClientSoap’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

The reason for the exception was quite simple: the web service B (which invoked the class library method that retrieved the data from service A), hasn’t been configured for usage of web service A. In other words, the Service Model section in the web.config file was missing.

Solution? Put the Service Model section generated in the app.config of the class library (as mentioned earlier) into the web.config file of the web service project.

Happy programming!