Sharepoint 2010 Ribbon Control and Rich Text Editor
// July 26th, 2010 // Uncategorized
Im currently lucky enough to be working on the 2nd largest Sharepoint 2010 deployment in the world currently! It really has been a wonderful opportunity to be exposed to some of the new Sharepoint 2010 functionalities as well as interfaces, API’s, SDK etc.
One of the latest modules for the Project is the media library ribbon control, a control which manipulates the way our users will upload images to Sharepoint.
The OOTB functionality allows users to upload images from multiple sources namely:
1) From Sharepoint
2) From Computer
3) From Address
We needed new functionality to be able to upload images using a silverlight control (activex prevents our users using Firefox which is a big problem for the 70,000 odd users!). The silverlight control also checks for banned words which wasnt available to us. The key functionality here is:
1) Replace the existing “Upload Picture” split button with ours
2) Call the Upload Image Dialog
3) Instantiate the callback method which inserts the image back into the Rich Text Editor
First up, we need to create a new module in Visual Studio 2010. This is the module which act as a replacement button for OOTB “Upload Picture” split button. Im not going to go through doing this as this is basic VS2010 functionality. The new elements.xml file is as below:
| XML | | copy code | | ? |
| 01 | |
| 02 | <?xml version="1.0" encoding="utf-8"?> |
| 03 | <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> |
| 04 | <CustomAction |
| 05 | Id="Ribbon.Image.Image.Edit.ReplacementButton" |
| 06 | Location="CommandUI.Ribbon" |
| 07 | Rights ="EditListItems" > |
| 08 | <CommandUIExtension> |
| 09 | <CommandUIDefinitions> |
| 10 | <CommandUIDefinition |
| 11 | Location="Ribbon.EditingTools.CPInsert.Media.Image"> |
| 12 | <SplitButton |
| 13 | Id="Ribbon.EditingTools.CPInsert.Media.Image.ReplacementButton" |
| 14 | Alt="$Resources:core,ButInsertImageAlt;" |
| 15 | Command="InsertImage" |
| 16 | CommandMenuOpen="InsertImageMenuOpen" |
| 17 | CommandMenuClose="InsertImageMenuClose" |
| 18 | Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-176" Image16by16Left="-224" |
| 19 | Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-192" Image32by32Left="-448" |
| 20 | LabelText="Insert Image" |
| 21 | MenuAlt="$Resources:core,ButInsertImageMenuAlt;" |
| 22 | Sequence="10" |
| 23 | TemplateAlias="o1" |
| 24 | ToolTipTitle="$Resources:core,cui_ButInsertImage;" |
| 25 | ToolTipDescription="$Resources:core,cui_STT_ButInsertImage;"> |
| 26 | <Menu Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Replacement"> |
| 27 | <MenuSection |
| 28 | Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.Replacement" |
| 29 | DisplayMode="Menu" |
| 30 | Sequence="10"> |
| 31 | <Controls Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.Controls.Replacement"> |
| 32 | <Button |
| 33 | Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromComputer.Replacement" |
| 34 | Sequence="10" |
| 35 | Alt="$Resources:core,ButFromComputerAlt;" |
| 36 | Command="UploadPictureReplacement" |
| 37 | LabelText="$Resources:core,ButFromComputer;" |
| 38 | ToolTipTitle="$Resources:core,cui_STT_title_ButInsertImageFromComputer;" |
| 39 | ToolTipDescription="$Resources:core,cui_STT_ButInsertImageFromComputer;"/> |
| 40 | <Button |
| 41 | Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromMediaLibrary.Replacement" |
| 42 | Sequence="15" |
| 43 | Alt="$Resources:core,ButFromAddressAlt;" |
| 44 | Command=".MediaLibrary.Ribbon.PerformInsert" |
| 45 | LabelText="From Media Library" |
| 46 | ToolTipTitle="Insert Picture from Media Library" |
| 47 | ToolTipDescription="Insert a picture from Media Library onto the page"/> |
| 48 | <Button |
| 49 | Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromAddress.Replacement" |
| 50 | Sequence="20" |
| 51 | Alt="$Resources:core,ButFromAddressAlt;" |
| 52 | Command="InsertImageWeb" |
| 53 | LabelText="$Resources:core,ButFromAddress;" |
| 54 | ToolTipTitle="$Resources:core,cui_STT_title_ButInsertImageFromAddress;" |
| 55 | ToolTipDescription="$Resources:core,cui_STT_ButInsertImageFromAddress;"/> |
| 56 | <Button |
| 57 | Id="Ribbon.EditingTools.CPInsert.Media.Image.Menu.Image.FromSharepoint.Replacement" |
| 58 | Sequence="25" |
| 59 | Alt="From Sharepoint" |
| 60 | Command="InsertImageSharepoint" |
| 61 | LabelText="From Sharepoint" |
| 62 | ToolTipTitle="Insert Image from Sharepoint" |
| 63 | ToolTipDescription="Insert an image using the asset picker tool"/> |
| 64 | |
| 65 | </Controls> |
| 66 | </MenuSection> |
| 67 | </Menu> |
| 68 | </SplitButton> |
| 69 | </CommandUIDefinition> |
| 70 | </CommandUIDefinitions> |
| 71 | <CommandUIHandlers> |
| 72 | <CommandUIHandler |
| 73 | Command="UploadPictureReplacement" |
| 74 | CommandAction= "javascript: |
| 75 | var id='?RootFolder=&DisplayType=uploadimages'; |
| 76 | uploadImageDialog(id); |
| 77 | " /> |
| 78 | |
| 79 | </CommandUIHandlers> |
| 80 | </CommandUIExtension> |
| 81 | |
| 82 | </CustomAction> |
| 83 | </Elements> |
| 84 | |
| 85 |
Notes:
1) Line 11: The Location specified is exactly the same as the one listed in the CMDUI.xml file (This is the file which lists the OOTB ribbon controls). This is ensures we replace the ribbon control not create a new one.
2) Line 22: Use the same sequence number to replace the button
3) Line 36: The method name which invokes the javascript. See Line 73
Right, so first thing to remember. Everytime you deploy the feature or change it in any way, you need to clear the cookies/cache. Your changes wont be seen otherwise. That took me about 5 hours of work right there!!
Now, for the javascript. We use the ECMAScript opendialog functionality where we specify our own callback function which will be called one we’re done with the upload functionality (not covered here. this functionality would be part of the dialog you launch).
| Javascript | | copy code | | ? |
| 01 | |
| 02 | openDialog: function (params) { |
| 03 | params = $.extend({ |
| 04 | id: "", |
| 05 | allowMaximize: true, |
| 06 | showClose: true, |
| 07 | callBackFunction: CallDETCustomDialog |
| 08 | }, params); |
| 09 | var siteurl = SP.PageContextInfo.get_webServerRelativeUrl(); |
| 10 | var options = SP.UI.$create_DialogOptions(); |
| 11 | if (siteurl == "/") { |
| 12 | options.url = params.url + params.id; |
| 13 | } |
| 14 | else { |
| 15 | options.url = siteurl + params.url + params.id; |
| 16 | } |
| 17 | options.allowMaximize = params.allowMaximize; |
| 18 | options.showClose = params.showClose; |
| 19 | options.width = params.width; |
| 20 | options.height = params.height; |
| 21 | options.dialogReturnValueCallback = params.callBackFunction; |
| 22 | SP.UI.ModalDialog.showModalDialog(options); |
| 23 | //SP.UI.ModalDialog.showWaitScreenWithNoClose(); |
| 24 | } |
| 25 | |
| 26 | // upload Image Dialog |
| 27 | function uploadImageDialog(id) { |
| 28 | $(this).openDialog({ |
| 29 | id: id, |
| 30 | url: "/_layouts/FileUpload/BasicUpload.aspx", |
| 31 | callBackFunction: InsertImageUploadedCallback |
| 32 | }); |
| 33 | } |
| 34 | |
| 35 | function InsertImageUploadedCallback(dialogResult, returnValue) { |
| 36 | |
| 37 | if (dialogResult == "OK") { |
| 38 | //Delete any existing content the range contains |
| 39 | RTE.Cursor.get_range().deleteContent(); |
| 40 | |
| 41 | //Get a handle on the current range of the cursor inside the RTE |
| 42 | var rng = RTE.Cursor.get_range().$3_0; |
| 43 | |
| 44 | //Create a DOM object representing the image |
| 45 | var d = rng.ownerDocument; |
| 46 | var a = d.createElement("img"); |
| 47 | //a.setAttribute("id", uniqueid); |
| 48 | a.setAttribute("src", returnValue); |
| 49 | |
| 50 | //Insert the image into the RTE at the current cursor range position |
| 51 | SP.UI.UIUtility.insertAfter(a, rng); |
| 52 | } |
| 53 | if (dialogResult == "Replace") { |
| 54 | |
| 55 | var $v_0 = RTE.Cursor.getSelectedImage(); |
| 56 | if (!$v_0) { |
| 57 | |
| 58 | } |
| 59 | if ($v_0.complete || $v_0.readyState === 'complete') { |
| 60 | $v_0.setAttribute("src", returnValue); |
| 61 | } |
| 62 | |
| 63 | } |
| 64 | } |
| 65 | |
| 66 |
Notes:
1) Line 27: UploadImageDialog launches our dialog with the appropriate callbackfunction
2) Line 21: Is set to InsertImageUploadedCallback
3) Line 37 – Line 51: Use this to insert a new image into the rich text editor.
4) Line 53 – Line 63: Use this to replace the currently selected image
So once we have this functionality we can now create a new aspx page which would be invoked using this dialog. We called ours “basicupload.aspx”.
Within this page’s OnSave method we implemented some javascript which would then invoke the callback method and pass back the image url to the callback method. This is acheived using the following code:
| Javascript | | copy code | | ? |
| 1 | |
| 2 | if(containerState == ContainerState.UploadImages) |
| 3 | this.Page.ClientScript.RegisterStartupScript(this.GetType(), "InsertImageUploadedCallback", "commonModalDialogClose('OK', '" + oWeb.Url + "/" + oImageItem.File.Url + "');", true); |
| 4 | else |
| 5 | this.Page.ClientScript.RegisterStartupScript(this.GetType(), "InsertImageUploadedCallback", "commonModalDialogClose('Replace', '" + oWeb.Url + "/" + oImageItem.File.Url + "');", true); |
| 6 | |
| 7 |
Notes:
The code shown above passes back the uploaded image file url back to the callback method based on whether we are replacing or uploading a new image.










Hi,
Thanks for this article, verry interesting and useful,
I tried to do something like you on an other action in the ribbon but i’ve got a js error on my page when i tried to acces to the CPInsert menu after deploying my feature,
Maybe you could tell me what wrong i’m doing…
The Button is EditingTools.CPInsert.Links.UploadFile,
this is my code :
Thanks a lot for your help !