Pages

Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

May 4, 2013

Custom values on Choice column - Part 2


In Part 1 here of this article, we understood how the default choices work in OTB Create Column page (FldNew.aspx) in SharePoint 2010.
Now, its time to start the fun. Let's see examples of how we can show custom choice values:

First, remember to always make a backup copy of any OTB file before customizing it.

Example 1: Change static text values in resource file
Open the wss.en-US.resx (located in C:\inetpub\wwwroot\wss\VirtualDirectories\80\App_GlobalResources directory) using notepad or Visual Studio. Search for the keys, and replace the default values with your custom values such as (X, Y, and Z).


And this is how it will look like when creating new column:


There are only 3 keys to be used here. The downside of changing values for these 3 keys is that this will impact other pages, for example these keys are used in qstedit.aspx page used in survey lists. 
You can create new keys with custom values inside wss.en-US.resx and reference them through a a GetGlobalResourceObject()  in FldNew.aspx page.


Example 2: Custom static choices on page:
You can define your static strings directly without the need to resources file.
Edit FldNew.aspx, and replace the whole original inline code (highlighted yellow portion in Part 1) with this:

SPHttpUtility.HtmlEncode(
            "January" + "\r\n" + "Febraury" + "\r\n" + "March"+ "\r\n" +
            "April" + "\r\n" + "May" + "\r\n" + "June" + "\r\n" +
            "July" + "\r\n" + "August" + "\r\n" + "September" + "\r\n" +
            "October" + "\r\n" + "November" + "\r\n" + "December"
            ,Response.Output);


And this is how it will look like:



Example 3: Custom dynamic strings:
We can provide list of numbers from 0 to 9. Put the following code instead of the inline code (highlighted yellow portion in Part 1) in page. Set the rows parameter inside the textarea tag to expand the choices box to show more values as required.

        string ChoicesTxt = "0";
       
        for (int i=1; i<10; i++)
            ChoicesTxt += "\r\n" + i.ToString();
       
       // write the choices string into idChoices control on page
       SPHttpUtility.HtmlEncode(ChoicesTxt,Response.Output);

 And it will like this:


Example 4: Custom data from SharePoint list:
Create a custom list named "MyChoices" and add your choice values in Title field. Adjust the permissions to make it readable by all farm users or elevate the privileges through code. Replace the idChoices inline code (highlighted yellow portion) with the following:


        string ChoicesTxt = "";
        bool  _CustomChoicesError = false;
       
        try
        {
            SPWeb web = SPContext.Current.Web;
            SPList MyChoicesList = web.Lists.TryGetList("MyChoices");
            if (MyChoicesList != null)
            {
                // if lists exists, read all the items
                SPListItemCollection MyChoices = MyChoicesList.Items;
                foreach (SPListItem choice in MyChoices)
                {
                    ChoicesTxt += choice.Title + "\r\n";  
                }
            }
            else
                _CustomChoicesError = true; // list does not exist
        }
        catch (Exception ex)
        {
            _CustomChoicesError = true;
        }
       
        // in case of error, revert back to original choices
        if (_CustomChoicesError)
            ChoicesTxt = "Enter Choice #1\r\nEnter Choice #2\r\nEnter Choice #3\r\n";
       
        // write the choices string into idChoices control on page
        SPHttpUtility.HtmlEncode(ChoicesTxt,Response.Output);

The list (left), and how the values will look like (right):



If the 'MyChoices' list is deleted or an error occurred during data retrieval, then the page will display the original values.
Note: When you create a column using custom choice values, change value of any of the items temporarily and then undo the change. This is to trigger clearOutDefaultWithCheck() for the default value control to show the first value (its default behavior is to take its value from the resources files). Also you can do this by adding more code to handle this.


I hope you enjoyed with these ideas about customizing the choice values across your farm.



April 30, 2013

Custom values on Choice column - Part 1

Couple of weeks ago I was playing around with SharePoint columns, and thought it would be nice to have a custom set of choices to show always when we create a choice column in SharePoint 2010.


Out of The Box functionality:
In SharePoint 2010, go to any list/library, and click 'Create Column' button. When you select a choice column then 3 dummy choice items will display initially ('Enter Choice #1', 'Enter Choice #2' and 'Enter Choice #3'). If you delete these and entered your custom list of items instead, you will notice that the default value field shows the first item value automatically.

My objective is to show useful data each time you create a choice column across your SharePoint farm. Examples could be: numbers from 1 to 10, or list of all months, or just a bunch of names..and the custom values can be static, calculated or coming from a SharePoint list!

I find manipulating SP pages an amusing task, and it is helpful to give you an inside view of how everything works. However, keep in mind that customizing OTB pages is not recommended because all your work can be flushed when patches got installed.
If you do things carefully and you are not going to install any update then continue reading!

First let's have a look on how the choices works in the OTB page.
The page we just saw in column creation is: 'FldNew.aspx' and you can find it in _Layouts folder.
Hit F12 key to view the JavaScript code. If you select the arrow icon and click on the box that shows the three dummy values then we can get to the control and its id is 'idChoices' as follows:

<tr>
                <td colspan="2"></td>
                <td class="ms-authoringcontrols">&#160;</td>
                    <td class="ms-authoringcontrols" id="onetidEnterChoice"><label for="idChoices">Type each choice on a separate line</label>:<font size="3">&#160;</font><br />
                        <table border="0" cellspacing="1">
                                <tr>
                                        <td>
<textarea class="ms-input" name="Choices" id="idChoices" rows="4" cols="40" wrap="off"  onchange="clearOutDefaultWithCheck()" >
Enter Choice #1
Enter Choice #2
Enter Choice #3
</textarea>
                                        </td>
                                </tr>
                        </table>
                </td>
</tr>

The default value control has the id:'onetidIODefChoiceValue'. This is how it works:
Initial value is 'Enter Choice #1'. When user edits and put custom choices, the method clearOutDefaultWithCheck() triggers and will call the other method clearOutDefault() when Calculated Value radio button was not selected. Method clearOutDefault() will set the first choice as the value of the text box of the Choice radio button.



Let's switch to Visual Studio and open the 'FldNew.aspx' and search for 'idChoice'. 
Caution: make backup copy for each OTB file before editing.

<tr>
<td colspan="2"></td>
<td class="ms-authoringcontrols">&#160;</td>
<td class="ms-authoringcontrols" id="onetidEnterChoice"><label for="idChoices"> <SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,fldedit_typeeachchoiceonseparate%>" EncodeMethod='HtmlEncode'/></label>:<font size="3">&#160;</font><br />
<table border="0" cellspacing="1">
<tr>
<td>
<textarea class="ms-input" name="Choices" id="idChoices" rows="4" cols="40" wrap="off"  onchange="clearOutDefaultWithCheck()" >
<%
SPHttpUtility.HtmlEncode((string)(this.GetGlobalResourceObject("wss", "fldedit_L_strDefaultChoice_Text")) + "\r\n" + (string)(this.GetGlobalResourceObject("wss", "fldedit_L_strChoice2_Text")) + "\r\n" + 
(string)(this.GetGlobalResourceObject("wss", "fldedit_L_strChoice3_Text")),Response.Output);
%></textarea>
</td>
</tr>
</table>
</td>
</tr>

Yellow portion is the where you need to focus, because this tells us how the control is getting the default values. This is an inline C# code that reads static text strings from a resource file using GetGlobalResourceObject() and encode the combined text string to be displayed within the control.
The method GetGlobalResourceObject() reads the a string value of a resource key stored in Resources file named 'wss'. The actual resource file name is 'wss.en-US.resx'. This is an ASP.NET application level resources file and available in the App_GlobalResources directory for every web application in SharePoint. 
For example: for my web application that resides on default port 80, the file path is:
C:\inetpub\wwwroot\wss\VirtualDirectories\80\App_GlobalResources\wss.en-US.resx

For idChoice control the keys are: "fldedit_L_strDefaultChoice_Text", "fldedit_L_strChoice2_Text" and  "fldedit_L_strChoice3_Text".
And for the the onetidIODefChoiceValue control the key is: "fldedit_L_strDefaultChoice_Text".

You can open this wss.en-US.resx file by notepad or Visual Studio. Search for the keys, and you will find the default choice values!



Now we finished understanding what's going on...the following article (Part 2) is about setting our desired custom choice values!


January 28, 2013

Bulk file download from SharePoint using DocExtractor


This is something that I developed a while ago and thought to share it online.

A real scenario
Imagine that you are a site collection admin in a small company, and your boss asked you to store on DVDs all the documents that belong to an employee who already left his position..several months ago.
Now to add little spices to the requirements, the manager might say something like:
"..oh, and we need all the Excel reports that had been uploaded by Mr. X to the Operations site between September 2012 and January 2013".
You get he picture. You can imagine other possible scenarios like when there is a need to store the contents of each department before terminating a big project.


Using Search?
SharePoint has powerful search functionality (especially when equipped with FAST search). You can specify some criteria, but search does not behave as we want in this context. There are few criteria options to play with, and You can only download one file item at a time. You will not be able to download all files that match the criteria as a bulk download operation. Also, you can't get list attachments.


My bulk download solution: DocExtractor
I designed and developed an easy to use, criteria–based file downloader for SharePoint.


A User originally must have Site Collection administration rights. I added the ability to navigate  through local web applications and select desired site collection from login form so user must have also Farm administration rights (both roles can be played by the same user in small companies). 


The user can either select to download all files on the site collection without exception, or to specify desired criteria in no time. Criteria can be any combination of the following:
  • Site(s), 
  • User(s) and his/her role (Author/ Modifier) , 
  • File type (groups of formats in MS Office, PDF, Images, Videos, Audio, Web and custom), 
  • File size (in B/KB/MB)
  • File creation/modification date period
  • Text in title (a 'Contains' Filter)

All lists and libraries (including hidden ones) will be searched, and the tool will download: last checked-in version of each file, as well as list attachments. Although the tool has access to all files, the download operation itself is subject to blocked files constraint.
We can choose whether to download the files with or without its folders hierarchy. If the latter option used then the tool will rename file copies automatically on the output directory. 

While downloading, user can cancel the operation at any time. Also, the user will see colored notifications about the download status. After download operation is completed, a log file is created to show all the download details and errors if any.



By the way, the download is really fast. I tested that on my dev. farm machine, and it downloaded more than 2800 files (size is about 2.3 GB) in less than 2 minutes.



The development part

The utility is a Windows Forms application consisting of GUI forms and work classes that uses SharPoint Object Model. Queries are dynamically created by making CAML conditions out of user criteria, then inserting these conditions into one big query. This big query will be used to retrieve URLs of matching files from site or site-collection using SPSiteDataQuery objects. List attachments are also examined to get the matching URLs. These combined URLs to be downloaded in a background thread by iterating through the URLs, get their corresponding SPFile objects, then copy their byte streams on the target folder.

For example, when user specifies file type(s), then conditions are added to the query as this:
qBuilder.addCondition(@"
                            
                            doc
                        ");
qBuilder.addCondition(@"
                            
                            docx
                        ", "OR");

And this is a method to retrieve the list of file url from site collections including the qualified list attachments:
// site specific attachments
// Specific files according to user criteria in all sites
public List _getSpecificDocsInSiteCollection()
{
    List FileRefs = new List();
    SPSiteDataQuery DocFilesQuery;

    using (SPSite site = new SPSite(SiteUrl))
    {
        //using (SPWeb web = site.OpenWeb("/"))
        using (SPWeb web = site.OpenWeb())
        {
            user = null;
            if (UserLoginName != "")
                user = web.EnsureUser(UserLoginName);// only when specific user

            DocFilesQuery = new SPSiteDataQuery();

            DocFilesQuery.Lists = "

The project is on Github.com, you can download the executable and the project from here.
The utility was tested on two SP 2010 Foundation farms. Of course a lot of changes and features can be added later such as implementing more criteria or the ability to zip the resulted output folder automatically.
Happy SP coding and administration :)