Thursday 20 February 2020

Multiple Download in SharePoint Classical libraries

Downloading Files

SharePoint Classical Library

I might be a bit late posting this but I found some users still use the classical style of SharePoint over the modern style. For them, one of the drawbacks of classical style is that only one file can be downloaded at a time. The bellow solution provides a way to download multiple selected documents in a SharePoint library through the user custom action.

There are many paid apps on the web for this and that is the reason why we do not get the solution for such a simple requirement.

The solution requires a custom action on the library where this is to be implemented, this can be added through SharePoint Designer using simple steps:
Open the Site in SharePoint Designer > from the Left Nav open the List and Libraries section > on the page select the Library where this solution needs to be implemented > under the List Custom Action need to add a new Custom action > to do this select the Custom Action button and from the dropdown select View Ribbon > in the Popup window add the Action Name as "Multiple Download" > in the Ribbon Location change the value from "Ribbon.Documents.Manage.Controls._children" to "Ribbon.Documents.Copies.Controls._children" > You could add the image link if you need to further decorate your Custom Action.


This is a simple Custom Action and nothing much happens when you click it, in order to customize the Custom Action you would need to further update the custom action's CommandUIExtension in order to do this you could go through any approach, but I'm showing you to update it through a simple c# console app.
create a C# console app in Visual Studio (2019 or any that you use) > Add SharePoint reference through NuGet Package Manager "Microsoft.SharePointOnline.CSOM" or simply add reference through Local SharePoint DLL files > Create ClientContext for the Site > add Credentials for the ClientContext > get the desired List/Library > Load the List's UserCustomActions > check for custom action with Name matching "Multiple Download" as mentioned earlier while creating the custom action through SharePoint designer > on the console write the current value of custom action's CommandUIExtension > store this value and modify the value's "CommandAction" and "EnabledScript" with respective values "javascript: bulkDownload();" and "javascript: enable();" these are actually the functions that would be called for this custom action, but these functions do not exist on any javascript file so you need to add a javascript link to the master page with the following javascript commands.

C# Code to edit the custom action:

`
Console.WriteLine("Started Main");
ClientContext ctx = new ClientContext();
SecureString password = new SecureString(); foreach (char c in ) { password.AppendChar(c); }
ctx.Credentials = new SharePointOnlineCredentials(password);
var web = ctx.Web;
ctx.Load(web);
ctx.ExecuteQuery();
Console.WriteLine();
Console.WriteLine(web.Title);
Console.WriteLine();
var list = web.Lists.GetByTitle();
ctx.Load(list);
ctx.ExecuteQuery();
Console.WriteLine();
Console.WriteLine(list.Title);

Console.WriteLine();
var customAntions = list.UserCustomActions;
clientContext.Load(customAntions);
clientContext.ExecuteQuery();
if (customAntions.Count > 0)
{
foreach (var customAction in customAntions)
{
if (customAction.Name != "Multiple Download")
{
#region FirstExecution
// // First execute below lise to get the current value.
Console.WriteLine(customAction.CommandUIExtension);
#endregion FirstExecution
#region SecondExecution
// // During next execution uncoment bellow two lines and execute
// customAction.CommandUIExtension = "<CommandUIExtension><CommandUIDefinitions><CommandUIDefinition Location=\"Ribbon.Documents.Copies.Controls._children\"><Button Id=\"{Same Value as Fetched}\" Command=\"{Same Value as Fetched}\" Image32by32=\"Image Url or blank\" Image16by16=\"Image Url or blank\" Sequence=\"0\" LabelText=\"Multi Download\" Description=\"\" TemplateAlias=\"o1\" /></CommandUIDefinition></CommandUIDefinitions><CommandUIHandlers><CommandUIHandler Command=\"{Same Value as Fetched}\" CommandAction=\"javascript:bulkDownload();\" EnabledScript=\"javascript:enable();\" /></CommandUIHandlers></CommandUIExtension>"; // Line one end
//customAction.Update(); 
#endregion SecondExecution
}
}
}
list.Update();
web.Update();
clientContext.Load(list.UserCustomActions);
clientContext.ExecuteQuery();
Console.WriteLine();
`

The Javascript file contents would be as follows:

`
function enable() {
    var items = SP.ListOperation.Selection.getSelectedItems();
    var itemCount = items.length;
    return (itemCount > 1);
}
function bulkDownload() {
    var items = SP.ListOperation.Selection.getSelectedItems();
    var itemCount = items.length;
    if (itemCount == 0) return;
    var context = SP.ClientContext.get_current();
    var site = context.get_site();
    var web = context.get_web();
    var list = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
    context.load(site);
    context.load(web);
    context.load(list);
    context.executeQueryAsync(
        Function.createDelegate(this, function () {
            var query = new SP.CamlQuery();
            var view = "";
            for (var i = 0; i < itemCount; i++) {
                view += `${items[i].id}`;
            }
            view += '
';            query.set_viewXml(view);
            var url = window.location.href;
            if (url.indexOf('?') > -1) {
                var urlQ = url.split("?")[1];
                var urlQQ = urlQ && urlQ.split("&");
                var folderUrl = '';
                for (var i = 0; i < urlQQ.length; i++) {
                    var a = urlQQ[i];
                    if (a && a.length && a.indexOf("RootFolder") > -1) {
                        folderUrl = a.split("=")[1];
                    }
                }
                if (folderUrl && folderUrl.length) {
                    query.set_folderServerRelativeUrl(decodeURIComponent(folderUrl));
                }
            }
            var itemsQuery = list.getItems(query);
            context.load(itemsQuery, 'Include(FileRef)');
            context.executeQueryAsync(
                Function.createDelegate(this, function () {
                    var itemsEnu = itemsQuery.getEnumerator();
                    while (itemsEnu.moveNext()) {
                        var currentItem = itemsEnu.get_current();
                        var downloadApi = web.get_url() + '/_layouts/15/download.aspx?SourceUrl=';
                        window.open(downloadApi + encodeURIComponent(currentItem.get_item('FileRef')), "_blank");
                    }
                }),
                Function.createDelegate(this, function (sender, args) {
                    console.log("Error retriving Items");
                })
            )
        }),
        Function.createDelegate(this, function (sender, args) {
            console.log("Error loading list");
        })
    );
}
`






















Thursday 23 November 2017

SharePoint Enterprise Search Center: Modified By Refiner

The modified by refiner is a very crucial refiner in almost every organization. It enables the administrators know who has modified the file and also it helps to ease the search.

The requirement for adding modified by refiner in the search center are as follows:
  • A Enterprise Search Center which can crawl the contents from all sites on the tenant.
  • The user must be the administrator of this Enterprise Search Center's Site collection.
To create the refiner:
  • Go to site Settings.
  • Click on Search Schema under the  Site Collection Administration section
  • In the Managed Properties section search for RefinableString
  • Select any Property which has no Mapped Crawled Properties (Say RefinableString55)
  • Edit the Managed Property
  • On the Edit Page scroll down to the Mappings to crawled properties section
  • Click the Add a Mapping.
  • Search for editor you would find "ows_q_USER _Editor" select it and it to the Mappings to crawled properties, and save the Managed Property.
To create a custom refiner filter (through Sharepoint Designer)
  • Go to the filters folder through All Files > _catalogs > masterpage > Display Templates > Filter.
  • Find the file Filter_Default and create a copy the file in the same location.
  • Edit the copied file, give a distinct name in the title tag say "Refinement Item Display Name".
  • Scroll to line number 264. where a function outputFilter is declared as "function outputFilter(refinementName, refinementCount, refiners, method, aClass, showCounts) {".
  • on the next line insert the following code:
if(refinementName.indexOf("|") !== -1){
refinementName = refinementName.split('|')[1];
                refinementName = refinementName.trim();
}
  • Save the page, now a new refiner filter is created.

To add the refiner:
  • Edit the Search Result Page were refiner is required.
  • Edit the Refinement Web-Part
  • In the properties for Search Refinement, click the Choose Refiners button
  • Select the RefinableString55 from the Available refiners and click add
  • Set the Display Name as "Modified By"
  • Select the Custom Refinement Item from the Display Template
  • Modify the rest three fields (viz Sort By, Sort Direction, Maximum refiner values) as per requirement.
  • Save the refiners by clicking on OK
  • Save the Edit refiner properties section on the left by clicking OK
  • Save the Page changes, check in the page and finally publish the page.
If you need snippets to understand better than plz reply, Thanks for reading. 

Sunday 18 December 2016

SharePoint list creation using REST api

This is a code blog to create a SharePoint List using REST API calls and jQuery scripting currently the only input is the list name and rest options are hard coded but can be easily be modified to fit your need

The supporting functions for the above code are

The second supportive function helps in removing spaces in the list name and capitalization of each words first letter(alphabet)
Please, do comment on any query related to the topic

Wednesday 12 October 2016

SharePoint 2013 (CSOM): Star Ratings Programmatically Adding Star-Rating or Re-Rating a List Item.

This Blog is about SharePoint's Star Rating Feature and how to change/read the Field Values Programmatically using CSOM. That is basically Rating or Re-rating the item.

What can be done by the following code is :
  • Select a list (should have ratings enabled).
  • Select the Item form the list.
  • Select a Site user whom you need to rate.
  • Finally the main code
    • To change the user's rating.
              OR
    • To rate the item.
  • To view the field values.

Most of the aspects of Star Rating are being covered but how Un-rate is intentionally not being covered as the user cant un-rate the item in SharePoint out of the box. If you want a code to un-rate the item please comment about it, I would Post it later.  
Note: Please use it for Ethically.
Code:
1. Console apps main Program code.
                 
2. Code of the FetchList Class.
                
3. Code of FetchItem class.
                
4. Code of SetUser class.
               
5.  Code to change the ratings packed in ChangeRating class.
                
Please feel free to comment on any related issues.