/// <summary> /// Distill all useful information of a hyperlink string, and put the found data in a ParsedLinkInfo structure /// </summary> /// <param name="eclSession">The ECL Session provides access to the external items. </param> /// <param name="elementName">The name of the element being processed</param> /// <param name="hyperLinkText">The full tag to parse.</param> /// <param name="endStartTag">Within the hyperLinkText, where end-tag ends</param> /// <returns>A newly created ParsedLinkInfo object with all the found information filled out</returns> private ParsedLinkInfo ParseLinkInfo(IEclSession eclSession, string elementName, string hyperLinkText, int endStartTag) { string elementStartTagOpen = "<" + elementName; ParsedLinkInfo linkInfo = new ParsedLinkInfo(); // Determine hyperlink parts string startTag = hyperLinkText.Substring(0, endStartTag + 1); string startTagAttributes = hyperLinkText.Substring(elementStartTagOpen.Length, endStartTag - elementStartTagOpen.Length); linkInfo.LinkElementName = elementName; // Process attributes IDictionary<string, string> tridionAttributes = new Dictionary<string, string>(); linkInfo.RemainingAttributes = ParseTridionTagAttributes(startTagAttributes, tridionAttributes); // Determine target URI if (!tridionAttributes.ContainsKey(AttributeNameTridionHref)) { throw new InvalidDataException(string.Format("Could not find attribute {1} in tag {0}", startTag, "tridion:href")); } string tridionHrefValue = tridionAttributes[AttributeNameTridionHref]; string targetUriString = ProcessExpression(tridionHrefValue); // Check link URI and determine link-type if (targetUriString.StartsWith("ecl:")) { // resolve into stub uri targetUriString = eclSession.GetOrCreateTcmUriFromEclUri(eclSession.HostServices.CreateEclUri(targetUriString)); } if (!TcmUri.IsValid(targetUriString)) { throw new Exception(string.Format("Could not process href value '{0}' into uri", tridionHrefValue)); } linkInfo.TargetUri = new TcmUri(targetUriString); if (linkInfo.TargetUri.ItemType == ItemType.Page) { linkInfo.LinkType = AttributeTridionTypePage; } // Check for override of type in link itself if (tridionAttributes.ContainsKey(AttributeNameTridionType)) { linkInfo.LinkType = tridionAttributes[AttributeNameTridionType]; } // Check for anchor attribute if (tridionAttributes.ContainsKey(AttributeNameTridionAnchor)) { string anchorValue = ProcessExpression(tridionAttributes[AttributeNameTridionAnchor]); if (!String.IsNullOrEmpty(anchorValue)) { linkInfo.Anchor = anchorValue; } } // Output attribute (only for multimedia) if (tridionAttributes.ContainsKey(AttributeNameTargetAttribute)) { linkInfo.TargetAttribute = tridionAttributes[AttributeNameTargetAttribute]; } if ((linkInfo.LinkType == AttributeTridionTypeComponent) && String.IsNullOrEmpty(linkInfo.Anchor)) { // for component links where nothing is specified specifically do not add an anchor linkInfo.Anchor = "false"; } if (tridionAttributes.ContainsKey(AttributeNameTridionVariantid)) { linkInfo.VariantId = tridionAttributes[AttributeNameTridionVariantid]; } return linkInfo; }
/// <summary> /// Distill all useful information of a hyperlink node, and remove the existing tridion: attributes from the node /// </summary> /// <param name="linkNode">The element node containing a tridion:href attribute being processed</param> private ParsedLinkInfo ParseLinkInfo(XmlNode linkNode) { // Set up data not in attributes ParsedLinkInfo linkInfo = new ParsedLinkInfo(); StringBuilder sb = new StringBuilder(); XmlAttributeCollection linkAttributeNodes = linkNode.Attributes; if (linkAttributeNodes != null) { IList<XmlAttribute> linkAttributes = linkAttributeNodes.Cast<XmlAttribute>().ToList(); linkInfo.LinkElementName = linkNode.LocalName; foreach (XmlAttribute linkAttribute in linkAttributes) { if (linkAttribute.NamespaceURI == TemplateUtilities.TridionNamespace) { // Remove attribute from original node linkAttributeNodes.Remove(linkAttribute); // So what attribute is it? string attName = linkAttribute.LocalName; string value = linkAttribute.Value; switch (attName) { case AttributeNameTridionType: linkInfo.LinkType = value; break; case AttributeNameTridionHref: { string targetUriString = ProcessExpression(value); if (!TcmUri.IsValid(targetUriString)) { throw new InvalidDataException(string.Format("Could not process href value '{0}' into uri", value)); } linkInfo.TargetUri = new TcmUri(targetUriString); if (linkInfo.TargetUri.ItemType == ItemType.Page) { linkInfo.LinkType = AttributeTridionTypePage; } } break; case AttributeNameTargetAttribute: linkInfo.TargetAttribute = value; break; case AttributeNameTridionAnchor: linkInfo.Anchor = value; break; case AttributeNameTridionVariantid: linkInfo.VariantId = value; break; default: sb.Append(string.Format("{0}=\"{1}\" ", attName, value)); break; } } } } if (sb.Length > 0) { linkInfo.RemainingAttributes = sb.ToString(); } if (linkInfo.TargetUri == null) { throw new InvalidDataException(string.Format("Internal error: {0}", "Attribute 'href' must be present")); } if ((linkInfo.LinkType == AttributeTridionTypeComponent) && String.IsNullOrEmpty(linkInfo.Anchor)) { // For component links where nothing is specified specifically do not add an anchor linkInfo.Anchor = "false"; } return linkInfo; }
/// <summary> /// Render and possibly publish an ECL item /// </summary> /// <param name="linkInfo">Parsed link info</param> /// <param name="item">EclItemInPackage object</param> /// <returns>template fragment for (published) ECL item or fragment with external link</returns> private string RenderEclItem(ParsedLinkInfo linkInfo, EclItemInPackage item) { // parse remaining attributes to determine width and height IDictionary<string, string> remainingAttributes = new Dictionary<string, string>(); string width; string height; ParseRemainingAttributes(linkInfo.RemainingAttributes, remainingAttributes, out width, out height); // convert remaining attributes into IList<ITemplateAttribute> IList<ITemplateAttribute> attributes = new List<ITemplateAttribute>(); foreach (var attribute in remainingAttributes) { attributes.Add(new NodeKeyValuePair(new KeyValuePair<string, string>(attribute.Key, attribute.Value))); } // we need a variantId because we could have to publish the ECL item using AddBinary string variantId = DefaultVariantId; if (!string.IsNullOrEmpty(linkInfo.VariantId)) { variantId = linkInfo.VariantId; } else if (!(string.IsNullOrEmpty(width) && !(string.IsNullOrEmpty(height)))) { variantId = string.Format("{0}x{1}", width, height); } string itemUrl = ResolveEclItem(item, attributes, variantId, _targetStructureGroup); attributes.Add(new NodeKeyValuePair(new KeyValuePair<string, string>(linkInfo.TargetAttribute, itemUrl))); if (linkInfo.LinkElementName.ToUpperInvariant() == "IMG") { string embedFragment = item.EclItem.GetTemplateFragment(attributes); if (!string.IsNullOrEmpty(embedFragment)) { // if provider can embed item we return embed fragment return embedFragment; } string externalLink = item.EclItem.GetDirectLinkToPublished(attributes); if (!string.IsNullOrEmpty(externalLink)) { StringBuilder result = new StringBuilder(); result.AppendFormat("<img "); foreach (var att in attributes) { string value = att.Value; if (att.Name.ToUpperInvariant() == "ALT") { value = item.EclItem.Title; } result.AppendFormat(" {0}=\"{1}\"", att.Name, HttpUtility.HtmlAttributeEncode(value)); } result.AppendFormat(" />"); return result.ToString(); } } // All <a> links and images that do not need special treatment processed by default finish actions // because we already resolve Ecl items with ResolveEclItem return null; }