August 12, 2014

Paste From Word Plugin:UI Extension

In Tridion 2011 the paste-special feature doesn't work perfectly. The ask was to copy/paste articles directly from the Microsoft Word, as Tridion OOB feature was not working so client's whole process was impacted. 

so we come up with this plugin  Paste Special Cross Browser Extension  which helped them to copy paste from word without those problematic word tags. it was written on top of  excellent CKeditor (without reinventing :) )
Plugin Code Structure:


  • CKeditor
  • Client
  • Config

With this plugin it is possible to paste content from Microsoft Word and maintain original content formatting and also paste as a plain text. The plugin adds the Paste from Word and Paste as Text button which makes it possible to paste clipboard data. This Paste Special Cross Browser Extension removes the existing Paste Special Functionality from the CME/Experience Manager and replaces it with a cross browser solution.

CKeditor: Contains CKeditor’s java script, CSS and HTML files (PasteAsText and PasteFromWord)  

Client: Contains PasteSpecialFormatArea javascript file that is the main javascript file where we define the command for the UI extension buttons.

For e.g.

Extensions.PasteAsText.prototype.isAvailable = function PasteAsText$isAvailable(target){              
    return true;
};
Extensions.PasteAsText.prototype.isEnabled = function PasteAsText$isEnabled(target){
    return true;
};

Extensions.PasteAsText.prototype._execute = function
PasteAsText$_execute(target)
{
popUpData="";
var host = window.location.hostname;
var newwindow = window.open("http://"+host+"/WebUI/Editors/PasteSpecialFormatArea/ckeditor/PasteAsText.html",'FormatArea','height=356,width=750');
     
var unloadFunc = function () { setEditorData(); };
if (newwindow) { // null if a pop-up blocker does not create the window
if (newwindow.addEventListener) {
newwindow.addEventListener('unload', unloadFunc, false);
} else {
newwindow.attachEvent('onunload', unloadFunc);
}
}

function setEditorData()
{
if(popUpData != "")
{
target.editor.applyHTML(popUpData);
}
}
};

function setPopupText(data)
{
popUpData = data;
}


Config: Contains the config file that has the configuration for the UI extension button and also all the dependency files path.

Deployment
  
1.     Copy the plugin folder “BCGFormatArea” inside the Editor folder in the Tridion installation path “InstallationPath\Tridion\web\WebUI\Editors”.

2.     Now in IIS create a virtual directory with the name “BCGFormatArea” inside Editor Directory as shown in the below screen shot.


3.     Now open the “System.config” file in the path “C:\Program Files (x86)\Tridion\web\WebUI\WebRoot\Configuration” and add a new editor configuration setting inside the “<editors default="CME">” element tag 


Here is the configuration setting:

<editor name="BCGFormatArea" xmlns="http://www.sdltridion.com/2009/GUI/Configuration">
<installpath> InstallationPath\Tridion\web\WebUI\Editors\BCGFormatArea\</installpath>
<configuration>config\BCGFormatArea.config</configuration>
<vdir>BCGFormatArea</vdir>
</editor>
 Note: Make sure the virtual directory name in the editor setting <vdir> is matched with the created one.
4.     Now make the IIS reset and open the CMS you will see two new “Paste As Text” and “Paste From Word” buttons added in the component view as shown in the below screenshot.



5.     Click the button to open the popup.

How it works:

Most intersting methods to notice  are _execute, setEditorData, setPopupText.

_execute: It first trigger the popup "PasteAsText.html". which in turns intialize the ckEditor. 

so now when user enter the content in the text box and press ok, following code gets executed:

 function GetContents() {
                // Get the editor instance that you want to interact with.
                var editor = CKEDITOR.instances.editor1;                
window.opener.SetPopupText(editor.getData());
closeWin();
            }

if you notice it just set the text via calling formatArea's SetPopupText method. 
and closeWin(), which again triggers the unloadFunc method of FormatArea. which sets the data to the CME textbox.

July 24, 2014

Tridion CMIS connector for aDAM - External content Library

We had a requirement to connect aDam with Tridion 2013. I started the POC after reading docs, posts       ( from Eric & Bart).

External Content Library aka ECL was introduced in Tridion 2013 to connect external content/multimedia sources with Tridion Interface e.g youtube, vimeo, flicker, facebook, aDam, Media Manager. Its a great feature.
When content starts displaying in the CME, it looks like native components.

Prerequisite

Tridion: 
  • Assembly: Tridion.ExternalContentLibrary.V2
  • Admin Privilege
Terminologies:

Mount Point: Tridion folder which you mount to access external content. all external content is listed under this folder. 

ECL Stub Schema: When a provider is mounted in Tridion, it generates a Stub schema , and all stub components (from external sources) displayed in this mountPoint are type of this stub schema.(because you need a schema to represent a component in Tridion)

Interface: Interfaces in following figure are used in development.








aDam
  • aDam Studio installed
  • Rest Service to access its content - in aDam 5.0 there was no open API/oData etc were available. In current 5.0 version there is no official API comes with aDam installer. but aDam guys provided this Sample Rest Service which can be extended, as i discussed with them, API will be released in next versions.
Few Terminologies
  • Classification: its basically taxonomy of aDam, and content in CME would also categorized by classification. 
  • Record: Assets are called Record in aDam. 
Development.  
Lets move to development side, i will keep code short as possible with a view to brevity and clarity.

Here i am declaring that my connector will show two types of item in the interface, first one is a folder, which is collection of items, in aDam case its Classification. Rest methods are standard implementations.

AdamEclProvider : IContentLibrary 
it initialize the AddIn, this is the class which is configured in ExternalContentLibrary.xml.

[AddIn(
    "AdamProvider",
    Description = "Adam External Content Library Provider",
    Publisher = "Raj Future Technologies",
    Version = "1.0.0.0")]
    public class AdamEclProvider : IContentLibrary

    {
public IList<IDisplayType> DisplayTypes
        {
            get
            {
                return new[]
                    {
                        HostServices.CreateDisplayType( "clf", "Classification", EclItemTypes.Folder),
                        HostServices.CreateDisplayType( "ast", "Assets", EclItemTypes.File),
                    };
            }

        }

     }//Class end


AdamContext : IContentLibraryContext:

This call has code for connecting to external sources and retrieval of the content. 

internal class AdamContext : IContentLibraryContext

    {

/*this method is triggered when user click on MountPoint, its fetches the classifications from the Adam and show there
now when that particular folder is clicked, sub classicifations and assest are displayed. */

public IFolderContent GetFolderContent(IEclUri parentFolderUri, int pageIndex, EclItemTypes itemTypes)
        {
                       
            List<IContentLibraryListItem> result = new List<IContentLibraryListItem>();
            if (parentFolderUri.ItemType == EclItemTypes.MountPoint && itemTypes.HasFlag(EclItemTypes.Folder))
            {
//AdamHelper is kind of facade to get the information from service
                            var classifications = AdamHelper.GetClassifications();
                foreach (var classification in classifications)
                {
                    result.Add(new AdamListClassification(parentFolderUri.PublicationId, classification.id.ToString(), classification.Name));                
                
                }
                
           canSearch = true;
            }
            else if (parentFolderUri.ItemType == EclItemTypes.Folder && parentFolderUri.SubType == "clf" && itemTypes.HasFlag(EclItemTypes.File))
            {
               // throw new Exception("iam here");
                var records = AdamHelper.GetRecords(parentFolderUri.ItemId);
                
                result.AddRange()//
            }
                return AdamEclProvider.HostServices.CreateFolderContent(parentFolderUri, result, false, canSearch);


        }
//fetch particular item. 
public IContentLibraryItem GetItem(IEclUri eclUri)
        {
                       if (eclUri.ItemType == EclItemTypes.File && eclUri.SubType == "ast")
            {
                var record = AdamHelper.GetRecord(eclUri.ItemId);
                return new AdamAsset(eclUri.PublicationId, record, eclUri.ItemId);
            }
            throw new NotSupportedException();

        }
//fetch item list
 public IList<IContentLibraryItem> GetItems(IList<IEclUri> eclUris)
        {
///code goes here to call the aDam helper
}

} //Class end

//This class represent one type of asset, so if you have image, video you have to implement it for  each of the asset.

public class AdamAsset : IContentLibraryMultimediaItem
    {
public AdamAsset(int publicationId, RecordData record, string parentId)
        {
            _parentId = parentId;
            _record = record;
            _id = AdamEclProvider.HostServices.CreateEclUri(publicationId, AdamEclProvider.MountPointId, record.id.ToString(), "ast", EclItemTypes.File);

        }

public string DisplayTypeId
        {
            get { return "ast"; }

        }

}
}//Class end

//Represent a classification

public class AdamClassification : IContentLibraryListItem, IContentLibraryItem 

    {

    }

Note: You have to set WebReady property to "Yes" from Files tab to view the asset in Tridion.

with above code you will able to display the asset in CMS and will able to include it in the native Tridion components, for publishing those there would be additional template code. which i did not do as scope of my POC and different direction of the project.


Official Adam Connector: Official aDam connector is also available from SDL which is licensed Separately. You can check with SDL for it.

Let me know if you have any questions or need any help, feel free to comment below.

July 09, 2014

Content Porter - How it works

Content Porter(CP)  is integral part of SDL Tridion development to transfer content in DTAP environments. I have used it in various releases 5.3 sp1, 2009, 2011 etc. Its has been improved a lot in each of the releases. 2013 sp1 claims to be fastest CP ever.

Next set of lines i will explain some internals of content porter. 

Following tools/services are behind the import/export of a Content Porter package.
  • Content Porter Client
  • Import Export Service
  • Core Service
 1) Content Porter Client - this tools is generally downloaded on the client machine from the CM GUI interface. 
It acts as thin client for user, which send user selections/settings to server and show the progress of import/export.

 2) Import Export Service - It is installed after running Content Porter server setup. Here import/export happens. It basically groups and wraps different method of Core Service.

if you open: http://CMSURL/ImportExportService/ImportExportService.asmx. You will see some endpoints. and from their names you can figure out the use.

Another URL http://CMSURL/ImportExportService/UploadPackage.aspx:  its used to upload package from client to Server side.

 3) Core Service - Its is installed as part of Tridion CM installation. It is used by Import/Export service APIs to facilitate the import/export of content.

Export Process: 

  1. User selects content to be exported.
  2. and that selections are sent to Import/Export Service
  3. Import export service calls Core service APIs and complete Package is generated at server file-system
  4. Progress of that is shown to user on CP client
  5. at last exported package is sent back to User Machine via CP client.
Fig-1: Export Process

                                                               


Import Process

  1. User selects package to be imported
  2. Package is uploaded at server with help of client & import/export service
  3. Service extract the package to a temp folder
  4. Service read the package
  5. Then items are updated in the CM DB using coreservice



Fig-2: Import Process

So in both cases(export/import) most of the work is performed at server side,  so it does not matter much from where you actually trigger content porter.

April 25, 2014

Deployer Extension Secrets in SDL Tridion

While migrate from 5.3 to 2011, i found an issue in Deployer extension, My particular extension Module was  on top of  "deploy" action processor in  Tridion 5.3, but same did not work in 2011.

In 2011 Deployer works in transactions, so whatever i was updating initially it got updated in DB but it was  was not assumed as part of transaction and on final commit it was getting removed from database.

I get to know about an optional attribute "Phase" in Processor node. so i performed following steps to configure my extension

1) Copy paste existing Processor node with action deploy/undeploy  depending upon your requirement.

2) <Processor Action="Deploy" Class="com.tridion.deployer.Processor"  Phase="post-transaction"
>
            <!-- A Module is triggered by a Processor to process incoming instructions.
                    The 'Type' attribute needs to be unique within a Processor and serves
                    as a symbolic identifier. The 'Class' attribute defines the
                    implementation used for any type of Module. Replace or add modules to
                    implement custom Deployer behavior. -->
                                <Module Type="CustomDeploy" Class="com.tridion. portal. Deploy">
                       
                                                </Module>
        </Processor>
3) It would be activated only after the transaction has committed its results.

4) Now there would be 3 processor in cd_deployer.config file.

Possible values of Phase, I did not find  cd_deployer.schema to validate.
  • pre-processing
  • processing
  • post-processing
  • pre-transaction
  • post-transaction