Archive
#SP2010 web part rounded corners #SharePoint #PS2010 #ProjectServer #MSProject #in
At one of my clients I was asked to document how we achieved rounded corners on web parts. So as a result, I figured a blog post about it would be useful.
Now when I first implemented this (almost 2 years ago!) as the 2010 product RTM’d, I based it on the only blog post around at the time:
- The end result looks like this:
NB: Please note that this version is slightly modified from the version supplied on the blog link above.
In my implementation I was using the jQuery version available at the time:
- jQuery 1.5.1
- jQuery UI 1.8.13
Although jQuery UI is not required, it is always good to have for those awesome calendar pop-ups just in case.
This may work with the newer versions of jQuery, but I haven’t tried it out yet.
Example CSS, JavaScript and rounded corner image files are provided at the bottom of the post.
So without further ado, lets go through how to achieve the rounded corners in SharePoint 2010:
What does the code actually do?
With every page refresh, the JavaScript code, determines where all the web parts on the page are and injects appropriate mark up (<DIV>) above and below each web part, ready to be styled by CSS.
Step 1. Upload your reference files
Personally I like to store all my custom files within the Style Library within SharePoint, but they can live anywhere within SharePoint as long as all users have read access to them.
So lets take a look at what we are storing.
Standard Plug-In Files:
- jquery-ui-1.8.13.custom.css
- jquery-1.5.1.min.js
- jquery-ui-1.8.13.custom.min.js
You can download this version here:
- jQuery: http://docs.jquery.com/Downloading_jQuery#Past_Releases
- jQueryUI: http://jqueryui.com/download
The latest versions are available here:
Custom Files
- <custom JavaScript file>.js
- <custom CSS file>.css
These files are where we will implement the JavaScript and CSS code to produce the rounded corners on each web part.
Corner Image Files
The following files are used to create the rounded corner affect. To keep multi-browser support we are using this method, but you could replace them with CSS3 styling by changing the CSS code to achieve the same result.
- WPBottomLeft.gif
- WPBottomRight.gif
- WPTopLeft.gif
- WPTopRight.gif
Example files are provide below.
Step 2. Add your Master Page file references
Initially add the following references into <head> section of your Master Page, preferably just before the end tag </head>
<link type="text/css" href="/Style Library/jquery-ui-1.8.2.custom.css" rel="Stylesheet" /> <script src="/Style Library/jquery-1.4.2.min.js" type="text/javascript"></script> <script src="/Style Library/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script>
Now the above references are just standard plug-ins available from the jQuery website, but we also need to add some of our own JavaScript / jQuery magic, which of course needs its own reference file.
<script src="/Style Library/<customJavaScriptFile>.js" type="text/javascript"></script>
We also need to reference a custom CSS file, so that we can associate the corner images we will be using etc…
Publishing Feature enabled?
Now if you are using the Publishing feature, you can place your custom CSS via the Site Settings interface:
Site Actions > Site Settings > Under Look and Feel – Click “Master Page”
- (http://<server url>/_Layouts/ChangeSiteMasterPage.aspx)
Under the “Alternate CSS URL”, enter the URL for your custom CSS file, for example:
- /style library/<customCSSFile>.css
- NB: This will ensure it is the last CSS file referenced within the Master Page to allow for overrides.
Publishing Feature not-enabled?
If you you do not have the publishing feature enabled (Office 365 P1 or SharePoint Foundation 2010 for example), you can add the reference into the Master Page also.
<link type="text/css" href="/Style Library/{customCSSFile}.css" rel="Stylesheet" />
Step 3. Adding the code
So now that we have our JavaScript, jQuery and CSS files setup in the Master Page, we can edit out custom files with the following code:
CSS Code (customCSSFile.css)
/* Web Part Chrome Styles – START */
.wpContainer {
padding-bottom:0px !important;
}
.wpTitleBorder, .wpBorderOnly {
background-color:#fff !important;
border-left:1px solid #c6c6c5 !important;
border-right:1px solid #c6c6c5 !important;
}
.ms-WPHeader td {
background-color:#ffffff !important;
border:0 !important;
padding:0 !important;
padding-top: 3px !important;
border-bottom: 1px #CECFCE solid !important;
}
h3.ms-WPTitle {
/* color:#36424a !important; */
font-size:15px !important;
font-weight:normal !important;
margin:-3px 0 0 0px !important;
padding:0 14px 4px 4px !important;
}
h3.ms-WPTitle a {
/* color:#36424a !important; */
font-size:15px !important;
font-weight:normal !important;
}
h3.ms-WPTitle nobr {
white-space:normal !important;
}
.ms-WPHeader td div.ms-HoverCellInActive {
margin:0 !important;
*padding:0 0 2px 0 !important; /* IE <8 fix */
}
.ms-WPHeader td .ms-HoverCellInActive {
margin:0 !important;
*padding:0 0 2px 0 !important; /* IE <8 fix */
}
.ms-WPHeader td .ms-HoverCellInActive img {
margin:0 0 2px 0 !important;
*margin:0 !important; /* IE <8 fix */
}
.ms-WPHeader img.ms-HoverCellInActive { /* Firefox */
padding:0 0 2px 0 !important;
}
.ms-WPHeader td .ms-HoverCellActiveDark {
border:0 !important;
margin:0 !important;
padding:0 0 2px 0 !important;
}
td.ms-WPBorder, td.ms-WPBorderBorderOnly {
border:0 !important;
padding:0px 0px !important;
}
.ms-WPBody {
font-family:Tahoma, arial, sans-serif !important;
font-size:11px !important;
padding:0 !important;
}
.ms-WPBody td, .ms-WPBody TD DIV, .ms-WPBody TD DIV A {
font-family:Arial, Tahoma, sans-serif !important;
font-size:11px !important;
}
.wpCornersTop {
background:url('/blog/Style Library/Images/WPTopRight.gif')
top right no-repeat !important;
height:10px !important;
padding-right:10px !important;
}
.wpCornersTop div {
background:url('/blog/Style Library/Images/WPTopLeft.gif')
0 0 no-repeat !important;
height:10px !important;
}
.wpCornersBtm {
background:url('/blog/Style Library/Images/WPBottomRight.gif')
bottom right no-repeat !important;
height:11px !important;
padding-right:11px !important;
}
.wpCornersBtm div {
background:url('/blog/Style Library/Images/WPBottomLeft.gif')
0 0 no-repeat !important;
height:11px !important;
}
/* Web Part Chrome Styles - STOP */
JavaScript / jQuery Code (customJavaScriptFile.js)
function wrapWebParts() { //Find all divs (div.ms-WPBody) with an ID beginning //with "WebPart". All web parts have unique IDs assigned //to them, and they begin with "WebPart". Then traverse up //the HTML document 4 levels and add the class "wp". $('td[id*=MSOZoneCell_WebPart]').children("table").addClass("wp"); //For web parts with the Title and Border chrome, //add the class "wpTitleBorder" to the element //with class "wp". $(".ms-WPBorder").parents(".wp").addClass("wpTitleBorder"); //For web parts with the Border Only chrome, add the class //"wpBorderOnly" to the element with the class "wp". $(".ms-WPBorderBorderOnly").parents(".wp").addClass("wpBorderOnly"); //Find all table cells that have an ID beginning with //'"MSOZoneCell" and add the class "wpContainer". $("td[id^=MSOZoneCell]").addClass("wpContainer"); //For web parts with the chrome type Title and Border or Border Only, //add containers that can be used for rounded corners and other //treatments //alert($(".wpTitleBorder").length); $(".wpTitleBorder").before('<div class="wpCornersTop"><div></div></div>') .after('<div class="wpCornersBtm"><div></div></div>'); $(".wpBorderOnly").before('<div class="wpCornersTop"><div></div></div>') .after('<div class="wpCornersBtm"><div></div></div>'); $("img[src*=/_layouts/images/blank.gif]") .attr("style", "display: none;"); $('div[class=wpCornersBtm]').each(function() { var mainWPTable = $(this).prev(); var inlineWidthStyle = mainWPTable.attr("style"); var realWidthSplit = ""; var realWidth = ""; if (inlineWidthStyle != undefined) { realWidthSplit = inlineWidthStyle.split(":"); realWidth = realWidthSplit[1].toLowerCase(); realWidth = realWidth.replace("px", ""); realWidth = parseInt(realWidth, 10); realWidth = realWidth + 13; $(this).attr("style", "width: " + realWidth + "px"); $(this).prev().prev().attr("style", "width: " + realWidth + "px"); } }); } $(document).ready(function(){ wrapWebParts(); });
And Finally…
The end result is this:
If we break this down, the jQuery code has discovered each web part on the page, added a <div> above and below the web part and then the CSS has styled it with the supplied image files referenced in the style sheet.
The code also takes into account the chrome type being used on the web part:
This results in the following:
Chrome Type: None
Chrome Type: Title and Border
Chrome Type: Title Only
Chrome Type: Border Only
Code Downloads:
Current Year, Month and Quarter in JavaScript #SP2010 #SharePoint #PS2010 #MSProject #ProjectServer #in
Just a quick post to show some useful JavaScript I have been using this week.
In particular a one liner to work out the current quarter.
1 var currentYear = (new Date).getFullYear(); 2 var currentMonth = (new Date).getMonth(); 3 var currentQuarter = Math.floor(((currentMonth + 11) / 3) % 4) + 1;
Minimising JavaScript files for production #in #SharePoint #SP2010 #ProjectServer #PS2010
As per my previous post, in my current project we are starting to migrate the whole solution to live.
The project I am working on is a global solution with locations in UK, USA, India, China + others. As a result of this, like many global projects, we suffer from the available connections.
This is potentially very minor in helping, but as part of the production process we are minimising the JavaScript files.
To do this, I have used the Yahoo compressor which is a java applet where you can pass in the file and output the minimised version.
Download Link: http://yuilibrary.com/downloads/#yuicompressor
How To Documentation: http://developer.yahoo.com/yui/compressor/#using
Example Command Line: java -jar yuicompressor-2.4.6.jar –nomunge –preserve-semi –disable-optimizations <input file> -o <output file>
Useful JavaScript Function – Default parameters within your JavaScript functions #in #SharePoint #SP2010 #PS2010 #ProjectServer
So it has been a while since I have posted anything on the blog.
As I am sure many of you can relate, there comes a time in all projects when you have to concentrate solely on them to ensure that all factors play out as expected. One of those times would be go live time.
The project I have been working on for the last year is about to go into trial with its first division, so it has been heads down to ensure that all bug fixes and business intelligence data is correct.
As of today, we are officially at a code freeze and we are clearing down the databases to rid them of test data ready for migration to the Production environment and the final integration testing process.
As a result, we can commence blogging again, of which I have a few topics stored up.
First up is…
Default parameters in a JavaScript function
Project Scenario: I created a generic function to contact the User Profile service and set some default global variables when the page loads for the current logged in user.
This had to be extended to cope with me passing a different AD User Name (SAMAccountName) and return the details in a JavaScript object.
So the basic mechanism was there already.
- I was passing the current user as a variable
- User Profile Service was already being queried
- Set the global variables for the current user
I wanted to extend this to take any user, but not upset the other functions that relied on the global variables I was setting in the function.
So essentially I added a setGlobal flag parameter and provided a default to the function so that existing code could work (surrounded by the newly created flag of course) and then implemented what I needed to.
This allowed my existing code to continue to function without issue, but also allowed me to reuse my User Profile functionalities for another purpose.
Examples:
The original idea came from the following blog post:
In my code, I implemented the first method. In future however I shall certainly use the second approach.
Calculated Column Formula: Probability and impact analysis for risks #SharePoint #SP2010 #ProjectServer #PS2010 #EPM #MSProject #in
Many project managers like to do risk analysis in terms of probability and impact, ultimately creating a heat map when data is rolled up at the project or programme level.
Further information about the methodology can be found here: http://www.expertprogrammanagement.com/2010/06/project-risk-management/
To aid in the creation of these roll up dashboards, we need to evaluate each risk as it is entered (and updated) and assess the probability of the risk occurring against the impact it has against the project (normally in terms of Cost, Resource or Time).
The following chart details this analysis:
NB: Numeric values have been assigned for the formulas listed below
To implement this in SharePoint (either standalone or as an extension to the standard Risks list in Project Server) we need to translate what the Project Manager / Team Members would like to state in words regarding probability & impact into a numeric value for sorting and analysis.
The following Choice columns are added to the Risk form.
User Interface Columns:
| Column | Type | Values |
| Probability of Risk | Choice | Very Low, Low, Medium, High, Very High |
| Impact of Risk | Choice | Very Low, Low, Medium, High, Very High |
Once we have the UI version of Probability and Impact, we need to use some hidden / calculated columns to convert these values in to numbers.
Once we have these values we then multiply them together:
Probability x Impact = Expected Outcome Value
Hidden Columns:
| Column | Type | Values |
| Risk Probability Value | Calculated Column | =IF([Probability of Risk]=”Very Low”,0.1,IF([Probability of Risk]=”Low”,0.3,IF([Probability of Risk]=”Medium”,0.5,IF([Probability of Risk]=”High”,0.7,IF([Probability of Risk]=”Very High”,0.9,0))))) |
| Risk Impact Value | Calculated Column | =IF([Impact of Risk]=”Very Low”,0.05,IF([Impact of Risk]=”Low”,0.1,IF([Impact of Risk]=”Medium”,0.2,IF([Impact of Risk]=”High”,0.4,IF([Impact of Risk]=”Very High”,0.8,0))))) |
| Expected Value Result | Calculated Column | =[Risk Probability Value]*[Risk Impact Value] |
Now that we have our Expected Outcome as a number, we can convert this back to a value the end user will understand, report and dashboard from.
RAG Outcome:
| Column | Type | Values |
| RAG | Calculated Column | =IF([Expected Value Result]<0.05,”Green”,IF([Expected Value Result]>0.14,”Red”,”Amber”)) |
For each risk in the list we will now have a RAG value.
Further customisations I end up doing in clients include adding a RAG indicator column showing a graphical representation of the risk using jQuery.
RAG Indicator:
| Column | Type | Values |
| RAG Indicator | Calculated Column | =”<div class=’convertToHTML’><img src=’/pwa/customisation/images/RAG” & [RAG] & “Sml.gif’ alt=”‘ & [RAG] & ‘” title=”‘ & [RAG] & ‘”></div>” |
The above formula expects three images:
- RAGGreenSml.gif
- RAGAmberSml.gif
- RAGRedSml.gif
Images in the formula are stored in a document library called:
- Customisation
with a folder inside called:
- images
Run the following jQuery function on the page with the list view on to convert the RAG Indicator calculated column string into rendered html:
Useful JavaScript Function – Refreshing a page with parameters for use with Query String Filter Web Parts in #SP2010 #SharePoint #ProjectServer #PS2010 #in
In my current project I have the need to determine the current users personal preferences based on favourites stored in a list.
These personal preferences then drive various web parts on the page.
Using this the Enterprise Edition of SharePoint Server 2010 makes this very easy with the use of the Query String Filter Web Part and various other web parts that support connections including:
- Reporting Services Web Part
- Excel Services Web Part
- List Web Parts
- etc…
Using the combination of parameters and the above web parts it makes it a lot easier to create dashboard pages that are specific to a users:
- Preferences
- Job Role
- Department
- etc…
Now in most of my projects, I have found that dashboard pages tend to be buried under a 2nd or 3rd level of navigation, which makes it very easy to create links with parameters already in them.
However, in this case, I have to create various dashboard pages at the root of the site, whilst using standard SharePoint Publishing Navigation (Global Navigation). The parameters being passed are user selectable based on favourites stored in a list.
Given that the SharePoint Site Map Provider doesn’t know about this random favourites list I have created, I need to improvise to ensure that the end user is presented with dashboard pages personalised to them, as soon as they hit the root site URL.
Code Example:
Essentially the following happens:
- The page load to a certain point
- We determine if we have the query string parameter(s) we are looking for
- If we don’t, we stop the page from rendering using document.execCommand(“stop”)
- Go get our require parameter(s)
- Determine if any previous parameters existed on the page currently (to make the code more generic)
- Reload the page with the new parameter(s)
If you find any unwanted page flashing before the page reload, use JavaScript to set style=”display: none;” on the main content <div> on the v4.master – Master Page, if the parameter doesn’t exist.
Although this is certainly one method of achieving my goal and seems to currently fit my clients requirements, I would certainly be interested to hear from others on how to achieve my goal without drastically changing standard SharePoint components.
Useful JavaScript Function: isInteger and isNumeric #SharePoint #SP2010 #in
Just a quick post as a reminder for myself in future projects.
Useful JavaScript Function: PreSaveAction #SP2010 #SharePoint #PS2010 #ProjectServer #in
Just a quick blog post to talk about a standard JavaScript function that exists in SharePoint 2007 and 2010 – PreSaveAction().
Now I have done extra validation and functions on list forms in allsorts of ways before (some of which is blogged on this site) and it is only recently that this standard function has been brought to my attention. (Thanks @GlynClough via twitter).
Once I learned about this function I of course google’d about it to see what I could find and came across the following blog articles:
- http://www.endusersharepoint.com/2008/10/07/endusersharepointcom-extending-issues-and-tasks-part-3/
- http://www.allaboutmoss.com/index.php/tag/presaveaction/
These are excellent articles that explain the function, however in the way I tend to work in my projects it posed a problem.
We are essentially overriding a standard SharePoint JavaScript function and the articles assume that you can place a Content Editor Web Part onto the page to add the functionality.
Now in SharePoint 2010 this is less of a problem, since there are very good and official ways to add web parts to list form pages, even in a Publishing Site.
However, in Microsoft Office SharePoint Server 2007 utilising publishing sites, editing newform.aspx and editform.aspx pages caused many issues.
This forced the consultant / developer to create their own new / edit forms and pages in order to insert sometimes a very small amount of code.
Since most of my projects seem to involve the Publishing feature in one way or another, I typically place JavaScript reference files in the Master Page. This means that my JavaScript code is running on every page.
So, getting to the point of this article, I have modified the general example that is supplied on other sites to take into account this method of JavaScript development by simply querying what page I am on before I run my validation tests and functions.
Code Example:
Using jQuery to find the current logged in user #in #SP2010
Problem:
In MOSS 2007, we had methods to get the current logged in user by accessing some of the properties found in the Welcome Menu.
Although this is still the case in SharePoint Server 2010, there are some fundamental changes to the code and the way the Welcome Menu is rendered in SPS 2010 that means we have to do something slightly different to get the same result.
I have recently had a requirement to achieve this in my current project and thought I would share the basics with you.
Essentially we are still retrieving the information from an HTML element property in the Welcome Menu, but the menu itself is rendered in AJAX and therefore is not necessarily available as soon as the page is rendered and the DOM document ready state is set.
As a result of this, running JavaScript / jQuery on the page at either:
- $(document).ready
- _spBodyOnLoadFunctionNames
will not return the required result, since the menu elements we need to interrogate have not been rendered yet.
Solution:
- Set a timer to keep running a particular function to wait until the menu is rendered
- Stop the timer
- Interrogate the DOM as required using jQuery
Code Example:






You must be logged in to post a comment.