Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Office365 Weather WebPart

A while ago I wrote a Sharepoint web part that displayed a 5 day weather forecast for a user configurable location using Met Office data from the Azure Datamarket. I wanted to try porting this web part to Office365, to see if I could overcome the challenges of working predominantly client side using Javascript.

With the help of jQuery to make ajax requests to the Datamarket and a cryptographic library to encrypt the username and password that is included in the ajax request headers I've managed to accomplish this goal.

One of the major challenges was to overcome the cross site scripting issues, where I was making requests to the Datamarket from the Office365 domain. The Datamarket supports the oData standard well from a .Net Framework perspective, but it requires user interaction to allow the request from a purely web client or javascript approach. Internet Explorer has an object called a XDomainRequest which is specifically designed for cross site data requests, the only problem is that you can't include any headers, which means that authentication was ruled out. Aparently IE 10 will work the same way that Chrome does now and properly support jQuery CORS. So, I had to compromise and change internet explorer's security settings to allow cross site data requests.

I've just published the code in a CodePlex project here: http://o365Weather.codeplex.com

Using jQuery & Windows Azure Marketplace

I'm trying to create an Office365 webpart that displays a 5 day weather forecast. The sandbox restrictions mean that I can't call the data service from the server side code, so I need to make the call client side.

Marketplace data is accessible as JSON, so using jQuery and a cryptography library called crypto.js to handle the authentication I should be able to return some data.

Here is a simple htm page that demonstrates a working call to the Azure Marketplace, the username can be anything but the password should be your Primary Account Key from the data subscription.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Windows Azure Data Market</title>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script> 
    <script type="text/javascript" src="http://crypto-js.googlecode.com/files/2.5.3-crypto-min.js"></script>   
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            var user = "{username}";
            var pwd = "{primary account key}";
            $.support.cors = true;
            $.ajax({
                type: "GET",
                beforeSend: function (xhr) {
                    var bytes = Crypto.charenc.Binary.stringToBytes(user + ":" + pwd);
                    var base64 = Crypto.util.bytesToBase64(bytes);
                    xhr.setRequestHeader("Authorization", "Basic " + base64);
                },
                url: "https://api.datamarket.azure.com/DataGovUK/MetOfficeWeatherOpenData/Site?$top=100&$format=json",
                dataType: "json",               
                success: function (data) {
                    alert('success!');
                },
                error: function (jqXHR, textStatus, errorThrown) {                    
                    alert(errorThrown.message);
                }
            });
        })
    </script>
</head>
<body>

</body>
</html>

Add jQuery to Office365 Solutions

Becuase of the restrictions on Sharepoint 2010 Sandboxed solutions it's essential to be able to write functional code client side, as you are very restricted on what you can do on the server.

Writing Javascript can be extremely labourious without the assistance of some helper libraries like jQuery, and adding javascript links and code is even a challenge in a sandboxed solution.

Here's a cool way of adding jQuery code to Office365 or Sharepoint Online sandboxed solutions.

protected override void RenderContents(HtmlTextWriter writer)
        {
            StringBuilder js = new StringBuilder();

            js.AppendLine("$(document).ready(function(){");
            js.AppendLine(" alert('hello world!');");
            js.AppendLine("});");

            base.RenderContents(writer);

            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
            writer.AddAttribute(HtmlTextWriterAttribute.Src, "//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js");
            writer.RenderBeginTag(HtmlTextWriterTag.Script);
            writer.RenderEndTag();

            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
            writer.RenderBeginTag(HtmlTextWriterTag.Script);
            writer.WriteLine(js.ToString());
            writer.RenderEndTag();           
        }  

Domino Keyword Lookups, jQuery & JSON

In Domino 8 it became possible to return a view in JSON format using &outputformat=JSON querystring parameter.

Here’s a simple view in Notes:

















Here is what the JSON looks like:

{
  “@timestamp”: “20090303T123231,91Z”,
  “@toplevelentries”: “3″,
  “viewentry”: [
    {
      "@position": "1",
      "@noteid": "8000000C",
      "@children": "4",
      "@descendants": "4",
      "@siblings": "3",
      "entrydata": [
        {
          "@columnnumber": "0",
          "@name": "Index",
          "@category": "true",
          "text": {
            "0": "Option A"
          }
        }
      ]
    },
    {
      “@position”: “1.1″,
      “@unid”: “84FE562575501BE88025755F0031E1B1″,
      “@noteid”: “8F6″,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice A1"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “1.2″,
      “@unid”: “84FE562575501BE88025755F0031E1B1″,
      “@noteid”: “8F6″,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice A2"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “1.3″,
      “@unid”: “84FE562575501BE88025755F0031E1B1″,
      “@noteid”: “8F6″,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice A3"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “1.4″,
      “@unid”: “84FE562575501BE88025755F0031E1B1″,
      “@noteid”: “8F6″,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice A4"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “2″,
      “@noteid”: “80000010″,
      “@children”: “4″,
      “@descendants”: “4″,
      “@siblings”: “3″,
      “entrydata”: [
        {
          "@columnnumber": "0",
          "@name": "Index",
          "@category": "true",
          "text": {
            "0": "Option B"
          }
        }
      ]
    },
    {
      “@position”: “2.1″,
      “@unid”: “866C6FA4AEA492158025755F00328A60″,
      “@noteid”: “8FA”,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice B1"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “2.2″,
      “@unid”: “866C6FA4AEA492158025755F00328A60″,
      “@noteid”: “8FA”,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice B2"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “2.3″,
      “@unid”: “866C6FA4AEA492158025755F00328A60″,
      “@noteid”: “8FA”,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice B3"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “2.4″,
      “@unid”: “866C6FA4AEA492158025755F00328A60″,
      “@noteid”: “8FA”,
      “@siblings”: “4″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "textlist": {
            "text": [
              {
                "0": "Choice B4"
              }
            ]
          }
        }
      ]
    },
    {
      “@position”: “3″,
      “@noteid”: “80000014″,
      “@children”: “1″,
      “@descendants”: “1″,
      “@siblings”: “3″,
      “entrydata”: [
        {
          "@columnnumber": "0",
          "@name": "Index",
          "@category": "true",
          "text": {
            "0": "Option C"
          }
        }
      ]
    },
    {
      “@position”: “3.1″,
      “@unid”: “B6C86E0C587E08CB802575620031CA0F”,
      “@noteid”: “8FE”,
      “@siblings”: “1″,
      “entrydata”: [
        {
          "@columnnumber": "1",
          "@name": "Choice",
          "text": {
            "0": "Choice C1"
          }
        }
      ]
    }
  ]
}



Using jQuery and its incumbent JSON AJAX methods we can return data from the view and process it.
Below is a simple form which has 2 select option drop downs on it:











When the User chooses an Option from the ‘Option’ drop down, a set of choices specific to the selected option need to be offered in the ‘Choice’ field.

Here is the code from the JSHeader
function Option_changed()
{    
    //URL to the view with the restricttocategory set to the selected choice
    var url = dbpath + ‘/keywords?readviewentries&outputformat=json&restricttocategory=’ + $(‘#Option option:selected’).text()
    //Select object
    select = $(‘#Choice’)                    
    //Default option
    options = ‘’
    //jQuery AJAX call to return JSON
    $.getJSON(url,function(data) {    
        //Check if we have any rows
        if(data.viewentry){
            //Loop through the rows
            $.each(data.viewentry, function(i, item){        
                $.each(item.entrydata, function(i, item){
                    //If the column contains multi-value
                    if(item.textlist){
                        //Loop through the multi-value column data                    
                        $.each(item.textlist, function(i, item){
                            //Loop through the text values
                            $.each(item, function(i, item){    
                                options += ‘’
                            })                        
                        })                        
                    } else {
                        //No multi-value so just grab the text
                        $.each(item.text, function(i, item){
                            options += ‘’
                        })
                    }
                })
            })
            //Loop through the columns
            select.html(options)
        }
    })
    //
    $(‘#Choice’).html(options)        
}