Tuesday, September 25, 2012

Sharepoint 2007 - Modal Dialog Sharepoint2010-Like

Or .. How to show modal dialog with page content only.

In Sharepoint 2007 we don't have a client script framework that shows modal dialogs with ligthbox effect, as in Sharepoint 2010.
We can reproduce with a lot of jquery ui and similia.

In MOSS, we can use the function javascript of core.js, commonShowModalDialog.
Open Site and in Homepage, add a Content Editor Web Part with this simple code:


<a href="javascript:openInModalDialog()">CLICK HERE</a>

<script type="text/javascript">
function openInModalDialog()
{
  var url = "/Lists/Calendar/Calendar.aspx";
  commonShowModalDialog(url,"resizable: no; status:no; scroll: no; help: no; center: yes; dialogwidth:800px; dialogHeight:500px;",RetrieveItemValue);
}
</script>


Click on link opens modal dialog, but we show the entire page in window:



Now, open Calendar page in edit mode. Add Content Editor Web Part at the bottom of the page with code below.

We add jquery:

<script type="text/javascript" src="/intranet/Media/js/jquery-1.8.0.min.js"></script>

We define a new jquery function to get querystring values from url:

///////////////////////////////////////////////////////////
//FUNCTION GET QUERYSTRING VALUES
///////////////////////////////////////////////////////////
(function($) {
    $.QueryString = (function(a) {
        if (a == "") return {};
        var b = {};
        for (var i = 0; i < a.length; ++i)
        {
            var p=a[i].split('=');
            if (p.length != 2) continue;
            b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
        }
        return b;
    })(window.location.search.substr(1).split('&'))
})(jQuery);
///////////////////////////////////////////////////////////

Now, we add the function to retrieve page in modal dialog environment:

$(document).ready(function(){

 var isDlg = $.QueryString["isDlg"];
 if(isDlg && isDlg == "1"){
  $('body > :not(#MSO_ContentTable)').hide(); //hide all nodes directly under the body
  $("#MSO_ContentTable").appendTo('body');
 }

});

This function hides all elements in page, but the content table.

Then, save and back to home.
Edit first Content Editor WP, adding querystring "isDlg=1" to url in javascript:

var url = "/Lists/Calendar/Calendar.aspx?isDlg=1";


Now, save and click on Click Here link. Et voilĂ !


(
Note: An issue is that if you click on a link in modal dialog (i.e. New or change month) browser opens new windows page...
I think you can use jquery to control events on this modal dialog..
I did not try this solution.. 
)

Thursday, September 20, 2012

Sharepoint 2010 - Customizing Quick Launch with pages

How to show different quick launch menu items in different pages?

The quick launch in Sharepoint is an object common to all pages of the site.
To show menu items according to the page you visited, I followed client side method with javascript (jquery).
Here's how, using Sharepoint Designer 2010.

On css stylesheet of the site, I added this instruction, which hides all the items in the Quick Launch:

. s4-ql ul.root> li {
display: none;
}

Then, make note of the position of the menu items in the quick lanuch: eg.


0 - Document Libraries
1 - Lists
2 - MyLink
     0 - MySubLink1
     1 - MySubLink2
3 - MyOtherLink
4 - MyLastLink



The pages follows the following rules:

Page1 shows 0,1,4
Page2 shows 0,2,3
Page3 shows 0,2 (and sub ​​links 1), 3.4


And now, I change the master.page, adding references to jquery and inserting the following code:

//get all items in the quick launch
var li_nav = $(".vertical-menu>ul>li");
//get page name (from url, return page1.aspx)
var page_name = GetCurrentPageName();
//for each li
var i = 0;
li_nav.each(function(){
    if (page_name.indexOf("page1")> -1) {
       if (i == 2 || i == 3)
         $(this).hide();
       else
         $(this).show();
    }
    else if(page_name.indexOf("page2")> -1) {
       if (i == 1 || i == 4)
         $(this).hide();
       else
         $(this).show();
    }
    else if(page_name.indexOf("page3")> -1) {
       if (i == 1)
         $(this).hide();
       else if (i == 2) {
         $(this).show();
         var j = 0;
         $(this).children("ul").children("li").each(function(){
            if (j == 0){
                $(this).hide();
            }
            j++;
         });
       }
       else
         $(this).show();
    }
    else {
       $(this).show();
    }
    i++;
});

So, navigating to page1.aspx we see


0 - Document Libraries
2 - MyLink
     0 - MySubLink1
     1 - MySubLink2
4 - MyLastLink


To page2.aspx:

0 - Document Libraries
2 - MyLink
     0 - MySubLink1
     1 - MySubLink2
3 - MyOtherLink

To page3.aspx:


0 - Document Libraries
2 - MyLink
     1 - MySubLink2
3 - MyOtherLink
4 - MyLastLink

Wednesday, September 19, 2012

Resizing Cross-Domain IFrame with Javascript

I tried to find a way to pass height of page loaded in an IFRAME to parent document in order to reset the height of the IFRAME with javascript.
It's a simple coding, but .. if you use IFRAME with a page in a different domain, you cannot access to properties of page opened in IFRAME and from page to opener.

The idea is to be able to pass the value of the height of the content at regular intervals, using a javascript function, and try to read it by the parent.

This applies to the height value, but works for any data, of small size, to be passed client side from content of the iframe to container in a cross domain situation.
Obviously, if we can access page open iframe in edit.

NOTE: Both domains must be added to Trusted Sites.

Let's see how.
I put the following function in the page that I want to load iframe:

setInterval (function () {this.frames.status = getHeight();}, 400);

getHeight function () {

     var height;
    [we calculate body height, or div container height, if it changes with js, i.e.]
     return height;
}

At intervals of 400 ms, the function calculates the height of the loaded page (or element) and sets the object this.frames.status (this object can be write and read in cross domain situation!).

In the page containing the IFRAME, we set code like this:

<!-- this is for write value -->
<div id="div_height"></div>
<script type="text/javascript">

setInterval(function(){

   var iframe = document.getElementsByTagName("iframe")[0];

   if(iframe && iframe.document.frames.status != ""){


      document.getElementById("div_height").innerText = "now iframe has height of " + iframe.document.frames.status + " pixels";

      var h_iframe = parseInt(iframe.document.frames.status) + 150;
      iframe.style.height = h_iframe;
   }
}, 500);
</script>

At intervals of 500 ms, the function reads the value of the iframe.document.frames.status object, converts it to an integer and sets it as the height of the IFRAME (or other objects).

It works!

Tuesday, September 18, 2012

Sharepoint 2010 - Client Validation of a Custom Form with Javascript

What to do if you want to perform a client validation with Javascript, in your custom new/edit form.

The submit button cames with this code in onclick event:


if (!PreSaveItem()_) return false;WebForm_DoPostBackWithOptions(new ...

The PreSaveItem function invokes PreSaveAction function that you can override with your own definition.If PreSaveAction returns true, then form proceeds to save data, otherwise, it stops with alert.


With Sharepoint Designer 2010, open form with Edit in Advanced Mode and insert code below:


<!-- call jquery -->
<script type="text/javascript" src="/SiteAssets/js/jquery.min.js"></script>
<!-- override PreSaveAction -->
<script type="text/javascript">
function PreSaveAction()
   var field_to_validate = $("select[title='TITLE OF FIELD']").val();
   if(field_to_validate == ""){
     alert("Warning: complete field_to_validate!");
     return false;
   }
   return true;
}
</script>

We add jquery (but if you want to use simple javascript, you can).
Then, check field by title: in browser, input tag came with attribute "Title" equals to display name of column, then I search for this value.
If empty, return alert then false.


Wednesday, September 12, 2012

Sharepoint 2010 - Create a Site Collection Template without Errors...


(I know, the title of this post is misleading ...)

I had to create a template for Site Collection and, according to various posts and tutorials, the procedure seems very simple: Save site as template, Import into a new project in Visual Studio 2010, changing some scope, put into hidden some features and recompile.
Then, upload wsp on farm, deploy and so on ...

Everything is fine until I try to create a new Site Collection using the new template.
The page loading... and ... error "File not found"!!
In the log file, nothing about which files it is searchin for.

I found no solution, my template was not so complex, but did not understand why this error.

In the end, the lighting has arrived.

We know that is not possible (in theory) save a site as a template if it has the Publishing Feature activated.
"In theory", because through the direct link to the page, you can save it as template.
But Microsoft does not support this type of template (site with publishing feature activated), so they hide us the link.

In case of a top-level site of a site collection, even if Publishing Feature in NOT activated but, in Site Collection, Server Publishing Infrastructure Features is activated, we can Save site as model, BUT we get errors!

Activate Server Publishing Infrastructure Features creates some lists and libraries of type "publishing".
Unfortunately, turn them off  does not eliminate what was created and it seems that these items are the cause of the failure in create new site collection from template.
Although this does not give errors in creation, build and deployment.
And if we use this template for a new site in a Site Collection (yes, we can do), it's ok.

So, if you want to create a Site Template for a Site Collection, you DO NOT EVER activate the Server Publishing Infrastructure Features in Site Collection!

Lesson to learn..

Get QueryString Value with JQuery

I found this solution to get value of querystring with jquery.

Add jquery script to your page and insert this code in script to define the new function:

(function($) {
    $.QueryString = (function(a) {
        if (a == "") return {};
        var b = {};
        for (var i = 0; i < a.length; ++i)
        {
            var p=a[i].split('=');
            if (p.length != 2) continue;
            b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
        }
        return b;
    })(window.location.search.substr(1).split('&'))
})(jQuery);

Then, call it for your querystring parameter:

var q = $.QueryString["query"];

Fine!