Stefan Goßner

Senior Escalation Engineer for SharePoint (WSS, SPS, MOSS, SP2010) and MCMS

Blogs

How to use standard Toolbar dialogs in custom placeholder controls

  • Comments 2
  • Likes

MCMS 2002 offers a great flexibility and extensibility due to integration in the .NET framework and the ability to create custom console actions, rich controls and most important: custom placeholder controls.

MCMS 2002 already ships with 3 placeholder controls:

  • HtmlPlaceholderControl
  • SingleImagePlaceholderControl
  • SingleAttachmentPlaceholderControl

These placeholder control do not always meet the requirements of all users. But one major benefit of these shipped controls is that they are highly integrated with the the Web Author component. This means that Web Author contains classes and ASPX Web forms to extend the placeholder controls shipped with MCMS with dialogs to access the resource gallery and the channel structure. The most required features are the resource gallery browser to add an image or an attachment and the hyperlink dialog.

Custom placeholder controls often also have a requirement to access this repository content but MCMS documentation lacks any explanation on how to reuse the the build in classes and Web forms. To avoid the need to rebuild the same functionality from scratch this article will explain what to do to utilize the Web Author dialogs discussed above in your own custom placeholder controls.

 

Utilizing the Resource Gallery Browser

Which Placeholder type should be used?

This dialog is used in all shipped Placeholder Controls. But due to the fact that the controls work different the dialog verifies the underlaying placeholder type to ensure that the data is given back in the right manner. This feature is causing some problems when trying to reuse this dialog as it requires that one of the following placeholder types is used:

  • HtmlPlaceholder
  • ImagePlaceholder
  • AttachmentPlaceholder.

Other placeholder types (e.g. XmlPlaceholder) will not work with this dialog. If you need a resource gallery browser dialog with an XmlPlaceholder or a custom placeholder definition you need to create your own dialogs.

As the HtmlPlaceholder object is the most flexible of the above listed placeholder objects I will now focus on this placeholder type.

Where to store the data?

First we have to decide where to store the resulting resource link. I personally prefer to store it in a hidden or visible form field. But you could also decide to handle this is a different way. The solution listed below requires form fields for the following content:

  • MAPH_AttIconUrl (the Url for the generated icon for the attachment)
  • MAPH_AttLink (the Url of the actual Link to the attachment)
  • MAPH_AttName (the Link Text)

In addition to these elements I usually render an image tag to show the generated Icon of the URL.

How does the Resource Gallery browser work?

Web Author provides two client side JavaScript routines to access the Resource Gallery Browser:

  • WBC_launchAttachmentGallery
  • WBC_launchImageGallery

The difference of these two routines is that WBC_launchAttachmentGallery will show all kind of attachments, while WBC_launchImageGallery will only list image attachments.

The WBC_launchImageGallery routine takes the following 4 arguments:

  • query string containing the GUID of the current posting or the GUID of the current channel if it is a new posting (new postings do not have a GUID until being saved the first time)
  • name of the placeholder the Image/Attachment should be added too
  • the "type" of the placeholder control (used to identify how to give back the result)
  • flag to identify if local attachments are allowed or not. "false" indicates that only resource gallery items can be used.

The WBC_launchAttachmentGallery takes the following 6 arguments:

  • query string containing the GUID of the current posting or the GUID of the current channel if it is a new posting (new postings do not have a GUID until being saved the first time)
  • name of the placeholder the Image/Attachment should be added too
  • the "type" of the placeholder control (used to identify how to give back the result)
  • flag to define if local attachments are allowed or not. "false" indicates that only resource gallery items can be used.
  • flag to define if an Image Icon should be rendered for the attachment
  • flag to define if Video attachments are supported. (always false).

Web Author is not very flexible in the way it deals with the given placeholder types (3rd parameter). None of the placeholder types really works with flexible custom placeholder controls as the Web Author dialog always tries to "inject" the result into the controls it knows that must exist for the specific placeholder control. So we need to replace one of the routines Web Author provides to allow the dialog to work with our custom placeholder control. I have tested several different placeholder control types and found that the "ThinEditIE" type met my requirements most.

What needs to be coded?

The adjusted routine then needs to get the information where to store the resulting link As the resource gallery browser is not a modal dialog we cannot wait for it to come back and copy the result to the desired location. For the "ThinEditIE" placeholder control type this is being done in the following routines: WBC_setThinEditIEImage and WBC_setThinEditIEAttachment. These routines as implemented in Web Author require the ActiveX integrated with the standard HtmlPlaceholderControl. As this ActiveX control is not necessarily included in our custom placeholder control we need to modify these routines.

The problem is that we are not allowed to modify this routine in the Web Author JavaScript file shipped with MCMS as this would break the Microsoft Support Boundaries. A trick to bypass this problem is to register an updated version of the routine using the Page.RegisterStartupScript call. Below is the relevant modified routine for my MultiAttachmentPlaceholderControl which allows to add multiple attachments to one placeholder. Another sample that would utilize the ImageGallery and renders a slightly different version is my  ImageChangePlaceholderControl.

   string strJSWBC_setThinEditIEAttachment =
        "<SCRIPT language=\"javascript\">\n" + 
        "MAPH_DestPh = \"\";\n" + 
        "//\n" +
        "// Define new WBC_setThinEditIEAttachment function which will\n" +
        "// be used instead of the CMS predefined one.\n" + 
        "//\n" + 
        "    function WBC_setThinEditIEAttachment(strPhName, strURL, strDispText) {\n" +
        "        var strMyDispText = strDispText;\n" +
        "        if (strMyDispText == \"\") {\n" +
        "            strMyDispText = strURL;\n" +
        "        }\n" + 
        "        if (typeof document.all[\"NCPHRICH_\" + strPhName] != 'undefined') {\n" + 
        "            document.all[\"NCPHRICH_\" + strPhName].insertHtml(\"<a href=\\\"\" + strURL + "+
                         "\"\\\">\" + strMyDispText + \"</a>\");\n" +
        "        }\n" + 
        "        else\n" + 
        "        {\n" + 
        "            elements = strMyDispText.split('\"');\n" +
        "            if (typeof document.all[\"MAPH_AttIcon_\" + MAPH_DestPh] != 'undefined') {\n" +
        "                document.all[\"MAPH_AttIcon_\" + MAPH_DestPh].innerHTML=strMyDispText;\n" + 
        "            }\n" +
        "            if (typeof document.all[\"MAPH_AttLink_\" + MAPH_DestPh] != 'undefined') {\n" +
        "                document.all[\"MAPH_AttLink_\" + MAPH_DestPh].value = strURL;\n" +
        "            }\n" +
        "            if (typeof document.all[\"MAPH_AttIconUrl_\" + MAPH_DestPh] != 'undefined') {\n" + 
        "                document.all[\"MAPH_AttIconUrl_\" + MAPH_DestPh].value = strMyDispText;\n" +
        "            }\n" + 
        "            if (typeof document.all[\"MAPH_AttName_\" + MAPH_DestPh] != 'undefined') {\n" +
        "                document.all[\"MAPH_AttName_\" + MAPH_DestPh].value = elements[1];\n" +
        "            }\n" + 
        "        }\n" + 
        "    }\n" + 
        "\n" + 
        "</SCRIPT>";

   this.Page.RegisterStartupScript("WBC_setThinEditIEAttachment",strJSWBC_setThinEditIEAttachment); 

WBC_setThinEditIEImage needs to be extended and overloaded in the same way.

The black code lines listed above is the original code. The green lines contain an adjustment to avoid script errors, when the ActiveX Control is not present and the red lines are added to copy the properties into our hidden form fields. In some cases it might be interesting to have multiple different hidden fields for one custom placeholder control. Think about a MultipleAttachmentPlaceholderControl or an OnMouseOverImageChangePlaceholderControl where it will be necessary to pick multiple resources in the gallery. To deal with this I added the MAPH_DestPath variable which needs to be set before the resource gallery dialog is launched.

As discussed before the following elements need to be defined by your placeholder control code in authoring mode:

  • MAPH_AttIcon_... - an Image Tag to render the returned Attachment Icon
  • MAPH_DestPh_... - a hidden form field to take the URL to the Attachment
  • MAPH_AttIconUrl_... - a hidden form field to take the URL of the Attachmetn Icon
  • MAPH_AttName_... - a hidden form field to take the Attachment Text.

To create a button to call the Resource Gallery to add an attachment the following code is required:

    HtmlCode = "<INPUT TYPE=BUTTON value=\"Change...\" "+
               "onclick=\"MAPH_DestPh='"+sPhName+"_1';"+
                   "WBC_launchAttachmentGallery('wbc_purpose=Basic&"+
                       "NRMODE=Unpublished&WBCMODE=PresentationUnpublished&"+
                       "FRAMELESS=true"+channelGUID+"&NRNODEGUID="+
                       Page.Request.QueryString["NRNODEGUID"]+"', '"+
                       sPhName+"', 'ThinEditIE', true, true, false);"+
                   "return false;\">";

To create a button to call the Resource Gallery to add an image the following code is required:

    HtmlCode = "<INPUT TYPE=BUTTON value=\"Change...\" "+
               "onclick=\"MAPH_DestPh='"+sPhName+"_2';"+
                   "WBC_launchImageGallery('wbc_purpose=Basic&"+
                       "NRMODE=Unpublished&WBCMODE=PresentationUnpublished&"+
                       "FRAMELESS=true"+channelGUID+"&NRNODEGUID="+
                       Page.Request.QueryString["NRNODEGUID"]+"', '"+
                       sPhName+"', 'ThinEditIE', true);"+
                   "return false;\">"
 

Known problems:

If you have more than one Placeholder Control on one template which require different versions of the overridden script function then this will not work. You would have to ensure that both controls can work with the same Javascript routine.

Where can I find ready to use samples?

 

Utilizing the Hyperlink Dialog

The Hyperlink Dialog is a much more comfortable implementation as the resource manager. It is a modal dialog and it is possible to call it directly from JavaScript and wait what it returns. There is no need to implement such a hacky "callback" function as with the Resource Manager dialog.

Which Placeholder type should be used?

This modal dialog does not check the type of the placeholder being used. So there is no limitation in using the Hyperlink dialog. But if you need to use the Resource Manager also then you should utilize the HtmlPlaceholder with your placeholder control.

Where to store the data?

I personally prefer to store it in a hidden or visible form field. But you could also decide to handle this is a different way. The solution listed below requires form fields for the following content:

  • ICPH_Href (the Url to the selected posting)
  • ICPH_AltTag (the Description of the link)
  • ICPH_Target (the Target attribute of the Link)

How does the Hyperlink dialog work?

As described before the Hyperlink dialog is a modal dialog. It takes the following 4 parameters:

  • Old Hyperlink value
  • Old AltTag of the link
  • Old Target
  • Old Name attribute of the link (this is not used by my sample)

To pass these parameters they are concatenated to a single string separated with semicolon.

The dialog returns a string containing the same parameters in the same sequence also separated with semicolon.

What needs to be coded?

Below is a JavaScript routine which does all required things: create the argument string, call the Hyperlink dialog and process the return parameters. As mentioned before the values are stored in (hidden) form fields.

Below is the JavaScript routine I have written to do all required actions: collect the parameters, call the modal dialog and process the return value:

   string strJScmdCreateLink = "<SCRIPT language=\"javascript\">\n" +
      "function ICPH_createLink(phName) {\n" +
      "   var strHref = " + "  document.all[\"ICPH_Href_\" + phName].value;\n" +
      "   if (strHref == \"\") strHref = \"
http://\";\n" +
      "   var strTitle = " + "   document.all[\"ICPH_AltText_\" + phName].value;\n" +
      "   var strTarget = " + "  document.all[\"ICPH_Target_\" + phName].value;\n" +
      "   var strName = \"\";\n" +
      "\n" +
      "   var args = strHref + \";\" + strTitle + \";\" + strTarget + \";\" + strName;\n" +
      "\n" +
      "   var strPath = IDS_FRAMEWORK_NEW_VIRTUAL_PATH + \"/Dialogs/HLink/Hlink.aspx\";\n" +
      "\n" +
      "   var strDlgRet = window.showModalDialog( strPath, "+
                  "args, \"dialogWidth:450px;dialogHeight:265px;status:no;help:no\" );\n" +
      "\n" +
      "   if ( typeof(strDlgRet) == \"undefined\" ) " + 
      "      return;\n" +
      "\n" +
      "   if (strDlgRet == \"Cancel\")" +
      "      return;\n" +
      "\n" +
      "   var aAttributes = strDlgRet.split(\";\");\n" +
      "   document.all[\"ICPH_Href_\" + phName].value = aAttributes[0];\n" +
      "   document.all[\"ICPH_AltText_\" + phName].value = aAttributes[1];\n" +
      "   document.all[\"ICPH_Target_\" + phName].value = aAttributes[2];\n" +
      "\n" +
      "}</SCRIPT>";

   this.Page.RegisterClientScriptBlock("ICPH_createLink",strJScmdCreateLink);

The red lines contain the code preparing the arguments. The green lines contain the code to process the return value. The values are copied from and to (hidden) form fields. The bold black lines contain the code to call the modal Hyperlink dialog.

To create a button to call the Hyperlink Dialog to add a link to a posting the following code is required:

    HtmlCode = "<INPUT TYPE=BUTTON value=\"Edit Link\nAttributes\" "+
                   onClick=\"ICPH_createLink('"+sPhName+"')\">";

Where can I find ready to use samples?

Comments
  • Another control from Stephen Huen - the CMS Site Map web control displays channel structure ...

  • When developing a custom placeholder control an often requested feature is to be able to utilize the...