segunda-feira, Abril 07, 2014

How to use ProgId in SharePoint Custom Actions

This is somehow old topic but people(developers) keeps asking how to use the ProgId (PROGrammatic IDentifier) option in SharePoint Custom Action.

Some people that work with SharePoint don't have a clue this about this option and how to use it (MSDN documentation is not very good about this topic in SharePoint...).
There is a nice article talking about this subject in a declarative way, that can recommend a first view, link.

This article try to explain how we can create the Custom Action (not declarative or SSOM but JSOM) using the Parameter ProgId and how SharePoint handles this Parameter when this options is selected.

The first thing i can say is, the ProgId is about the structure of content we are working (XML) and not file type. 

The first thing we should know, the progid is about the XML structure of your document.
For this example we can create a normal Microsoft Word Document with some content, like is shown in the image bellow


After the content of the document is fill out, you should save the document as XML format as show in the image bellow.



For this example was created a Document with the Type "Word.Document" that is associated with Word. This is the type of document the XML structure is made, and this is the value the Custom Action will use to add the Action.


After this XML Structure validation you can upload the File to the Document Library and there you can see a little difference in the icon, Both selected documents has the type of associated (Word/Excel) but the file is XML, SharePoint assume the XML files (Examples2.xml and Book1.xml) with parameter "Word.Document" or "Excel.Sheet" that is coming from the XML and shown in the associated icon.

Create the Custom Action associated with ProgID 

After added the documents you can create your new Custom Action using “User Custom Action” SharePoint Object and define a custom action (Alert) to that will be associated with files from the Type “Word.Document”.


For this example i used a Tool created by processlynx AG (Swiss Company) that will be available in the SharePoint app store to create Custom Actions and Ribbons using Wizards that any Site Administrator could use (simple and useful).



If you need the ECMAScript example for this custom action you can look in the following Code example:

var newUserCustomAction = UserCustomActions.add();
newUserCustomAction.set_name('My ProgIDAction');
newUserCustomAction.set_title('My ProgIDAction');
newUserCustomAction.set_description('My ProgIDAction');
newUserCustomAction.set_location('EditControlBlock');
newUserCustomAction.set_sequence(0);
newUserCustomAction.set_registrationId('Word.Document');
newUserCustomAction.set_registrationType(3);
newUserCustomAction.set_url('javascript:alert(\'Test\')');

newUserCustomAction.update();

After the Custom Action is created the option will appear to the Menu Item as "My ProgID Action" and fires the alert "Test".


If you try to access to the Document with the extension “.Docx” the custom action don’t appear.


Question: I already saw this options in the file "docicon.xml", it's is related?
NO, it is not related. The ProgId Custom action is directly associated with Listitem field Data (ProgId and HTML File Type Columns).
The docicon.xml is used to manage (Open, read, etc...)documents and association with file types.

How this ProgId is Manage in SharePoint Data and Custom Action

The Custom Action ProgId is validated by the ListItem Column "ProgId" and "HTML File Type" and verify if the Identifier is the Same. 
For our example the Custom action will appear if the item has the field "Word.Document"
You can access to ListItem Data and fields/columns using the “SharePoint Client Browser for SharePoint 2010 and 2013” tool.


Question: Can we use the Registration type “File Type” for this?

The answer to this question is no, like the name say's is about the extension of the file and not about the ProgId associated to the file and metadata and Structure of the type of File.
"<?mso-application progid="Word.Document"?>"

Add Custom Action for FileType

The following example show the parameters we can use for add the custom action to a file type (XML), this option will make the action associated with File type but not with the structure of the XML. 


After this change, the the custom Action will be associated to all xml Files


Conclusion

The Option PRogID can be great feature when you are working with OPEN XML, Office Document and XML structure and you need to define specific Action for this type of Files.


Links that could help you:

"Processing Documents in Bulk Using SharePoint 2010 and Open XML 2.0"

Hope you like the article, 
Kind regards,
André Lage

sábado, Abril 05, 2014

How to Convert REST Call to SharePoint JSOM Object (ECMAScript)

This simple article tries to explain how we use REST Call and convert to SharePoint JSOM Object that retrieves the permissions associated with a Role, this can be also be used for management of permissions of items.

For this example i created a REST Call that retrieves the Permissions associated with a SharePoint RoleDefinition.
To get the SharePoint RoleDefinition associated using REST can be use the following url: "https://[site]/sites/Dev/_api/Web/RoleDefinitions"


For this example, i use the SharePoint RoleDefinition associated to "Full Control" and get the Permissions associated.

Method to call REST Call with Json (SP.BasePermissions

This example code uses SharePoint REST Calls to get the properties of RoleDefinition “Full Control” that includes a Object (SP.BasePermissions) in Json data.

$.ajax({
    url: "https://[site]/sites/Dev/_api/Web/RoleDefinitions(1073741829)",
    method: "GET",
    headers: { "Accept""application/json; odata=verbose" },
    success: function (data) {
        GetRights(data.d.BasePermissions);
    },
    error: function (xhr) {
        SP.UI.Notify.addNotification(xhr.status + ': ' + xhr.statusText, false);
    }
});

This REST call and returning JSON data can be visible using Fiddler tool as shown in the image below.




Method to convert REST json data to SharePoint JSOM (SP.BasePermissions)

The Method "GetRights(data)" uses the Json data to include in SP.BasePermissions() Object using Method "fromJson()".
After the Object is create it's listed the Permissions "SP.PermissionKind" and validate if the permissions are associated with Role "Full Control" using the Method "has".

Code Example:

function GetRights(rights) {
    var ValidateRights = new SP.BasePermissions();
    var permissionsid = '';
    var permissionsnames = '';
    ValidateRights.fromJson(rights);
    for (var prop in SP.PermissionKind.prototype) {
        permissionsid += prop + "\n";
        if (ValidateRights.has(parseInt(SP.PermissionKind.prototype[prop]))) {
            permissionsnames += prop + "\n";
        }
    }
    alert(permissionsid);
    alert(permissionsnames);

}

All the permissions are collected in a String and display in the alert message.



The List of Permissions can be Listed using the SP.PermissionKind Object.


PS: fullMask permision doesn't get all the permissions but only permissions lower then "Low=65535" in 32 Binary and High="32767" in 64 Binary from the SP.PermissionKind.prototype array list
Low(32):
65: 0000065535: 0000000000000001111111111111111: FullMask
High(64):
65: 0000032767: 0000000000000000111111111111111: FullMask

But the explanation of this values and how get the Realfullmask permission value will be explained in another article with the help of my colleague “Selim Gezgin”.

Hope you like this article, 
Kind regards, 
André Lage

terça-feira, Março 18, 2014

Create your Custom Content Type Picker Tree using REST

This is a simple article where you can create your own Content Type Tree view picker. 
I had the need to create a Content Type tree view picker when i was making a reference in my Custom Action solution "SharePoint 2013: Manage User Custom Actions App and Sandbox".
When we are creating a User Custom Action we can define wish Content Type will be associated. 
This can be very useful when we are creating Custom Ribbon to be associated at General Lists or specific Lists. 
In the near future i will create a article talking about the Ribbons and how we can manage using SharePoint Apps.
The Out of the Box steps to identify a Content Type ID is somehow hard or need to use some external tool like "SharePoint Client Browser for SharePoint 2010 and 2013" or "SharePoint Manager" or Powershell, here is a little description on how to get Ctype ID in the SharePoint Sites.

How to get Content Type ID using SharePoint Out of Box (example with a List):
  • Access to your  SharePoint List 
  • Access to List Settings
  • In "General Settings" > select "Advanced Settings"
  • Check "Allow management of content types?" to Yes


  • Select the Content Type "Item"
  • In the Url get the parameter "ctype", there should be the CT associated to the List



If you need more info about Content Types here you have some official links:
Content Type IDs

For testing purpose i have used JSTree plugin to create my tree view (you can Json Data to load the tree). 
PS: this JSTree plugin it is really complete and very well documented.

The main goal is to get the Content Types of the Site and Lists  (excluding the Hidden CT) as a Treeview and return to a Textbox.
Here a image example of the final output of the CT Picker.


How the solution Works 

The main goal is to create a Button that makes a call to a Modal Dialog to a Page that returns the Content Types of the Web and List as a Treeview. 


This solution have files to support the custom Content Type Picker: 

Page
  • CTPicker.aspx
Scripts
  • Jquery.js
  • jstree.js
  • Custom.js (where will be made the REST Calls or you can embedded in page)
Content
  • jstree.css
Create Content Type Picker Page

Create a Custom CTPicker.aspx page that has the controls for SharePoint Page and make the reference to the supporting files described before.



Create Content Type Picker Button and TextBox

Add the Button Picker "Browser" to Content Type Picker Page using Modal Dialog and Textbox where return the ID of the selected Content Type, for this you add a Script Script Editor Web Part and add the following example code;


Example Code:

<script>
function CTPickerDialog() {
    var options = {
        url: '../Shared%20Documents/CTPicker.aspx',
        title: 'Content Type Picker',
        showClose: true,
        showMaximized: true,
        allowMaximize: true,
        dialogReturnValueCallback: CloseCTPickerCallback
    };
    SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);
}
function CloseCTPickerCallback(result, target) {
    if (result == SP.UI.DialogResult.OK) {
        document.getElementById('URLTextBox').value = target;
    }
}
</script>
       <input type="submit" class="ms-input" value="Browser" id="BtnBrowseCTLocation" onclick="CTPickerDialog(); return false;" />


This code will open a modal dialog where you can select the existing content types in the existing Web.



Here is the example code to access your Content Types using REST:

<script>
$(document).ready(function () {
    LoadCTPicker();
});
function GetCurrentWebUrl() {
    return _spPageContextInfo.webServerRelativeUrl + ((_spPageContextInfo.webServerRelativeUrl.indexOf('/', _spPageContextInfo.webServerRelativeUrl.length - 1) !== -1) ? '' : '/');
}
function LoadCTPicker() {
    try {
        $('#CTPickerTree').on('select_node.jstree'function (e, data) {
            if (data.node.parent == "CT") {
                SP.UI.ModalDialog.commonModalDialogClose(1, data.node.id);
            }
            else if (data.node.parents.length == 4) {
                if (data.node.parents[1] == "Lists") {
                    SP.UI.ModalDialog.commonModalDialogClose(1, data.node.id);
                }
            }
        }).jstree(
           {
               "core":
                     {
                         "animation": 0,
                         "check_callback"true'data': [{
                             "id""Web""text": _spPageContextInfo.webTitle, "icon""../_layouts/15/images/smt_icon.gif?rev=32"'state': { 'selected'false'opened'true }, "children": [
                                 { "id""CT""text""Content Type""icon""../_layouts/15/images/pageLayoutHS.png"'state': { 'selected'false'opened'false } },
                                 { "id""Lists""text""Lists""icon""../_layouts/15/images/itgen.png?rev=26"'state': { 'selected'false'opened'false } }
                             ]
                         }]
                     }, "plugins": ["search""state""wholerow"]
           });

        RestLoad('CT');
        RestLoad('Lists');
    } catch (e) {
        SP.UI.Notify.addNotification('Request failed. ' + e.get_message() + '\n' + e.get_stackTrace(), false);
    }
}

function RestLoad(IDCT) {
    var webUrl = GetCurrentWebUrl();
    var Resturl = '';
    var CTID = '';
    var CTName = '';
    var CTImg = '';
    if (IDCT == 'CT') {
        Resturl = webUrl + "_api/web/ContentTypes?$select=Name,Id,Group&$orderby=Name&$filter=Group ne '_Hidden'";
    } else if (IDCT == 'Lists') {

        Resturl = webUrl + "_api/web/Lists?$select=Title,Id,ImageUrl";
    } else {
        Resturl = webUrl + "_api/web/Lists('" + IDCT + "')/ContentTypes?$select=Id,Name,Group&$filter=Group ne '_Hidden'"
    }

    $.ajax({
        url: Resturl,
        method: "GET",
        headers: { "Accept""application/json; odata=verbose" },
        success: function (data) {
            var TreePicker = $('#CTPickerTree').jstree(true);
            var ListsNode = TreePicker.get_node(IDCT);
            var jsonObject = data.d.results;
            for (var i = 0; i < jsonObject.length; i++) {
                if (IDCT == 'Lists') {

                    CTID = jsonObject[i].Id;
                    CTName = jsonObject[i].Title;
                    CTImg = jsonObject[i].ImageUrl;
                }
                else {
                    CTID = jsonObject[i].Id.StringValue;
                    CTName = jsonObject[i].Name + "(" + jsonObject[i].Group + ")";
                    CTImg = "../_layouts/15/images/pageLayoutHS.png";
                }
                TreePicker.create_node(ListsNode, {
                    id: CTID, text: CTName, icon: CTImg
                });
                if (IDCT == 'Lists') {
                    RestLoad(CTID);
                }
            }
        },
        error: function (xhr) {
            SP.UI.Notify.addNotification(xhr.status + ': ' + xhr.statusText, false);
        }
    });
}
</script>

Return Content Type Value to TextBox

After the selection of the Content Type the Modal Dialog is closed and returns the ID, for this case (0x0101).

Code Example:
 if (data.node.parent == "CT") {
                SP.UI.ModalDialog.commonModalDialogClose(1, data.node.id);
            }
            else if (data.node.parents.length == 4) {
                if (data.node.parents[1] == "Lists") {
                    SP.UI.ModalDialog.commonModalDialogClose(1, data.node.id);
                }
            }

Output of the Content Type selection:



With a little code and REST Call’s we can make a simple tree View J

Hope you like this article,
Kind regards, 

André Lage