Saturday 10 October 2015

Opening a popup with Alchemy4Tridion framework

Using A4T to open a popup and keep reusing it.


This post was prompted by a slightly related question on the Tridion Stack Exchange on opening a popup using the Alchemy A4T Framework. I thought I would share a simple way of opening a popup.

in your command.js

The first way is using the following

var itemId = selection.getItem(0);
var url = "${ViewsUrl}popup.html?item=" + itemId,
popup = $popup.create(url, "menubar=no,location=no,resizable=no,scrollbars=no,status=no,width=405,height=180", null);
popup.open();
This may work in the vast majority of cases, but for my use I needed to make sure that if a user opened up a popup by clicking the GUI button it would reuse the same one that was already open rather than opening an infinite number of popups. In order to achieve this you need to store a reference to the popup object in the properties of the Anguilla command.
var itemId = selection.getItem(0);
var url = "${ViewsUrl}popup.html?item=" + itemId;

var onPopupClose = function() {
 $evt.removeEventHandler(this.properties.popupInstance, "unload", this.getDelegate(this.properties.popupCloseHandler));
 this.properties.popupInstance = null;
 this.properties.popupCloseHandler = null;
}

var popup = this.properties.popupInstance;
if(popup)
{
 popup.focus();
}
else
{
 popup = $popup.create(url, "menubar=no,location=no,resizable=no,scrollbars=yes,status=no,width=800,height=350", null);

 this.properties.popupInstance = popup;
 this.properties.popupCloseHandler = onPopupClose;

 $evt.addEventHandler(popup, "unload", this.getDelegate(onPopupClose));

 popup.open();
}

What is happening in the code

So after creating the URL variable the first thing we do is create an anonymous function that we want called when the popup closes, what this does is removes this event handler firstly, and then removes the properties on this object of the popup instance and the close handler.

We get the popup reference from this object and if it exists we move focus to it, if not we create a new popup object and pass a reference to it back to the calling object so we can use it again next time the button is clicked.
Then we assign the onPopupClose function to the popupCloseHandler property, and finally we add an event handler to remove these references and clean it all up if the user closes the window.
and then we open the window.

I`d love to hear your feedback, and hope you find this useful.

Thursday 19 March 2015

Get Item Type, ID and Publication from a Tridion TCM

A quick and easy way to get itemId Type and Publication from a Tridion TCM, works with TCMs in the following formats


  • tcm:0-0-0
  • tcm:122-111-111
  • tcm:112-1132-44-v22
  • tcm:0-0
  • 12-23
  • 12-32-234
  • tcm:10-11
  • tcm:10-11-v44
  • tcm:10-11-16
  • tcm:10-11-16-v44

Usage


const string tcmString = "tcm:123-45-16";
var tridionTcm = new TridionTcm(tcmString);
var tcm = tridionTcm.Tcm;
var version = tridionTcm.Version;
var publicationId = tridionTcm.PublicationId;

Validate Tridion TCM using Regex

var isValid = TridionTcm.IsValidTcm("tcm:foo-bar");



    public class TridionTcm
    {
        private const string TridionRegPatern = @"(?tcm:)?(?[0-9]+)-(?[0-9]+)(?:-(?[0-9]+))?(?:-v(?[0-9]+))?";
        public int Id { get; private set; }
        public int PublicationId { get; private set; }
        public int TypeId { get; private set; }
        public String Tcm { get; private set; }
        public int? Version { get; private set; }


        public TridionTcm(string tcm)
        {
            tcm = tcm.ToLower();
            var rgx = new Regex(TridionRegPatern);
            var match = rgx.Match(tcm);
            PublicationId = int.Parse(match.Groups["publicationid"].Value);
            Id = int.Parse(match.Groups["itemid"].Value);
            TypeId = String.IsNullOrEmpty(match.Groups["typeid"].Value) ? 16 : int.Parse(match.Groups["typeid"].Value);
            Version = String.IsNullOrEmpty(match.Groups["version"].Value) ? (int?) null : int.Parse(match.Groups["version"].Value);
            Tcm = string.Format("tcm:{0}-{1}-{2}",PublicationId,Id,TypeId);

            if (!IsValidTcm(Tcm))
            {
                throw new Exception("I just created an invalid TCM, sorry.");
            }
        }



        public static Boolean IsValidTcm(string tcm)
        {
            tcm = tcm.ToLower();
            var rgx = new Regex(TridionRegPatern);
            return rgx.IsMatch(tcm);
        }


    }

Monday 9 February 2015

Using Zip files to publish hundreds of images at publish time

Sometimes you have a requirement to publish hundreds of images from Tridion as part of a page publish, my requirements were for a tool called Krpano http://krpano.com/ which generated a folder full of images, so the flow is as follows.

  1. generate all the images using the Krpano software.
  2. create a zip file of all the images
  3. create a Panorama component, and component link to the zip file.
  4. when the page is published all the images are extracted from the zip file and put in to the broker.

This is achieved with the following.


Multimedia schema "zip of images"



In our implementation we create the two metadata values in the schema, because we need them for the way we generate our code, but you can remove them, as they are added by the code if they are missing at publish time.

"Process Zip" Class

  • Create a new class that implements BaseTemplate, this looks for all component links etc that use the Multimedia Schema called "zip of images" and this uses the open source unzipping library http://dotnetzip.codeplex.com/
  • upload the assembly in to Tridion and create the accompanying TBB for Process Zip




Then you can drag the TBB in to your new component template in template builder


Make sure the debug level is set to info, there is plenty of debugging information output to aid you with diagnosing issues.




ProcessZip.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using DD4T.Templates.Base;
using DD4T.Templates.Base.Extensions;
using Ionic.Zip;
using Microsoft.Xml.Serialization.GeneratedAssembly;
using Tridion.ContentManager.CommunicationManagement;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.Publishing;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.Templating.Assembly;
using Tridion.ContentManager.Workflow;
using Dynamic = DD4T.ContentModel;
using DD4T.ContentModel;
using Component = Tridion.ContentManager.ContentManagement.Component;
using Page = Tridion.ContentManager.CommunicationManagement.Page;
using TcmUri = Tridion.ContentManager.TcmUri;

namespace DD4T.Templates
{
    [TcmTemplateTitle("Process Zip")]

    class ProcessZip : BaseTemplate
    {


        private const string EmbargoedStatusName = "Embargoed";



        public override void Transform(Engine engine, Package package)
        {
            Log.Info(String.Format("Staring"));
            this.Log = Tridion.ContentManager.Templating.TemplatingLogger.GetLogger(this.GetType());



            this.Package = package;
            this.Engine = engine;

            var output = package.GetValue(Package.OutputName);

            if (String.IsNullOrEmpty(output))
            {
                throw new Exception("No output in package. This TBB will only work after some DD4T output has been created");
            }


            var stringBuilder = new StringBuilder();


            //Create our own namespaces for the output
            var ns = new XmlSerializerNamespaces();
            //Add an empty namespace and empty value
            ns.Add("", "");

            var xmlWriterSettings = new XmlWriterSettings
            {
                Encoding = new UTF8Encoding(),
                Indent = true,
                OmitXmlDeclaration = true
            };


            using (var writer = XmlWriter.Create(stringBuilder, xmlWriterSettings))
            using (var outputReader = new StringReader(output))
            {

                if (engine.PublishingContext.ResolvedItem.Item is Page)
                {
                    var serializer = new PageSerializer();
                    var page = (Dynamic.Page)serializer.Deserialize(outputReader);
                    this.FindZips(page.MetadataFields, this.CreateFilesFromZip);
                    serializer.Serialize(writer, page, ns);
                }
                else
                {
                    var serializer = new ComponentSerializer();
                    var component = (Dynamic.Component)serializer.Deserialize(outputReader);
                    this.FindZips(component, this.CreateFilesFromZip);
                    serializer.Serialize(writer, component, ns);
                }
            }

            var transformedOutput = stringBuilder.ToString();


            if (package.GetByName(Package.OutputName) != null)
            {
                var outputItem = package.GetByName(Package.OutputName);
                package.Remove(outputItem);
                package.PushItem(Package.OutputName, package.CreateStringItem(ContentType.Xml, transformedOutput));
            }
            else
            {
                package.PushItem(Package.OutputName, package.CreateStringItem(ContentType.Xml, transformedOutput));
            }










        }

        private void CreateFilesFromZip(Dynamic.Component component)
        {
            Component zipComponent = this.GetImageComponent(component.Id);
            Log.Info(String.Format("Zip component found {0}", zipComponent.Id));

            if (!zipComponent.BinaryContent.Filename.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("Component is not a zip");
            }


            BinaryContent imageData = zipComponent.BinaryContent;



            using (MemoryStream ms = new MemoryStream(imageData.GetByteArray()))
            {
                Log.Debug("Opening Zip file in memory");

                using (ZipFile zip = ZipFile.Read(ms))
                {
                    var numberOfImagesInZipField = new Field
                    {
                        XPath = "",
                        FieldType = FieldType.Number,
                        Name = "numberOfImagesInZip",
                    };
                    var filePathsField = new Field
                    {
                        XPath = "",
                        FieldType = FieldType.Text,
                        Name = "filePaths",
                    };


                    int imageCount = 0;
                    List fileList = new List(zip.EntryFileNames);

                    //Use natural sort to allow them to add files with numbers in and sort in human readable order.
                    fileList.Sort(new NaturalSortComparer());

                    foreach (string file in fileList)
                    {
                        ZipEntry e = zip[file];
                        Log.Debug(String.Format("Extracted file from zip: {0}", e.FileName));
                        if (ValidFileToExtract(e.FileName))
                        {
                            using (MemoryStream extractedFileStream = new MemoryStream())
                            {
                                Component relatedComponent = (Component)Engine.GetObject(zipComponent.Id);
                                e.Extract(extractedFileStream);
                                string uniqueId = relatedComponent.Id.ToString().Replace(":", "");

                                string fileName = string.Format("{0}_{1}{2}", uniqueId, imageCount, Path.GetExtension(e.FileName));
                                Log.Debug(String.Format("Saving file as: {0}", fileName));


                                using (Bitmap extractedImage = new Bitmap(extractedFileStream))
                                {
                                    string addBinaryFilename = Path.GetFileName(fileName);
                                    string addBinaryVariantId = string.Format("{0}{1}", uniqueId, fileName);

                                    Log.Debug(String.Format("MimeType: {0},addBinaryFilename: {1},addBinaryVariantId: {2}", GetMimeType(extractedImage.RawFormat), addBinaryFilename, addBinaryVariantId));

                                    Engine.PublishingContext.RenderedItem.AddBinary(
                                                                            extractedFileStream, addBinaryFilename, addBinaryVariantId, relatedComponent,
                                                                            GetMimeType(extractedImage.RawFormat));
                                }
                                imageCount++;
                                filePathsField.Values.Add(fileName);

                            }


                        }
                    }


                    numberOfImagesInZipField.NumericValues.Add(imageCount);

                    //Remove the metadata values that are added in the CME so the webapp can generate the facade correctly
                    component.MetadataFields.Remove("numberOfImagesInZip");
                    component.MetadataFields.Remove("filePaths");

                    //Polpulate with the real values.
                    component.MetadataFields.Add("numberOfImagesInZip", numberOfImagesInZipField);
                    component.MetadataFields.Add("filePaths", filePathsField);


                }
            }
        }



        private void FindZips(Dynamic.Component component, Action callback)
        {
            if (component.Schema.Title == "zip of images")
            {
                callback(component);
            }
            else
            {
                this.FindZips(component.Fields, callback);
                this.FindZips(component.MetadataFields, callback);
            }
        }

        private void FindZips(FieldSet fieldSet, Action callback)
        {
            foreach (Field field in fieldSet.Values)
            {
                if (field.FieldType == FieldType.ComponentLink
                    || field.FieldType == FieldType.MultiMediaLink)
                {
                    foreach (var linkedComponent in field.LinkedComponentValues)
                    {
                        this.FindZips(linkedComponent, callback);
                    }
                }
                if (field.FieldType == FieldType.Embedded)
                {
                    foreach (var embeddedFields in field.EmbeddedValues)
                    {
                        this.FindZips(embeddedFields, callback);
                    }
                }
            }
        }


        private Component GetImageComponent(string tcmUri)
        {
            Log.Debug("Stepping into 'GetImageComponent'");

            Component imgComponent = null;

            //Solution to capture the in-worflow version
            string inWorkflowImageTcmUri = tcmUri + "-v0";

            //Is the page being previewed in Experience Manager?
            Boolean inExperienceManager = InExperienceManager();

            if (tcmUri.Contains("-v") || !Engine.GetSession().IsExistingObject(inWorkflowImageTcmUri))
            {
                Log.Debug("Looks like we are not in-workflow. Use last major version.");

                imgComponent = (Component)Engine.GetObject(tcmUri);
                if (IsEmbargoed(imgComponent))
                {
                    throw new Exception("Current component is embargoed");
                }
                if (!inExperienceManager && !MeetsMinimalApprovalStatus(imgComponent))
                {
                    throw new Exception("Current component does not meet minimal approval status");
                }

                return imgComponent;
            }

            if (inExperienceManager)
            {
                Log.Debug("Currently in Experience Manager");

                //This means we are in "Session Preview" (Experience Manager) mode
                return (Component)Engine.GetObject(inWorkflowImageTcmUri);
            }

            Log.Debug("Checking if in-workflow version can be used");

            imgComponent = (Component)Engine.GetObject(inWorkflowImageTcmUri);
            if (!IsEmbargoed(imgComponent) && MeetsMinimalApprovalStatus(imgComponent))
            {
                //Current in-workflow status meets the minimal approval requirement
                return imgComponent;
            }

            Log.Debug("Fallback and use the last major version");

            imgComponent = ((Component)Engine.GetObject(tcmUri)).GetPublishableVersion(Engine.PublishingContext.PublicationTarget);
            if (IsEmbargoed(imgComponent))
            {
                throw new Exception("Current component is embargoed");
            }
            if (!inExperienceManager && !MeetsMinimalApprovalStatus(imgComponent))
            {
                throw new Exception("Current component does not meet minimal approval status");
            }

            return imgComponent;
        }

        private Boolean MeetsMinimalApprovalStatus(Component imgComponent)
        {
            Log.Debug("Stepping into 'MeetsMinimalApprovalStatus'");

            //Get the image's approval status
            ApprovalStatus imgApprovalStatus = null;
            try
            {
                imgApprovalStatus = imgComponent.ApprovalStatus;
            }
            catch (Exception exception)
            {
                Log.Debug("Unable to fetch the image component's approval status [" + exception.Message + "]");
            }

            if (imgApprovalStatus == null)
            {
                //This means it's an image created before workflow was introduced
                Log.Debug("Returning 'true' since the image workflow status is 'undefined'");
                return true;
            }

            //Need to introduce this to support debugging with the Template Builder
            if (GetCurrentMode() == CurrentMode.TemplateBuilder)
            {
                Log.Debug("Returning 'true' since the Publication Target is 'null' in 'TemplateBuilder' mode");
                return true;
            }

            //Get the publication target's minimal approval status
            ApprovalStatus minApprovalStatus = Engine.PublishingContext.PublicationTarget.MinApprovalStatus;

            if (minApprovalStatus == null || imgApprovalStatus.Position >= minApprovalStatus.Position)
            {
                Log.Debug("Image status meets the minimal approval status!");
                return true;
            }

            Log.Debug("Image status does NOT meet the minimal approval status!");
            return false;
        }

        private Boolean InExperienceManager()
        {
            Log.Debug("Stepping into 'InExperienceManager'");

            CurrentMode currentMode = GetCurrentMode();
            if (currentMode == CurrentMode.SessionPreview)
            {
                //This means we are in Experience Manager
                return true;
            }

            return false;
        }

        private CurrentMode GetCurrentMode()
        {
            Log.Debug("Stepping into 'GetCurrentMode'");

            RenderMode renderMode = Engine.RenderMode;

            if (renderMode == RenderMode.Publish)
            {
                return CurrentMode.Publish;
            }

            if (renderMode == RenderMode.PreviewDynamic)
            {
                PublicationTarget pubTarget = Engine.PublishingContext.PublicationTarget;
                if (pubTarget == null)
                {
                    return CurrentMode.TemplateBuilder;
                }

                if (pubTarget.Id.Equals(TcmUri.UriNull))
                {
                    return CurrentMode.CmePreview;
                }

                return CurrentMode.SessionPreview;
            }

            return CurrentMode.Unknown;
        }

        private Boolean IsEmbargoed(Component imgComponent)
        {
            Log.Debug("Stepping into 'IsEmbargoed'");

            // Get the image's approval status
            ApprovalStatus imgApprovalStatus = null;
            try
            {
                imgApprovalStatus = imgComponent.ApprovalStatus;
            }
            catch (Exception exception)
            {
                Log.Debug("Unable to fetch the image component's approval status [" + exception.Message + "]");
            }

            if (imgApprovalStatus == null)
            {
                //This means it's an image created before workflow was introduced
                Log.Debug("Returning 'false' since the image workflow status is 'undefined'");
                return false;
            }

            Log.Debug("Image status is [" + imgApprovalStatus.Title + "]");
            if (String.Equals(imgApprovalStatus.Title, EmbargoedStatusName))
            {
                Log.Debug("Image is embargoed!");
                return true;
            }

            Log.Debug("Image is NOT embargoed!");
            return false;
        }


        private Boolean ValidFileToExtract(string fileName)
        {
            return fileName.ToLower().EndsWith(".jpg");
        }


        private static string GetMimeType(ImageFormat imageFormat)
        {
            //TODO: Could enumerate Tridion's configure mime types instead of the system's
            foreach (ImageCodecInfo imageCodecInfo in ImageCodecInfo.GetImageDecoders())
            {
                if (imageCodecInfo.FormatID == imageFormat.Guid)
                {
                    return imageCodecInfo.MimeType;
                }
            }
            return "image/unknown";
        }


        private enum CurrentMode
        {
            TemplateBuilder,
            CmePreview,
            SessionPreview,
            Publish,
            Unknown
        }

        public class NaturalSortComparer : IComparer, IDisposable
        {
            private bool isAscending;

            public NaturalSortComparer(bool inAscendingOrder = true)
            {
                this.isAscending = inAscendingOrder;
            }

            #region IComparer Members

            public int Compare(string x, string y)
            {
                throw new NotImplementedException();
            }

            #endregion

            #region IComparer Members

            int IComparer.Compare(string x, string y)
            {
                if (x == y)
                    return 0;

                string[] x1, y1;

                if (!table.TryGetValue(x, out x1))
                {
                    x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
                    table.Add(x, x1);
                }

                if (!table.TryGetValue(y, out y1))
                {
                    y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
                    table.Add(y, y1);
                }

                int returnVal;

                for (int i = 0; i < x1.Length && i < y1.Length; i++)
                {
                    if (x1[i] != y1[i])
                    {
                        returnVal = PartCompare(x1[i], y1[i]);
                        return isAscending ? returnVal : -returnVal;
                    }
                }

                if (y1.Length > x1.Length)
                {
                    returnVal = 1;
                }
                else if (x1.Length > y1.Length)
                {
                    returnVal = -1;
                }
                else
                {
                    returnVal = 0;
                }

                return isAscending ? returnVal : -returnVal;
            }

            private static int PartCompare(string left, string right)
            {
                int x, y;
                if (!int.TryParse(left, out x))
                    return left.CompareTo(right);

                if (!int.TryParse(right, out y))
                    return left.CompareTo(right);

                return x.CompareTo(y);
            }

            #endregion

            private Dictionary table = new Dictionary();

            public void Dispose()
            {
                table.Clear();
                table = null;
            }
        }
    }
}

Output after running past the ProcessZip TBB

As you can see the two metadata fields for the zip are now populated numberOfImagesInZip contains a count of images found and extracted from each zip, and filePaths contains a list of all the filepaths releative to the root images folder for each file out of the zip extracted.
                      
                        
                          numberOfImagesInZip
                          
                            numberOfImagesInZip
                            
                            
                              10
                            
                            
                            
                            
                            
                          
                        
                        
                          filePaths
                          
                            filePaths
                            
                              tcm1273-61578_0.jpg
                              tcm1273-61578_1.jpg
                              tcm1273-61578_2.jpg
                              tcm1273-61578_3.jpg
                              tcm1273-61578_4.jpg
                              tcm1273-61578_5.jpg
                              tcm1273-61578_6.jpg
                              tcm1273-61578_7.jpg
                              tcm1273-61578_8.jpg
                              tcm1273-61578_9.jpg
                            
                            
                            
                            
                            
                            
                          
                        
                      


Tuesday 5 November 2013

C# WebClient with Timeout to get the HTML of a remote page

Sometimes you just need a simple WebClient to get back the results from an HTTP Post, but you need to set the timeout, this is how to do that.

public class TimeoutWebClient : WebClient
    {
        public int Timeout { get; set; }

        public TimeoutWebClient()
        {
            Timeout = 60000;
        }

        public TimeoutWebClient(int timeout)
        {
            Timeout = timeout;
        }

        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            request.Timeout = Timeout;
            return request;
        }
    }

and call like

 TimeoutWebClient client = new TimeoutWebClient { Timeout = 5000 };
 var htmlText = client.DownloadString(url);

Tuesday 22 January 2013

Tridion 2009 using Custom URLs for components

If you need to populate a field in a Tridion component using advanced parameters or information from other services you can use Custom URLs to get the value of the field, and pass it to the custom page, you can also send that value back, once it has been modified by your custom page.


Below you can see how this would work, followed by some sample source code.



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>
 Untitled Page
</title>
    <style type="text/css">
        .style1
        {
            width: 97px;
        }
        em
        {
         color:Red;
         font-style:italic;
         font-weight:bold;
        }
    </style>

    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

    <script type="text/javascript" language="javascript">
        function SaveAndClose() {
            var newValue = new Array();
            var Host = window.location.hostname;
            Host = Host.toLowerCase();
            if (Host.indexOf("dev") !== -1) {
                Host = "http://www.mydevsite.com";
            }
            else if (Host.indexOf("qa") !== -1) {
                Host = "http://www.myqasite.com";
            }
            else {
                Host = "http://www.mylivesite.com";
            }

            if ($("#User").val().length > 0) {
                newValue[0] = Host + "/feed.ashx?type=" + $("#Type").val() + "&user=" + $("#User").val();
                window.returnValue = newValue;
                self.close();
            }
            else {
                alert("You need to fill in the user field");
            }
        }

        function HideUserBox() {
            $("#User").hide();
            $("#ContextUser").html("Username is not required for this type of feed");
            $("#User").val("");
        }

        function ShowUserBox() {
            $("#User").show();
            $("#ContextUser").html("");
        }

        function getParameterByName(name) {
            name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
            var regexS = "[\\?&]" + name + "=([^&#]*)";
            var regex = new RegExp(regexS);
            var results = regex.exec(window.dialogArguments.customArguments.fieldValue);
            if (results == null)
                return "";
            else
                return decodeURIComponent(results[1].replace(/\+/g, " "));
        }


        function SetContextHelp() {
            var str = "<h1>Help</h1>Select the type of feed you would like to use.";
            var Type = $("#Type").val();
            switch (Type) {
                case "Facebook":
                    str = "<h1>FaceBook<\/h1>All you need to enter for the User field is the numeric part so for the test feed <b>http:\/\/www.dummyfacebookfeedsite.com\/feeds\/feed<em>24<\/em>.xml<\/b> it would be <em>24<\/em><\/p>";
                    ShowUserBox();
                    break;
                case "Investis":
                    str = "<h1>Investis<\/h1>No additional parameters are required<\/p>";
                    HideUserBox();
                    break;
                case "Taleo":
                    str = "<h1>Taleo<\/h1>No additional parameters are required<\/p>";
                    HideUserBox();
                    break;
                case "Twitter":
                    str = "<h1>Twitter<\/h1>All you need to enter for the User field is the part after twitter.com\/ so for the test feed <b>https:\/\/twitter.com\/<em>MyUsername<\/em><\/b> it would be <em>MyUsername<\/em><\/p>";
                    ShowUserBox();
                    break;
                case "Youtube":
                    str = "<h1>Youtube<\/h1>All you need to enter for the User field is the part after \/user\/ so for the test feed <b>http:\/\/www.youtube.com\/user\/<em>MyUsername<\/em><\/b> it would be <em>MyUsername<\/em><\/p>";
                    ShowUserBox();
                    break;
            }
            $("#ContextHelp").html(str);
        }

        $(document).ready(function () {
            $("#User").val(getParameterByName("user"));
            $("#Type").val(getParameterByName("type"));
            SetContextHelp();
        });


    </script>


</head>
<body style ="padding:8px;">
    <form name="form1" method="post" action="default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTMxODExNTY1MA9kFgICAw9kFgICAQ8QD2QWAh4Ib25jaGFuZ2UFEVNldENvbnRleHRIZWxwKCk7ZGRkZIJa/6lFwnHB6cSID/LnPwxZzMB7" />
</div>

<div>

 <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWBwL729DXAwLYobCbAwKbwILMBwL7reHFDQKNhbybDAKEnqumCgL8gpeMB6O7pPSCvvDDegx8LyqfWc6lzux3" />
</div>
    <div id="Main">
        <table border="0" width = "100%">
            <tr>
                <td>Type</td>
                <td>
                    <select name="Type" id="Type" onchange="SetContextHelp();">
 <option value="Facebook">Facebook</option>
 <option value="Investis">Investis</option>
 <option value="Taleo">Taleo</option>
 <option value="Twitter">Twitter</option>
 <option value="Youtube">Youtube</option>

</select>
                </td>
            </tr>
            <tr>
                <td>User</td>
                <td>
                    <input name="User" type="text" id="User" /><p id = "ContextUser"></p>
                </td>
            </tr>
            <tr>
                <td class="style1">
                    &nbsp;
                </td>
                <td>
                    <input type="button" value="Save" onclick="SaveAndClose()" />
                </td>
            </tr>
        </table>
        <p style ="padding:8px;background-color:#dbdbdb;" id="ContextHelp"></p>
    </div>
    </form>
</body>
</html>

Monday 22 October 2012

How to get the contents of a field out of a component on the page in Tridion

This will allow you to pass in a Page TCM, and get back the summary from the first component based on the General schema, if not it will return a default string

This also limits to 
  • Pages ending with .aspx
  • not in a Structure group of "so"
  • not in a structure group of "so2010"
  • Published to the Publish target specified





int Days = Convert.ToInt32(ConfigurationManager.AppSettings["Days"]);
string CMSUrl = Convert.ToString(ConfigurationManager.AppSettings["CMSUrl"]);
string GlobalSiteURL = Convert.ToString(ConfigurationManager.AppSettings["GlobalSiteURL"]);
int GlobalPublicationID = Convert.ToInt32(ConfigurationManager.AppSettings["GlobalPublicationID"]);
string PublishTarget = Convert.ToString(ConfigurationManager.AppSettings["PublishTarget"]); 

private string GetPageSummary(string Pagetcm)
    {
        TDSE tdse = new TDSE();
        tdse.Initialize();

        Tridion.ContentManager.Interop.TDS.Page page = (Tridion.ContentManager.Interop.TDS.Page)tdse.GetObject(Pagetcm, EnumOpenMode.OpenModeView, "tcm:0-0-0", XMLReadFilter.XMLReadAll);
        if (!page.Info.PublishLocationUrl.Contains("/so/") && !page.Info.PublishLocationUrl.Contains("/so2010/") && page.Info.PublishLocationUrl.EndsWith(".aspx") && (page.IsPublishedTo(PublishTarget)))
        {
            string summary = "";
            if (page.ComponentPresentations.Count > 0)
            {
                foreach (ComponentPresentation cp in page.ComponentPresentations)
                {
                    if (cp.Component.Schema.Title == "General")
                    {
                        summary += "<div style=\"background-color:#EAEAAE;padding:5px;\">" + cp.Component.Fields["summary"].value[1].ToString() + "</div>";
                        break;
                    }
                }
            }
            if (string.IsNullOrEmpty(summary))
            {
                summary += "No Summary available<br>";
            }
            summary += "<a href = \"" + CMSUrl + "Default.asp?URI=" + Pagetcm + "&CONTEXTURI=&FILTER=Data&ITEMTYPE=64&MODE=OpenModeEditWithFallback\" target = \"blank\">Edit page in Tridion</a>";
            summary += "<br><a href = \"" + GlobalSiteURL + page.Info.PublishLocationUrl + "\" target = \"blank\">View Page on website</a><br>";

            return summary;
        }
        return string.Empty;
    }

Get list of publications from Tridion sorted using Linq


Sometimes you need to get a list of child publications in to a dropdown etc, this is an extension to the code from http://stringwriter.com/tag/tridion/



//Call like this  GetChildPublications("tcm:0-5-1");     
private string GetChildPublications(string parentTCM)
    {
        TDSE tdse = new TDSE();
        tdse.Initialize();

        //gets current publication object
        Publication pub = tdse.GetPublication(parentTCM);
        //gets row filter object
        ListRowFilter filter = tdse.CreateListRowFilter();
        //filter only publication type
        filter.SetCondition("ItemType", 1);
        //returns using publications as xml

        string temp = "";

        XDocument xmlPublications = XDocument.Parse(pub.Info.GetListUsingItems(ListColumnFilter.XMLListIDAndTitle, filter));
        XmlNamespaceManager NS = new XmlNamespaceManager(new NameTable());
        NS.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");

        ListItem li;
        foreach (XElement PubNode in xmlPublications.XPathSelectElements("/tcm:ListUsingItems/tcm:Item", NS).OrderBy(s => (string)s.Attribute("Title")))
        {
            li = new ListItem();
            li.Text = PubNode.Attribute("Title").Value;
            li.Value = PubNode.Attribute("ID").Value;
            GlobalPublicationID.Items.Add(li);
        }

        return temp;
    }