Inject widgets anywhere on any page.

Topics: Controls
Jan 7, 2013 at 6:07 PM
Edited Jan 7, 2013 at 7:16 PM

Ever since I started using BE over a year ago this is one feature I always wanted. If someone wants the code to do this just contact me.

I created a widgets page in the admin/controls with holds a WidgetZone - I call PageZone. From here I can manage the widgets that will be accessible from any page using a code similar to the current method of injecting usercontrols. So my users can create standard widgets to use throughout their pages quickly by using a code like this:  [widget:4b78bcec-9d78-4481-a21b-09d181c11fea]

I also implemented a function to hide the border of the widget container to make the widget insertion more customizable.

I had to make changes to include, Blog.js, widget.js in the admin.masterpage as well as updating some of the default javascript global variables to enable managing a widgetzone from admin. Updates to the widget container and some of the admin links to be more relevant to the PageZone as "Delete Widget" and "Move Widget" are irrelevant on the page since they are embedded with a script. Finally updates to page.cs for the actual InjectWidgetControls method. Which I copied below.

 

    /// <summary>
    /// Injects any widget from the PageZone widget if one is referenced in the text.
    /// </summary>
    /// <param name="containerControl">The control that the user controls will be injected in to.</param>
    /// <param name="content">The string to parse for user controls.</param>
    private void InjectWidgetControls(System.Web.UI.Control containerControl, string content)
    {
        var currentPosition = 0;
        var matches = Utils.WidgetRegex.Matches(content);
        var containerControls = containerControl.Controls;
        var page = containerControl.Page;

        #region Load Page Zone Widget Data
        WidgetZone widgetZone = new WidgetZone { ZoneName = "PageZone" };
        XmlDocument xmlDocument = widgetZone.XmlDocument;

        XmlNodeList zone = null;
        if (xmlDocument != null)
        {
            zone = xmlDocument.SelectNodes("//widget");
        }

        if (zone == null)
        {
            return;
        }
        // This is for compatibility with older themes that do not have a WidgetContainer control.
        var widgetContainerExists = WidgetContainer.DoesThemeWidgetContainerExist(true);
        var widgetContainerVirtualPath = WidgetContainer.GetThemeWidgetContainerVirtualPath(false);
        #endregion

        foreach (Match match in matches)
        {
            // Add literal for content before custom tag should it exist.
            if (match.Index > currentPosition)
            {
                containerControls.Add(new LiteralControl(content.Substring(currentPosition, match.Index - currentPosition)));
            }

            // Now lets add our widget controls.
            try
            {
                foreach (XmlNode widget in zone)
                {
                    if (widget.Attributes["id"].InnerText == match.Groups[1].Value.Trim()) // widget Id
                    {
                        var fileName = string.Format("{0}widgets/{1}/widget.ascx", Utils.ApplicationRelativeWebRoot, widget.InnerText);

                        var usercontrol = (WidgetBase)page.LoadControl(fileName);
                        if (widget.Attributes != null)
                        {
                            usercontrol.WidgetId = new Guid(widget.Attributes["id"].InnerText);
                            usercontrol.Title = widget.Attributes["title"].InnerText;
                            usercontrol.ShowWidgetBorder = widget.Attributes["showWidgetBorder"] == null || bool.Parse(widget.Attributes["showWidgetBorder"].InnerText);
                            usercontrol.ShowTitle = usercontrol.IsEditable
                                                    ? bool.Parse(widget.Attributes["showTitle"].InnerText)
                                                    : usercontrol.DisplayHeader;
                        }

                        usercontrol.ID = usercontrol.WidgetId.ToString().Replace("-", string.Empty);
                        usercontrol.Zone = widgetZone.ZoneName;

                        usercontrol.LoadWidget();

                        // This will return the WidgetContainer with the control in it.
                        var widgetContainer = WidgetContainer.GetWidgetContainer(usercontrol, widgetContainerExists, widgetContainerVirtualPath);
                        page.LoadControl(widgetContainer.AppRelativeVirtualPath);
                        divText.Controls.Add(widgetContainer);
                    }
                }
            }
            catch (Exception)
            {
                // Whoopss, can't load that control so lets output something that tells the developer that theres a problem.
                containerControls.Add(
                    new LiteralControl(string.Format("ERROR - UNABLE TO LOAD WIDGET CONTROL : {0}", match.Groups[1].Value)));
            }
            currentPosition = match.Index + match.Groups[0].Length;
        }

        // Finally we add any trailing static text.
        containerControls.Add(new LiteralControl(content.Substring(currentPosition, content.Length - currentPosition)));
    }

 

**You could accomplish this more quickly with less code edits by adding a widgetzone to your masterpage called "PageZone" and then set its visibility to hidden if you are not logged into as admin. Then you can manage your PageZone widgets from any page but will only be visible when you are logged in. I just liked the admin functionality for my users to manage it there.