Wednesday, 30 March 2016

Fix SharePoint scrolling problems for Chrome

<script>
    function FixWorkspace() {
        // if you are using a header that is affixed to the top (i.e. SharePoint Ribbon) put the ID or class           // here to change the workspace height accordingly.
        var header = '#myHeader';
        var width = $(window).width();
        var height;
        if ($(header).length) {
            height = $(window).height() - $(header).height();
        } else {
            height = $(window).height();
        }
        $('#s4-workspace').width(width).height(height);
    }

    $(document).ready(function () {
        FixWorkspace();
    });

    $(window).resize(function () {
        FixWorkspace();
    });
</script>

Wednesday, 17 February 2016

SharePoint COM to get all image with more than specified size.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
namespace the the ConsoleApplication1
{
    class Program
    {
        static void Main ( string [] args)
        {
            string Webappurl = "http://abc.com/sites/123" ;
            using ( var ctx = new ClientContext (Webappurl))
            {

                ListItemCollectionPosition Pos = null ;
                while( true )
                {
                    DocumentsList list  = Ctx.Web.Lists.GetByTitle ( "Test" );
                    ListItemCollection results = documentsList.GetItems (CreateAllFilesQuery (pos));
                    ctx.Load (documentsList);
                    Ctx.Load (results, items => Items.ListItemCollectionPosition, items =>Items.Include (item => item [ "File_x0020_Size" ], item => item [ "FileRef" ]));
                    ctx.ExecuteQuery ();
                    // Get item position
                    pos = results.ListItemCollectionPosition;
                    foreach( var result in results)
                    {
                     double size = ConvertBytesToMegabytes ( Convert .ToInt64 (result [ "File_x0020_Size" ]));
      Console .WriteLine (result [ "FileRef" ] + "->" + Size.ToString () + "MB" );
                    }
                    // End where there is no items available
                    if(pos == null )
                        break ;
                }
                Console .Read ();
            }
        }

        public static CamlQuery CreateAllFilesQuery (ListItemCollectionPosition pos)
        {
            var qry = new CamlQuery ();
            string Rowlimit = "100" ;
            // Query to get only files and not folder (FSObjType will be 1 for folder)
            qry.ListItemCollectionPosition = pos;
            // 2097152 - which specified to get only images with more than 2MB of size
    qry.ViewXml =  "<View Scope = \" RecursiveAll \ "> <ViewFields> <FieldRef Name = 'FileRef' />                           <FieldRef Name = 'File_x0020_Size' /> </ ViewFields> <RowLimit>" + Rowlimit + "</                       RowLimit> <Query> <Where> <And> <Eq> <FieldRef Name = \ "FSObjType \" /> <Value                         Type = \ "Integer \"> 0 </ Value> </ Eq> <And> <Geq> <FieldRef Name = \                                 "File_x0020_Size \ " /> <Value Type = \ "Lookup \"> 2097152 </ Value> </ Geq> <Or>                     <Eq> <FieldRef Name = \ "File_x0020_Type \" /> <Value Type = 'Text'> jpg </ Value>                     </ Eq> <Or> <Eq> <FieldRef Name = \ "File_x0020_Type \" /> <Value Type = 'Text'>                       png </ Value> </ Eq> <Eq > <FieldRef Name = \ "File_x0020_Type \" /> <Value Type =                     'Text'> jpeg </ Value> </ Eq> </ Or> </ Or> </ And> </ And> </ Where> < / Query> </                     View> " ;
            return qry;
        }

        public static double ConvertBytesToMegabytes ( long bytes Download now)
        {
            return (bytes Download now / 1024f) / 1024f;
        }
    }
}

Wednesday, 5 August 2015

Passing Query string from SharePoint to the App Web

It has been almost two years since 2013, now I'm back... cheers..!

SharePoint 2013 uses set of tokens for use in apps for SharePoint. Like,

{StandardTokens}

which holds set of other tokens
             SPHostUrl={HostUrl}&
             SPAppWebUrl={AppWebUrl}&
             SPLanguage={Language}&
             SPClientTag={ClientTag}&
             SPProductNumber={ProductNumber}

But in case if you need any custom query string that should be used within your app from sharepoint. That is very difficult.

Here comes the approach called "Client Web Part"

When you develop any app in SharePoint, it will be in a separate domain or may in an external enviroment. SharePoint will redirect to the resective URL.

So if you want to display your app inside any page on the SharePoint,  here comes the approach called Client Web Part.

Client web Part used to hold your app in SharePoint pages inside an iFrame and it can be created only inside the Host Web of App.

When you are adding a Client web Part to the Host web inside the solution, you will be able to see an Element.xml file with some markup.


So if you want to define your custom property here, just use the the format in content tag,

<Content Type="html" Src="~appWebUrl/Pages/Default.aspx?{StandardTokens}&amp;CustomProp1=_CustomProp1_&amp;CustomProp2=_CustomProp2_" />

and expand the properties tag to specify each custom property,

<Properties>
<Property Name="CustomProp1" Type="string" RequiresDesignerPermission="true" DefaultValue="Propert1Value
                WebCategory="AppPart Properties"
                WebDisplayName="Custom Property 1">
</Property>
<Property Name="CustomProp2" Type="int" RequiresDesignerPermission="true" DefaultValue="1" 
                WebCategory="AppPart Properties"
                WebDisplayName="Custom Property 2">
</Property>
</Properties>      

So if you save and deploy the app, the URL and  all the query string will be the value for your iframe src 

We can able to add this client web part to any page in SharePoint by editing the page and adding the App Part that deployed in above step.

So here comes the question how we can add dynamic value to your query string and use it in your app code.

So add script editor web part to the SharePoint just below the Client web part and use the below js sample to replace the existing custom query string value with your dynamic value.

Here in this example, i'm replacing the custom property value "Propert1Value" with the current page url to the iframe src attribute

<script>
var iFramesElement = document.getElementsByTagName("iframe");
for(i = 0; i< iFramesElement .length; i++)
{
    var clientiFrame=iFramesElement [i];
    var propertyName="CustomProp1";
    if(clientiFrame.src.indexOf(propertyName) != -1)
    {             
        var propertyValue = getParameterByName(propertyName);
        if(propertyValue  != null)
        {
            clientiFrame.src=clientiFrame.src.replace(propertyValue,window.location.href);
        }
    }
}

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
</script>

So this query string can be obtained inside the app i.e. in the app page load code.

In the same way you can pass any value to the app by using Client Web Part iFrame.

Happy SharePointing...!!!!!!!!


Sunday, 22 September 2013

Working with BeforeProperties and AfterProperties on SPItemEventReceiver

I always forget this and when I come to create a new SharePoint Event Receiver I wonder why the BeforeProperties or AfterProperties are sometimes not populated.

Consider an example, we need to handle the ItemUpdating event for a document library and prevent a user from changing a certain column.  The code might look like this:
public override void ItemUpdating(SPItemEventProperties properties)
{
 if (properties.BeforeProperties["Title"] != properties.AfterProperties["Title"])
    {
        properties.Cancel = true;
        properties.ErrorMessage = "This column cannot be changed";
    }
}
For a document library, this works just fine.  For documents, Before and After properties are guaranteed for post events, such as ItemUpdating and ItemUpdated, but Before properties are not available for post events on list items.

The Before/After properties works differently between LIST and DOCUMENT LIBRARY

SharePointList

Event
BeforeProperties
AfterProperties
ListItem
ItemAdding
Null
New  Value
Null
ItemAdded
Null
New Value
New Value
ItemUpdating
Null
Changed Value
Original Value
ItemUpdated
Null
Changed Value
Changed Value
ItemDeleting
Null
Null
Original Value
ItemDeleted
Null
Null
Null

 
SharePointDocument Library
Event
BeforeProperties
AfterProperties
ListItem
ItemAdding
Null
Null
Null
ItemAdded
Null
Null
New Value
ItemUpdating
Original Value
Changed Value
Original Value
ItemUpdated
Original Value
Changed Value
Changed Value
ItemDeleting
Null
Null
Original Value
ItemDeleted
Null
Null
Null

Properties.ListItem refers to the current list item values at this point in the event. 
Original Value refers to the value which is already existing in the content DB.
New Value refers to the value which is being added newly in add event.
Changed Value refers to the value which is being updated in Update event.
So, if we go back to our original problem listed above.  How can we prevent a user from changing a certain column for an item in a list event?  From the list table, you can see if we hook into the ItemUpdating event, we can compare the current item’s value (properties.ListItem) to the AfterProperties value.  The code would look like this:
// SPListItem item= properties.ListItem;
// String oldvalue=item[“Title”].ToString();
if (properties.ListItem["Title"] != properties.AfterProperties["Title"])
{
    properties.Cancel = true;
    properties.ErrorMessage = "This column cannot be changed";
}
Hope it Helps.. 


Thursday, 19 September 2013

correlation tokens in SharePoint workflow

Correlation Token:
  • Is way to group together a set of related activity.
  • worflowTokem - created by default in workflows used to group together the whole workflow.
  • Is a unique identifier that enables mapping between the objects in a workflow and the environment that is hosting the Windows Workflow Foundation (WF) workflow runtime.
  • It can be referred for uniquely identifying each instance of a workflow, modification or task.  When SharePoint initiates a workflow, it does not have a unique set of objects. Instead, if one instance of the workflow is already running when the second initiates, the second will reuse objects from the first.
  • Correlation token properties ensure that the single activity object is operating on the correct workflow instance and accessing the correct details about the workflow.

You will have a separate correlation token for the each of the following:

  • The workflow itself.
  • Each task you need to reference in the workflow

Declare the correlation token for the workflow in the OnWorkflowActivated activity. Then, for each activity that affects the entire workflow, bind that activity’s correlation token to the correlation token of the OnWorkflowActivated activity.

Tuesday, 3 September 2013

Setting Workflow Status to Custom Values

If you consider workflow in SharePoint 2010,it will have certain default status such as In Progress,Completed,Failed on Start,Completed,etc..

but in case if we want custom values for the workflow that would enhance the look of the workflow status to the end user in more convenient way.

Steps Involved:

Note: I'm using Sequential Workflow,This can be used for state machine workflow also.
  1. Create a sequential workflow and select the type as List Workflow,
  2. So the Project explorer will look like,

    3. Edit the Element.xml file and add  the below custom tags just above the ending “Metadata” node,

    <ExtendedStatusColumnValues>
    <StatusColumnValue>Pending</StatusColumnValue>
    <StatusColumnValue>Approved</StatusColumnValue>
    <StatusColumnValue>Rejected</StatusColumnValue>
    </ExtendedStatusColumnValues>
    4. Let the logic in .cs file be as it is,now add a SetState activity form the toolbox and name it as setState1(any name you prefer) and this must be placed as the last activity in the workflow,then only it will work based on logic provided in all the other states located above.
    5.In the propeties of setstate activity give a name for MethodInvoking property,let it be "setState1_MethodInvoking"

    6. The integer value of the MAX is 15. From 0 to 14, the numbers are reserved for default values like InProgress, completed, error occurred etc. In Element.xml, the value of the first custom value will be 15 and then it will keep on increasing by 1. 
     So the values represented will be like,
    SPworkflowStatus.Max------>Pending
    SPworkflowStatus.Max+1------>Approved
    SPworkflowStatus.Max+2------>Rejected

    7. Build and Deploy to enjoy the result.



Wednesday, 21 August 2013

Differences between Event Receivers and SharePoint Workflows




Event Receivers
Workflows
1.
Can be Executed Synchronously or Asynchronously.
Can be Executed only Asynchronously which means when an action is completed.

2.
Since it is executing in both modes we can cancel the action which is going to be occurred.
Once an action is started you cannot stop the operation.

3.
Can't be initiated manually
Can be initiated automatically or manually.

4.
Logs are not possible
Log can be written in workflows

5.
Can be used in actions that needs to be completed immediately based on logic (Immediate execution)
Can be used in actions that will take even months or years to complete.( Long running)

6.
no state is maintained
Workflow maintains state.

7.
Triggered on Synchronous or Asynchronous events.
Triggered only on Creation/Change/deletion events.