Skip to content

Commit

Permalink
Add InjectSvg property to Logo theme object
Browse files Browse the repository at this point in the history
Resolves #3893

Co-authored-by: Daniel Valadas <info@danielvaladas.com>
Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
  • Loading branch information
3 people committed Jul 13, 2020
1 parent a005dcb commit 4e90e24
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 36 deletions.
121 changes: 98 additions & 23 deletions DNN Platform/Website/admin/Skins/Logo.ascx.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information
namespace DotNetNuke.UI.Skins.Controls
{
using System;
using System.Linq;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Linq;

using DotNetNuke.Abstractions;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Host;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.FileSystem;

using Microsoft.Extensions.DependencyInjection;

/// -----------------------------------------------------------------------------
/// <summary></summary>
/// <returns></returns>
/// <remarks></remarks>
/// -----------------------------------------------------------------------------
/// <summary>Logo Skin Object</summary>
public partial class Logo : SkinObjectBase
{
private readonly INavigationManager _navigationManager;
private readonly INavigationManager navigationManager;

/// <summary>Initializes a new instance of the <see cref="Logo"/> class.</summary>
public Logo()
{
this._navigationManager = Globals.DependencyProvider.GetRequiredService<INavigationManager>();
this.navigationManager = Globals.DependencyProvider.GetRequiredService<INavigationManager>();
}

/// <summary>Gets or sets the width of the border around the image.</summary>
public string BorderWidth { get; set; }

/// <summary>Gets or sets the CSS class for the image.</summary>
public string CssClass { get; set; }

/// <summary>Gets or sets the CSS class for the hyperlink.</summary>
public string LinkCssClass { get; set; }

/// <summary>Gets or sets a value indicating whether to inject the SVG content inline instead of wrapping it in an img tag.</summary>
public bool InjectSvg { get; set; }

/// <inheritdoc/>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Expand All @@ -47,33 +56,43 @@ protected override void OnLoad(EventArgs e)
this.imgLogo.CssClass = this.CssClass;
}

bool logoVisible = false;
if (!string.IsNullOrEmpty(this.LinkCssClass))
{
this.hypLogo.CssClass = this.LinkCssClass;
}

this.litLogo.Visible = false;
this.imgLogo.Visible = false;
if (!string.IsNullOrEmpty(this.PortalSettings.LogoFile))
{
var fileInfo = this.GetLogoFileInfo();
if (fileInfo != null)
{
string imageUrl = FileManager.Instance.GetUrl(fileInfo);
if (!string.IsNullOrEmpty(imageUrl))
if (this.InjectSvg && "svg".Equals(fileInfo.Extension, StringComparison.OrdinalIgnoreCase))
{
this.litLogo.Text = this.GetSvgContent(fileInfo);
this.litLogo.Visible = !string.IsNullOrEmpty(this.litLogo.Text);
}

if (this.litLogo.Visible == false)
{
this.imgLogo.ImageUrl = imageUrl;
logoVisible = true;
string imageUrl = FileManager.Instance.GetUrl(fileInfo);
if (!string.IsNullOrEmpty(imageUrl))
{
this.imgLogo.ImageUrl = imageUrl;
this.imgLogo.Visible = true;
}
}
}
}

this.imgLogo.Visible = logoVisible;
this.imgLogo.AlternateText = this.PortalSettings.PortalName;
this.hypLogo.ToolTip = this.PortalSettings.PortalName;

if (!this.imgLogo.Visible)
{
this.hypLogo.Attributes.Add("aria-label", this.PortalSettings.PortalName);
}
this.hypLogo.Attributes.Add("aria-label", this.PortalSettings.PortalName);

if (this.PortalSettings.HomeTabId != -1)
{
this.hypLogo.NavigateUrl = this._navigationManager.NavigateURL(this.PortalSettings.HomeTabId);
this.hypLogo.NavigateUrl = this.navigationManager.NavigateURL(this.PortalSettings.HomeTabId);
}
else
{
Expand All @@ -100,5 +119,61 @@ private IFileInfo GetLogoFileInfoCallBack(CacheItemArgs itemArgs)
{
return FileManager.Instance.GetFile(this.PortalSettings.PortalId, this.PortalSettings.LogoFile);
}

private string GetSvgContent(IFileInfo svgFile)
{
var cacheKey = string.Format(DataCache.PortalCacheKey, this.PortalSettings.PortalId, this.PortalSettings.CultureCode) + "LogoSvg";
return CBO.GetCachedObject<string>(
new CacheItemArgs(cacheKey, DataCache.PortalCacheTimeOut, DataCache.PortalCachePriority, svgFile),
(_) =>
{
try
{
XDocument svgDocument;
using (var fileContent = FileManager.Instance.GetFileContent(svgFile))
{
svgDocument = XDocument.Load(fileContent);
}
var svgXmlNode = svgDocument.Descendants()
.SingleOrDefault(x => x.Name.LocalName.Equals("svg", StringComparison.Ordinal));
if (svgXmlNode == null)
{
throw new InvalidFileContentException("The svg file has no svg node.");
}
if (!string.IsNullOrEmpty(this.CssClass))
{
// Append the css class.
var classes = svgXmlNode.Attribute("class")?.Value;
svgXmlNode.SetAttributeValue("class", string.IsNullOrEmpty(classes) ? this.CssClass : $"{classes} {this.CssClass}");
}
if (svgXmlNode.Descendants().FirstOrDefault(x => x.Name.LocalName.Equals("title", StringComparison.Ordinal)) == null)
{
// Add the title for ADA compliance.
var ns = svgXmlNode.GetDefaultNamespace();
var titleNode = new XElement(
ns + "title",
new XAttribute("id", this.litLogo.ClientID),
this.PortalSettings.PortalName);
svgXmlNode.AddFirst(titleNode);
// Link the title to the svg node.
svgXmlNode.SetAttributeValue("aria-labelledby", this.litLogo.ClientID);
}
// Ensure we have the image role for ADA Compliance
svgXmlNode.SetAttributeValue("role", "img");
return svgDocument.ToString();
}
catch (XmlException ex)
{
throw new InvalidFileContentException("Invalid SVG file: " + ex.Message);
}
});
}
}
}
29 changes: 18 additions & 11 deletions DNN Platform/Website/admin/Skins/Logo.ascx.designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions DNN Platform/Website/admin/Skins/Logo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,24 @@
<Help>Sets the border width of the logo image</Help>
<Value></Value>
</Setting>
<Setting>
<Name>CssClass</Name>
<Type>String</Type>
<Help>Sets a CSS class on the logo</Help>
<Value></Value>
</Setting>
<Setting>
<Name>LinkCssClass</Name>
<Type>String</Type>
<Help>Sets a CSS class on the hyperlink</Help>
<Value></Value>
</Setting>
<Setting>
<Name>InjectSvg</Name>
<Type>Boolean</Type>
<Help>
If set to true, the control will read the contents of the Logo file, look for an svg tag, and inject it directly into the hyperlink
</Help>
<Value></Value>
</Setting>
</Settings>
7 changes: 5 additions & 2 deletions DNN Platform/Website/admin/Skins/logo.ascx
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
<%@ Control Language="C#" AutoEventWireup="false" Inherits="DotNetNuke.UI.Skins.Controls.Logo" ViewStateMode="Disabled" Codebehind="Logo.ascx.cs" %>
<asp:hyperlink id="hypLogo" runat="server"><asp:image id="imgLogo" runat="server" enableviewstate="False" /></asp:hyperlink>
<%@ Control Language="C#" AutoEventWireup="false" Inherits="DotNetNuke.UI.Skins.Controls.Logo" ViewStateMode="Disabled" CodeBehind="Logo.ascx.cs" %>
<asp:HyperLink ID="hypLogo" runat="server">
<asp:Image ID="imgLogo" runat="server" EnableViewState="False" />
<asp:Literal ID="litLogo" runat="server" EnableViewState="False" />
</asp:HyperLink>

0 comments on commit 4e90e24

Please sign in to comment.