// https://github.com/mjmlio/mjml/blob/d4c6ea0744e05c928044108c3117c16a9c4110fe/packages/mjml-core/src/createComponent.js#L115 public virtual CssBoxModel GetBoxModel() { // LR: Default to the outmost container CssParsedUnit containerWidth = CssUnitParser.Parse(HtmlSkeleton.ContainerWidth); var paddings = GetShorthandAttributeValue("padding", "right") + GetShorthandAttributeValue("padding", "left"); var borders = GetShorthandBorderValue("right") + GetShorthandBorderValue("left"); // LR: Try and get the parents calculated Box Model size. if (HasParentComponent()) { var parent = GetParentComponent() as BodyComponent; // LR: Calculate based of the parents inner width (width after removing paddings and borders) containerWidth.Value = parent.GetContainerInnerWidth() - paddings - borders; return(new CssBoxModel( parent.GetContainerInnerWidth(), borders, paddings, containerWidth.Value )); } return(new CssBoxModel( containerWidth.Value, borders, paddings, containerWidth.Value)); }
public float GetShorthandBorderValue(string direction) { string mjAttributeDirection = GetAttribute($"border-{direction}"); string mjAttribute = GetAttribute("border"); if (!string.IsNullOrWhiteSpace(mjAttributeDirection)) { return(CssUnitParser.Parse(mjAttributeDirection).Value); } if (string.IsNullOrWhiteSpace(mjAttribute)) { return(0); } // MERGED borderParser: https://github.com/mjmlio/mjml/blob/d4c6ea0744e05c928044108c3117c16a9c4110fe/packages/mjml-core/src/helpers/shorthandParser.js#L3 //return CssUnitParser.Parse(mjAttribute).Value; Regex regex = new Regex("(?:(?:^| )([0-9]+))"); var match = regex.Match(mjAttribute); if (!match.Success) { return(0); } return(float.Parse(match.Value.Trim())); }
public override string RenderMjml() { var height = GetAttribute("height"); if (string.IsNullOrWhiteSpace(height)) { height = "20px"; } return($@" {TagHelpers.ConditionalTag($@" <table role=""presentation"" border=""0"" cellpadding=""0"" cellspacing=""0""> <tr> <td height=""{CssUnitParser.Parse(height).Value}"" style=""vertical-align:top;height:{height};""> ")} <div {HtmlAttributes(new Dictionary<string, string> { { "style", "div"} })} > </div> {TagHelpers.ConditionalTag($@" </td> </tr> </table> ")} "); }
private string GetWidth() { string width = GetAttribute("width"); CssParsedUnit parsedWidth = CssUnitParser.Parse(width); return(parsedWidth.Unit == "%" ? width : $"{parsedWidth.Value}px"); }
public string GetMobileWidth() { var width = GetAttribute("width"); var mobileWidth = GetAttribute("mobileWidth"); if (string.IsNullOrWhiteSpace(mobileWidth)) { return("100%"); } if (string.IsNullOrWhiteSpace(width)) { return($"{100 / ParentSectionColumnCount}%"); } var parsedWidth = CssUnitParser.Parse(width); switch (parsedWidth.Unit.ToLower()) { case "%": return(width); case "px": default: return($"{parsedWidth.Value / CssUnitParser.Parse(ContainerWidth).Value}%"); } }
public string GetContentWidth() { CssParsedUnit width = HasAttribute("width") ? CssUnitParser.Parse(GetAttribute("width")) : CssUnitParser.Parse($"{999999}px"); return(width.Value < GetContainerInnerWidth() ? width.ToString() : $"{GetContainerInnerWidth()}px"); }
public float GetShorthandAttributeValue(string attribute, string direction) { string mjAttributeDirection = GetAttribute($"{attribute}-{direction}"); string mjAttribute = GetAttribute(attribute); if (!string.IsNullOrWhiteSpace(mjAttributeDirection)) { return(CssUnitParser.Parse(mjAttributeDirection).Value); } if (string.IsNullOrWhiteSpace(mjAttribute)) { return(0); } // MERGED shorthandParser: https://github.com/mjmlio/mjml/blob/d4c6ea0744e05c928044108c3117c16a9c4110fe/packages/mjml-core/src/helpers/shorthandParser.js#L3 var splittedCssValue = mjAttribute.Split(' '); Dictionary <string, int> directions; switch (splittedCssValue.Length) { case 2: directions = new Dictionary <string, int> { { "top", 0 }, { "bottom", 0 }, { "left", 1 }, { "right", 1 } }; break; case 3: directions = new Dictionary <string, int> { { "top", 0 }, { "bottom", 2 }, { "left", 1 }, { "right", 1 } }; break; case 4: directions = new Dictionary <string, int> { { "top", 0 }, { "bottom", 2 }, { "left", 3 }, { "right", 1 } }; break; case 1: default: return(CssUnitParser.Parse(mjAttribute).Value); } return(CssUnitParser.Parse(splittedCssValue[directions[direction]]).Value); }
public override CssBoxModel GetBoxModel() { // LR: Default to the outmost container CssParsedUnit containerWidth = CssUnitParser.Parse(HtmlSkeleton.ContainerWidth); // LR: Try and get the parents calculated Box Model size. if (HasParentComponent()) { var parent = GetParentComponent() as BodyComponent; // LR: Get columns in this section ParentSectionColumnCount = GetSectionColumnCount(); // LR: Parent section width var sectionWidth = parent.CssBoxModel.BoxWidth; // LR: Column has width attribute? if (HasAttribute("width")) { ContainerWidth = GetAttribute("width"); } else { ContainerWidth = $"{sectionWidth / ParentSectionColumnCount}px"; } // LR: Parse the calculated width CssParsedUnit parsedWidth = CssUnitParser.Parse(ContainerWidth); // LR: Handle Percentage values if (parsedWidth.Unit.Equals("%", StringComparison.InvariantCultureIgnoreCase)) { parsedWidth.Value = sectionWidth * parsedWidth.Value / 100; ContainerWidth = $"{parsedWidth.Value}px"; } else { ContainerWidth = $"{parsedWidth.Value}px"; } // LR: Calculated column width var columnWidth = CssUnitParser.Parse(ContainerWidth); return(new CssBoxModel( parsedWidth.Value, 0, 0, columnWidth.Value )); } return(new CssBoxModel( containerWidth.Value, 0, 0, containerWidth.Value)); }
public string GetWidthAsPixel() { var parsedWidth = GetParsedWidth(); var parsedContainerWidth = CssUnitParser.Parse(ContainerWidth); if (parsedWidth.Unit.Equals("%", StringComparison.InvariantCultureIgnoreCase)) { return($"{ parsedContainerWidth.Value * parsedWidth.Value / 100}px"); } return(parsedWidth.ToString()); }
private object RenderMode() { string background = GetAttribute("background-url"); switch (GetAttribute("mode")) { case "fluid-height": string magicTd = HtmlAttributes(new Dictionary <string, string> { { "style", "td-fluid" }, }); return($@" <td {magicTd} /> <td {HtmlAttributes(new Dictionary<string, string> { { "background", background }, { "style", "hero" } })} > {RenderContent()} </td> <td {magicTd} /> "); default: var heightCss = CssUnitParser.Parse(GetAttribute("height")); var paddingTop = GetShorthandAttributeValue("padding", "top"); var paddingBottom = GetShorthandAttributeValue("padding", "bottom"); // LR: Start with the height value. e.g. 500px var height = heightCss.Value; // LR: Convert % to PX if (heightCss.Unit.Equals("%")) { height = GetContainerInnerWidth() / 100 * height; } // LR: Remove the top and bottom padding from the height e.g. 500px - 24px - 24px = 452px height -= paddingTop + paddingBottom; return($@" <td {HtmlAttributes(new Dictionary<string, string> { { "background", background }, { "style", "hero" }, { "height", $"{height}" } })} > {RenderContent()} </td> "); } }
public CssParsedUnit GetParsedWidth() { string width = string.Empty; if (HasAttribute("width")) { width = GetAttribute("width"); } else { width = $"{100 / GetSectionColumnCount()}%"; } CssParsedUnit parsedWidth = CssUnitParser.Parse(width); return(parsedWidth); }
public string GetElementWidth(string width) { if (string.IsNullOrWhiteSpace(width)) { var parsedContainerWidth = CssUnitParser.Parse(ContainerWidth); float columnWidth = parsedContainerWidth.Value / GetSectionColumnCount(); return($"{columnWidth}px"); } var parsedWidth = CssUnitParser.Parse(width); if (parsedWidth.Unit.Equals("%", StringComparison.InvariantCultureIgnoreCase)) { return($"{ 100 * parsedWidth.Value / GetContainerInnerWidth()}px"); } return(parsedWidth.ToString()); }
public CssCoordinate CalculateBackgroundAxisOrigin(string axis, CssCoordinate coordinate) { bool isX = axis.Equals("x", StringComparison.InvariantCultureIgnoreCase); bool isBackgroundRepeat = HasAttribute("background-repeat") && GetAttribute("background-repeat").Equals("repeat", StringComparison.InvariantCultureIgnoreCase); string position = isX ? coordinate.X : coordinate.Y; string origin = isX ? coordinate.X : coordinate.Y; float positionFloat; float originFloat; if (position.Contains("%")) { var percentage = CssUnitParser.Parse(position); if (isBackgroundRepeat) { positionFloat = percentage.Value; originFloat = percentage.Value; } else { float computed = (-50 + (percentage.Value * 100)) / 100; positionFloat = computed; originFloat = computed; } } else if (isBackgroundRepeat) { positionFloat = isX ? 0.5f : 0f; originFloat = isX ? 0.5f : 0f; } else { positionFloat = isX ? 0f : -0.5f; originFloat = isX ? 0f : -0.5f; } return(new CssCoordinate(originFloat.ToString(), positionFloat.ToString())); }
public string CalculateAWidth(string content) { if (string.IsNullOrWhiteSpace(content)) { return(null); } CssParsedUnit parsedWidth = CssUnitParser.Parse(content); if (!parsedWidth.Unit.Equals("px")) { return(null); } var borders = CssBoxModel.BorderWidth; var innerPaddings = GetShorthandAttributeValue("inner-padding", "left") + GetShorthandAttributeValue("inner-padding", "right"); return($"{parsedWidth.Value - innerPaddings - borders}px"); }
public virtual string GetOutlookWidth() { var containerWidth = CssUnitParser.Parse($"{GetContainerOuterWidth()}"); var paddingSize = GetShorthandAttributeValue("padding", "left") + GetShorthandAttributeValue("padding", "right"); var parsedWidth = CssUnitParser.Parse(GetAttribute("width")); switch (parsedWidth.Unit.ToLower()) { case "%": return($"{ (containerWidth.Value * parsedWidth.Value / 100) - paddingSize}px"); case "px": return(parsedWidth.ToString()); default: return($"{containerWidth.Value - paddingSize}px"); } }
public override void SetupStyles() { var backgroundHeight = CssUnitParser.Parse(GetAttribute("background-height")); var backgroundWidth = CssUnitParser.Parse(GetAttribute("background-width")); var backgroundRatio = Math.Round(backgroundHeight.Value / backgroundWidth.Value * 100d); var width = Element.HasAttribute("background-width") ? GetAttribute("background-width") : $"{GetContainerInnerWidth()}px"; StyleLibraries.AddStyleLibrary("div", new Dictionary <string, string>() { { "margin", "0 auto" }, { "max-width", $"{GetContainerInnerWidth()}px" } }); StyleLibraries.AddStyleLibrary("table", new Dictionary <string, string>() { { "width", "100%" } }); StyleLibraries.AddStyleLibrary("tr", new Dictionary <string, string>() { { "vertical-align", "top" } }); StyleLibraries.AddStyleLibrary("td-fluid", new Dictionary <string, string>() { { "width", "0.01%" }, { "padding-bottom", $"{backgroundRatio}%" }, { "mso-padding-bottom-alt", "0" } }); StyleLibraries.AddStyleLibrary("hero", new Dictionary <string, string>() { { "background", GetBackground() }, { "background-position", GetAttribute("background-position") }, { "background-repeat", "no-repeat" }, { "padding", GetAttribute("padding") }, { "padding-top", GetAttribute("padding-top") }, { "padding-left", GetAttribute("padding-left") }, { "padding-right", GetAttribute("padding-right") }, { "padding-bottom", GetAttribute("padding-bottom") }, { "vertical-align", GetAttribute("vertical-align") } }); StyleLibraries.AddStyleLibrary("outlook-table", new Dictionary <string, string>() { { "width", $"{GetContainerInnerWidth()}px" } }); StyleLibraries.AddStyleLibrary("outlook-td", new Dictionary <string, string>() { { "line-height", "0" }, { "font-size", "0a" }, { "mso-line-height-rule", "exactly" }, }); StyleLibraries.AddStyleLibrary("outlook-inner-table", new Dictionary <string, string>() { { "width", $"{GetContainerInnerWidth()}px" } }); StyleLibraries.AddStyleLibrary("outlook-image", new Dictionary <string, string>() { { "border", "0" }, { "height", GetAttribute("background-height") }, { "mso-position-horizontal", "center" }, { "position", "absolute" }, { "top", "0" }, { "width", width }, { "z-index", "-3" } }); StyleLibraries.AddStyleLibrary("outlook-inner-td", new Dictionary <string, string>() { { "background-color", GetAttribute("inner-background-color") }, { "padding", GetAttribute("padding") }, { "padding-top", GetAttribute("padding-top") }, { "padding-left", GetAttribute("padding-left") }, { "padding-right", GetAttribute("padding-right") }, { "padding-bottom", GetAttribute("padding-bottom") }, }); StyleLibraries.AddStyleLibrary("inner-table", new Dictionary <string, string>() { { "width", "100%" }, { "margin", "0px" } }); StyleLibraries.AddStyleLibrary("inner-div", new Dictionary <string, string>() { { "background-color", GetAttribute("inner-background-color") }, { "float", GetAttribute("align") }, { "margin", "0px auto" }, { "width", GetAttribute("width") } }); }
public override CssBoxModel GetBoxModel() { // LR: Default to the outmost container CssParsedUnit containerWidth = CssUnitParser.Parse(HtmlSkeleton.ContainerWidth); // LR: Get Padding var paddings = GetShorthandAttributeValue("padding", "right") + GetShorthandAttributeValue("padding", "left"); // LR: Get Borders var borders = GetShorthandBorderValue("right") + GetShorthandBorderValue("left"); // LR: Get inner-borders float innerBorders = GetShorthandAttributeValue("inner-border", "left") + GetShorthandAttributeValue("inner-border", "right"); // LR: All padding float allPaddings = paddings + borders + innerBorders; // LR: Try and get the parents calculated Box Model size. if (HasParentComponent()) { var parent = GetParentComponent() as BodyComponent; // LR: Get columns in this section ParentSectionColumnCount = GetSectionColumnCount(); // LR: Parent section width var sectionWidth = parent.CssBoxModel.BoxWidth; // LR: Column has width attribute? if (HasAttribute("width")) { ContainerWidth = GetAttribute("width"); } else { ContainerWidth = $"{sectionWidth / ParentSectionColumnCount}px"; } // LR: Parse the calculated width CssParsedUnit parsedWidth = CssUnitParser.Parse(ContainerWidth); // LR: Handle Percentage values if (parsedWidth.Unit.Equals("%", StringComparison.InvariantCultureIgnoreCase)) { parsedWidth.Value = (sectionWidth * parsedWidth.Value / 100); ContainerWidth = $"{parsedWidth.Value - allPaddings}"; } else { ContainerWidth = $"{parsedWidth.Value - allPaddings}px"; } // LR: Calculated column width var columnWidth = CssUnitParser.Parse(ContainerWidth); return(new CssBoxModel( parsedWidth.Value, borders, paddings, columnWidth.Value )); } return(new CssBoxModel( containerWidth.Value, borders, paddings, containerWidth.Value)); }
public string RenderWithBackground(string content) { CssParsedUnit containerWidth = CssUnitParser.Parse($"{GetContainerOuterWidth()}"); bool isFullWidth = IsFullWidth(); bool isPercentage = containerWidth.Unit.Equals("%", StringComparison.InvariantCultureIgnoreCase); CssCoordinate backgroundPosition = GetBackgroundPosition(); // LR: Convert direction to Percentage X switch (backgroundPosition.X) { case "left": backgroundPosition.X = "0%"; break; case "center": backgroundPosition.X = "50%"; break; case "right": backgroundPosition.X = "100%"; break; default: if (!backgroundPosition.X.ToString().Contains("%")) { backgroundPosition.X = "50%"; } break; } // LR: Convert direction to Percentage Y switch (backgroundPosition.Y) { case "top": backgroundPosition.Y = "0%"; break; case "center": backgroundPosition.Y = "50%"; break; case "bottom": backgroundPosition.Y = "100%"; break; default: if (!backgroundPosition.Y.ToString().Contains("%")) { backgroundPosition.Y = "0%"; } break; } // LR: Calculate position to origin // X = Axis Origin, Y = Axis Position // This logic is different when using repeat or no-repeat var originX = CalculateBackgroundAxisOrigin("x", backgroundPosition); var originY = CalculateBackgroundAxisOrigin("y", backgroundPosition); Dictionary <string, string> vSizeAttributes = new Dictionary <string, string>(); // If background size is either cover or contain, we tell VML to keep the aspect // and fill the entire element. if (GetAttribute("background-size").Equals("cover", StringComparison.InvariantCultureIgnoreCase) || GetAttribute("background-size").Equals("contain", StringComparison.InvariantCultureIgnoreCase)) { vSizeAttributes = new Dictionary <string, string> { { "size", "1,1" }, { "aspect", GetAttribute("background-size").Equals("cover", StringComparison.InvariantCultureIgnoreCase) ? "atleast" : "atmost" }, }; } else if (!GetAttribute("background-size").Equals("auto", StringComparison.InvariantCultureIgnoreCase)) { string backgroundSize = GetAttribute("background-size"); var bgSplit = backgroundSize.Split(' '); if (bgSplit.Length.Equals(1)) { vSizeAttributes = new Dictionary <string, string> { { "size", GetAttribute("background-size") }, { "aspect", "atmost" }, // reproduces height auto }; } else { vSizeAttributes = new Dictionary <string, string> { { "size", backgroundSize.Replace(' ', ',') }, }; } } var vmlType = GetAttribute("background-repeat").Equals("no-repeat", StringComparison.InvariantCultureIgnoreCase) ? "frame" : "tile"; if (GetAttribute("background-size").Equals("auto", StringComparison.InvariantCultureIgnoreCase)) { vmlType = "tile"; // If no size provided, keep old behavior because outlook can't use original image size with "frame" // Also ensure that images are still cropped the same way originX = new CssCoordinate("0.5", "0.5"); originY = new CssCoordinate("0", "0"); } return($@" <!--[if mso | IE]> <v:rect {HtmlAttributes(new Dictionary<string, string> { { "style", isFullWidth ? InlineCss(new Dictionary<string, string>{ { "mso-width-percent", "1000"} }) : InlineCss(new Dictionary<string, string>{ { "width", $"{GetContainerOuterWidth()}px" } }) }, { "xmlns:v", "urn:schemas-microsoft-com:vml"}, { "fill", "true"}, { "stroke", "false"}, })}> <v:fill {HtmlAttributes(new Dictionary<string, string> { { "origin", $"{originX.X}, {originY.X}"}, { "position", $"{originX.Y}, {originY.Y}" }, { "src", GetAttribute("background-url") }, { "color", GetAttribute("background-color") }, { "type", vmlType } }.MergeLeft(vSizeAttributes))} /> <v:textbox style=""mso-fit-shape-to-text:true"" inset=""0,0,0,0""> <![endif]--> {content} <!--[if mso | IE]> </v:textbox> </v:rect> <![endif]--> "); }
public string RenderImage() { bool bHasHeight = HasAttribute("height"); string height = GetAttribute("height"); string img = $@" <img {HtmlAttributes(new Dictionary<string, string> { { "alt", GetAttribute("alt") }, { "height", bHasHeight && height.Equals("auto", StringComparison.InvariantCultureIgnoreCase) ? height : CssUnitParser.Parse(height).Value.ToString() }, { "src", GetAttribute("src") }, { "srcset", GetAttribute("srcset") }, { "sizes", GetAttribute("sizes") }, { "style", "img" }, { "title", GetAttribute("title") }, { "width", GetContentWidth() }, { "usemap", GetAttribute("usemap") }, })} /> "; if (HasAttribute("href")) { return($@" <a {HtmlAttributes(new Dictionary<string, string>() { { "href", GetAttribute("href") }, { "target", GetAttribute("target") }, { "rel", GetAttribute("rel") }, { "name", GetAttribute("name") }, })} > {img} </a> "); } return(img); }