Friday, January 25, 2019

Editing wsp-package third-party solution

In this article I will explain how to make a change to a third-party solution by changing the data in the wsp file. I have a wsp file, where the visual web part is displayed in English, since I have to work with Russian-speaking users, I need to add names in Russian and translate the web part from ANSI to UTF-8, how to do it all in order. , so, let's begin!

1. Unpacking the wsp file (.cab) It is suitable to use archivers such as 7-Zip or WinRAR. Name solution is "Exaction.ListSearch.wsp", The screenshot shows that its web part is in English.



Right-click on our wsp file and select Unpacking in "Exaction.ListSearch" open this folder and will see manifest, dll-file and another folder related to the project (Features, Layouts, CONTROLTEMPLATES).


2. To change a web part from English to Russian to open folder "CONTROLTEMPLATES" with extension ".ascx". Open this file via notepad editor and change text on "Russian names".



Save As and change Encoding on UTF-8.



3. Now is download makeddf 1.0.1 in the same folder (you can in another, but you will have to specify the full path to the file makeddf.exe).

4. Open is PowerShell ISE editor (or Command Promt) run as Administrator and insert this command:

#Get path
cd "C:\wsp\Exaction.ListSearch"
#Create ddf-file
C:\wsp\Exaction.ListSearch\makeddf.exe /p Exaction.ListSearch /d Exaction.ListSearch.ddf /c Exaction.ListSearch.cab
#Set cab-file
makecab /f Exaction.ListSearch.ddf

5. Run command to get path cd "C:\wsp\Exaction.ListSearch"

6. Run command to create ddf-file: C:\wsp\Exaction.ListSearch\makeddf.exe /p Exaction.ListSearch /d Exaction.ListSearch.ddf /c Exaction.ListSearch.cab


7. Run command to create cab-file: makecab /f Exaction.ListSearch.ddf.


8. Rename file "Exaction.ListSearch.cab" on "Exaction.ListSearch.wsp".

9. Copy file "Exaction.ListSearch.wsp" into SharePoint server and Open is PowerShell ISE editor run as Administrator then add and run 2 command:

#Add PSSnapin Microsoft SharePoint
Add-pssnapin Microsoft.sharepoint.powershell
#Update Solutions
Update-SPSolution –Identity Exaction.ListSearch.wsp –LiteralPath C:\Wsp\NewListSearch\Exaction.ListSearch.wsp –GACDeployment -FullTrustBinDeployment
We are waiting for IIS to restart and open our web part, congratulations, everything works!


Happy Coding!

Thursday, January 24, 2019

Highlighting list items with .NET and CSR (Employee Vacation Project) on SharePoint server 2013, 2016

Hello everyone, in this article I will talk about the project in which I needed to highlight the elements of the list that matched by dates and categories. All of us go on vacation from time to time and someone may substitute us for the time of our absence, however, we need to see whether the period of time for vacation for employees in one category (for example, SharePoint developers) or not, for this task, I need a list of Calendar, columns Title, Category (lookup another list column), Start Time, End Time and Flag (hidden). I create several elements of the list (employees) with a start and end date, some leave vacation days.
The main advantage of this code is the use of C#, which means such features are available as Visual Web Part and JSLink (CSR).




Lets get started!

1. Open the visual studio 2012 or 2015 as run as administrator on SharePoint server (my example on SharePoint server 2013 OnPremise). 
2. Create an SharePoint server 2013 - Visual Web Part (name Project: "CalendarDatePeriods").



3. Set URL and Select a Farm Solution.



4. Add reference in the Project Microsoft.CSharp.

5. Open file "VisualWebPart1UserControl.ascx.cs".



6. Remove code "protected void Page_Load(object sender, EventArgs e){ }".

7. Add this code (Do not forget that the URL of the server and the name of the list may differ from yours!):
public class Item
 {
   public Int32 ID { get; set; }
   public string Title { get; set; }
   public string Category { get; set; }
   public DateTime StartTime { get; set; }
   public DateTime EndTime { get; set; }
 }
    //Class declaration array
    public class RootObject
    {
        public RootObject()
         {
            items = new List<Item>();
         }
            public List<Item> items { get; set; }
     }
         //Load page
         protected void Page_Load(object sender, EventArgs e)
          {
            //create int array
            List<int> ID_array = new List<int>();
            //GetListAllItems
            using (SPSite site = new SPSite("http://sp-test/sites/eng"))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;
                    string listUrl = web.ServerRelativeUrl + "/lists/Calendar";
                    SPList list = web.GetList(listUrl);
                    SPView view = list.Views["All Events"];
                    SPListItemCollection items = list.GetItems(view);
                    //Run class RootObject
                    RootObject objs = new RootObject();
                    foreach (SPListItem item in items)
                    {
                        //Add items to array
                        objs.items.Add(new Item
                        {
                            ID = Int32.Parse(item["ID"].ToString()),
                            Title = item["Title"].ToString(),
                            Category = item["Category"].ToString(),
                            StartTime = DateTime.Parse(item["Start Time"].ToString()),
                            EndTime = DateTime.Parse(item["End Time"].ToString()),
                        });
                    }
                    //Filter array DateTime periods
                    var array = objs.items;
                    for (int i = 0; i < array.Count - 1; i++)
                    {
                        for (int j = i + 1; j < array.Count; j++)
                        {
                            var p1 = array[i];
                            var p2 = array[j];
                            if (p1.Category != "1;#-" && p2.Category != "1;#-")
                            {
                                if (p1.Category != p2.Category)
                                    continue;
                                if (!(p1.StartTime > p2.EndTime || p2.StartTime > p1.EndTime))
                                {
                                    ID_array.Add(p1.ID);
                                    ID_array.Add(p2.ID);
                                    ID_array.Distinct().ToArray();
                                }
                            }
                        }
                    }
                    //Update List Item to DateTime period
                    for (int x = 0; x < ID_array.Count; x++)
                    {
                        using (SPSite osite = new SPSite("http://sp-test/sites/eng"))
                        {
                            using (SPWeb oweb = site.OpenWeb())
                            {
                                SPList olist = oweb.Lists["Calendar"];
                                SPListItemCollection oitems = list.GetItems(new SPQuery()
                                {
                                    Query = @"<Where><Eq><FieldRef Name='ID' /><Value Type='Int'>" + ID_array[x] + "</Value></Eq></Where>"
                                });

                                foreach (SPListItem item in oitems)
                                {
                                    item["Flag"] = "Yes";
                                    item.Update();
                                }
                            }
                        }
                    }
                }
            }
        }
8. Add reference in the lines where the code is highlighted in red, he will suggest.

using System;

using Microsoft.SharePoint;

using System.Collections.Generic;

using System.Linq;

using System.Web.UI;

9. If no errors are detected in the project, then do "Deploy Solution".
10. After the project is published on the server, IIS is restarted and you need to wait a couple of minutes if you need to make sure that the project has been published successfully, follow the link: http://your_sharepoint_server:port/_admin/Solutions.aspx and see your solution "calendardateperiods.wsp" status "Deployed". Then restart our list and click to "Property" -> "Edit Page":



"Add a Web Part" -> Categories "Custom" -> Add "CalendarDatePeriods - VisualWebPart1":



We added a web part and immediately saw that in the "Flag" column, for elements that match in categories and dates, the value is "Yes". This means our code is working successfully.



To highlight the color of elements whose values match, we use CSR (JSlink) and add it via the Content Editor Web Part. We need to add item in library "Site Assets" "jquery-2.1.3.min.js", then create JavaScript-file DateCSR.js in which you need to add the code allocated by our elements and "Flag" hiding column:

<script type="text/javascript" src="/sites/eng/SiteAssets/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
(function () { 
    var priorityFiledContext = {}; 
    priorityFiledContext.Templates = {}; 
    priorityFiledContext.Templates.Fields = {  
        "EventDate": { 
            "View": EventDateFiledTemplate 
        },
        "EndDate": { 
            "View": EndDateFiledTemplate 
        }
    }; 
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(priorityFiledContext);
})();
(function () { 
    var linkFiledContext = {}; 
    linkFiledContext.Templates = {}; 
    linkFiledContext.OnPostRender = linkOnPostRender;
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(linkFiledContext);
})();
function linkOnPostRender(ctx) 
{ 
    var linkCloumnIsEmpty = 1;
    for (i = 0; i < ctx.ListData.Row.length; i++) { 
        if (ctx.ListData.Row[i]["Flag"]) 
        { 
            linkCloumnIsEmpty = 1; 
            break; 
        } 
    } 
    if (linkCloumnIsEmpty) {
        var cell = $("div [name='Flag']").closest('th'); 
        var cellIndex = cell[0].cellIndex + 1;
        $('td:nth-child(' + cellIndex + ')').hide(); 
        $('th:nth-child(' + cellIndex + ')').hide(); 
    }
}
function EventDateFiledTemplate(ctx) {
    var Flag = ctx.CurrentItem.Flag;
    var EventDate = ctx.CurrentItem.EventDate;
    if (Flag == "Yes"){
       return "<span style='color :red'>" + EventDate + "</span>";
    } else {
          return "<span style='color :green'>" + EventDate + "</span>";
    }        
}
  function EndDateFiledTemplate(ctx) {
    var Flag = ctx.CurrentItem.Flag;
    var EndDate = ctx.CurrentItem.EndDate; 
    if (Flag == "Yes"){
         return "<span style='color :red'>" + EndDate + "</span>";
    } else {
        return "<span style='color :green'>" + EndDate + "</span>";
    }
}
</script>
"Add a Web Part" -> Category "Media and content" -> Add "Content Editor":



Add script "Content link" url, your JavaScript-file('/sites/eng/SiteAssets/DateCSR.js') and "Apply"



And we see our result, the most important thing is that this solution allows you to work with a large number of list items (I used more than 1000), without delays and timeouts. Additionally, you can modify this solution to suit your requirements; you can add an Event Reciever to create, modify, or delete list items with similar logic.


Happy Coding!