Skip to content

Commit 271ea42

Browse files
committed
Restored couple supporting widget controls needed for Razor themes (3.2.1.3)
1 parent b907581 commit 271ea42

4 files changed

Lines changed: 392 additions & 1 deletion

File tree

BlogEngine/BlogEngine.Core/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
[assembly: CLSCompliant(false)]
2020
[assembly: ComVisible(false)]
2121
[assembly: AllowPartiallyTrustedCallers]
22-
[assembly: AssemblyVersion("3.2.1.2")]
22+
[assembly: AssemblyVersion("3.2.1.3")]
2323
[assembly: SecurityRules(SecurityRuleSet.Level1)]
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// --------------------------------------------------------------------------------------------------------------------
2+
// <summary>
3+
// Widget Base
4+
// </summary>
5+
// --------------------------------------------------------------------------------------------------------------------
6+
7+
using BlogEngine.Core;
8+
9+
namespace App_Code.Controls
10+
{
11+
using System;
12+
using System.Collections.Specialized;
13+
using System.Web.UI;
14+
15+
using BlogEngine.Core.DataStore;
16+
17+
/// <summary>
18+
/// Widget Base
19+
/// </summary>
20+
public abstract class WidgetBase : UserControl
21+
{
22+
#region Properties
23+
24+
/// <summary>
25+
/// Gets a value indicating whether the header is visible. This only takes effect if the widgets isn't editable.
26+
/// </summary>
27+
/// <value><c>true</c> if the header is visible; otherwise, <c>false</c>.</value>
28+
public virtual bool DisplayHeader
29+
{
30+
get
31+
{
32+
return true;
33+
}
34+
}
35+
36+
/// <summary>
37+
/// Gets a value indicating whether or not the widget can be edited.
38+
/// <remarks>
39+
/// The only way a widget can be editable is by adding a edit.ascx file to the widget folder.
40+
/// </remarks>
41+
/// </summary>
42+
public abstract bool IsEditable { get; }
43+
44+
/// <summary>
45+
/// Gets the name. It must be exactly the same as the folder that contains the widget.
46+
/// </summary>
47+
public abstract string Name { get; }
48+
49+
/// <summary>
50+
/// Gets or sets a value indicating whether [show title].
51+
/// </summary>
52+
/// <value><c>true</c> if [show title]; otherwise, <c>false</c>.</value>
53+
public bool ShowTitle { get; set; }
54+
55+
/// <summary>
56+
/// Gets or sets the title of the widget. It is mandatory for all widgets to set the Title.
57+
/// </summary>
58+
/// <value>The title of the widget.</value>
59+
public string Title { get; set; }
60+
61+
/// <summary>
62+
/// Gets or sets the widget ID.
63+
/// </summary>
64+
/// <value>The widget ID.</value>
65+
public Guid WidgetId { get; set; }
66+
67+
/// <summary>
68+
/// Gets or sets the name of the containing WidgetZone
69+
/// </summary>
70+
public string Zone { get; set; }
71+
72+
#endregion
73+
74+
#region Public Methods
75+
76+
/// <summary>
77+
/// Get settings from data store
78+
/// </summary>
79+
/// <returns>
80+
/// The settings
81+
/// </returns>
82+
public StringDictionary GetSettings()
83+
{
84+
var cacheId = string.Format("be_widget_{0}", this.WidgetId);
85+
if (Blog.CurrentInstance.Cache[cacheId] == null)
86+
{
87+
var ws = new WidgetSettings(this.WidgetId.ToString());
88+
Blog.CurrentInstance.Cache[cacheId] = ws.GetSettings();
89+
}
90+
91+
return (StringDictionary)Blog.CurrentInstance.Cache[cacheId];
92+
}
93+
94+
/// <summary>
95+
/// This method works as a substitute for Page_Load. You should use this method for
96+
/// data binding etc. instead of Page_Load.
97+
/// </summary>
98+
public abstract void LoadWidget();
99+
100+
#endregion
101+
102+
#region Methods
103+
104+
/// <summary>
105+
/// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"></see>
106+
/// object, which writes the content to be rendered on the client.
107+
/// </summary>
108+
/// <param name="writer">
109+
/// The <see cref="T:System.Web.UI.HtmlTextWriter"></see> object that receives the server control content.
110+
/// </param>
111+
protected override void Render(HtmlTextWriter writer)
112+
{
113+
if (string.IsNullOrEmpty(this.Name))
114+
{
115+
throw new NullReferenceException("Name must be set on a widget");
116+
}
117+
118+
base.Render(writer);
119+
}
120+
121+
#endregion
122+
}
123+
}
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
// --------------------------------------------------------------------------------------------------------------------
2+
// <summary>
3+
// Themeable class for displaying WidgetBase derived controls.
4+
// </summary>
5+
// --------------------------------------------------------------------------------------------------------------------
6+
7+
namespace App_Code.Controls
8+
{
9+
using System;
10+
using System.IO;
11+
using System.Text;
12+
using System.Threading;
13+
using System.Web.UI;
14+
using System.Web.Hosting;
15+
using BlogEngine.Core;
16+
17+
using Resources;
18+
19+
/// <summary>
20+
/// Themeable class for displaying WidgetBase derived controls.
21+
/// </summary>
22+
/// <remarks>
23+
/// WidgetContainer is meant to be the themeable parent class of any control that derives from WidgetBase. This way a theme can automatically
24+
/// apply some basic styling to the way widgets are displayed without having to edit each one or edit the WidgetBase class to change the
25+
/// rendered output.
26+
/// Inherited WidgetContainers must contain a control named phWidgetBody. This is the control that the WidgetContainer's child Widget is
27+
/// injected inside of. phWidgetBody just needs to derive from Control to work, leaving flexibility for anyone creating a theme.
28+
/// If phWidgetBody isn't found, an exception isn't thrown, but a warning label is applied to the page.
29+
/// </remarks>
30+
public abstract class WidgetContainer : UserControl
31+
{
32+
#region "Properties"
33+
34+
/// <summary>
35+
/// Gets or sets the Widget this WidgetContainer holds.
36+
/// </summary>
37+
public WidgetBase Widget
38+
{
39+
get;
40+
set;
41+
}
42+
43+
44+
/// <summary>
45+
/// Gets a string representing the rendered html for administrative control of this WidgetContainer's child Widget.
46+
/// </summary>
47+
public string AdminLinks
48+
{
49+
get
50+
{
51+
if (Security.IsAuthorizedTo(Rights.ManageWidgets))
52+
{
53+
if (this.Widget != null)
54+
{
55+
var sb = new StringBuilder();
56+
57+
var widgetId = this.Widget.WidgetId;
58+
59+
sb.AppendFormat("<a class=\"delete\" href=\"#\" onclick=\"BlogEngine.widgetAdmin.removeWidget('{0}');return false\" title=\"{1} widget\"><span class=\"widgetImg imgDelete\">&nbsp;</span></a>", widgetId, labels.delete);
60+
sb.AppendFormat("<a class=\"edit\" href=\"#\" onclick=\"BlogEngine.widgetAdmin.editWidget('{0}', '{1}');return false\" title=\"{2} widget\"><span class=\"widgetImg imgEdit\">&nbsp;</span></a>", this.Widget.Name, widgetId, labels.edit);
61+
sb.AppendFormat("<a class=\"move\" href=\"#\" onclick=\"BlogEngine.widgetAdmin.initiateMoveWidget('{0}');return false\" title=\"{1} widget\"><span class=\"widgetImg imgMove\">&nbsp;</span></a>", widgetId, labels.move);
62+
63+
return sb.ToString();
64+
}
65+
}
66+
67+
68+
return String.Empty;
69+
}
70+
}
71+
72+
#endregion
73+
74+
/// <summary>
75+
/// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
76+
/// </summary>
77+
/// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
78+
protected override void OnLoad(EventArgs e)
79+
{
80+
base.OnLoad(e);
81+
ProcessLoad();
82+
}
83+
84+
private bool _processedLoad;
85+
/// <summary>
86+
/// Manually run the Initialization process.
87+
/// </summary>
88+
public void ProcessLoad()
89+
{
90+
if (_processedLoad) { return; }
91+
92+
// phWidgetBody is the control that the Widget control
93+
// gets added to.
94+
var widgetBody = this.FindControl("phWidgetBody");
95+
96+
if (widgetBody != null)
97+
{
98+
widgetBody.Controls.Add(this.Widget);
99+
}
100+
else
101+
{
102+
var warn = new LiteralControl
103+
{
104+
Text = "Unable to find control with id \"phWidgetBody\" in theme's WidgetContainer."
105+
};
106+
this.Controls.Add(warn);
107+
}
108+
109+
_processedLoad = true;
110+
}
111+
112+
/// <summary>
113+
/// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
114+
/// </summary>
115+
/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
116+
protected override void OnPreRender(EventArgs e)
117+
{
118+
base.OnPreRender(e);
119+
120+
// Hide the container if the Widget is null or also not visible.
121+
this.Visible = (this.Widget != null) && this.Widget.Visible;
122+
}
123+
124+
/// <summary>
125+
/// The container will be processed when invoked, rather than waiting
126+
/// for the Load event to occur.
127+
/// </summary>
128+
public virtual void RenderContainer() { }
129+
130+
/// <summary>
131+
/// Returns the virtual path of where a theme's widget container would expect to be located.
132+
/// </summary>
133+
/// <param name="existenceCheck">
134+
/// When true, the path to the theme folder to check for the WidgetContainer existence
135+
/// is returned. When false, the path to the control that will be loaded is returned.
136+
/// If it's a Razor theme, the path will be RazorHost instead of the actual theme folder
137+
/// name.
138+
/// </param>
139+
/// <returns></returns>
140+
public static string GetThemeWidgetContainerVirtualPath(bool existenceCheck)
141+
{
142+
if (existenceCheck)
143+
{
144+
// if it's a Razor theme, check if WidgetContainer.cshtml exists.
145+
string filename = BlogSettings.Instance.IsRazorTheme ? "WidgetContainer.cshtml" : "WidgetContainer.ascx";
146+
return string.Format("~/Custom/Themes/{0}/{1}", BlogSettings.Instance.Theme, filename);
147+
}
148+
else
149+
{
150+
// when existenceCheck == false, the actual file that will be loaded needs to be
151+
// returned. if it's a Razor theme, we will load WidgetContainer.ascx in the
152+
// RazorHost folder. we assume that the RazorHost folder contains WidgetContainer.ascx.
153+
return string.Format("~/Custom/Themes/{0}/WidgetContainer.ascx", BlogSettings.Instance.GetThemeWithAdjustments(null));
154+
}
155+
}
156+
157+
/// <summary>
158+
/// Returns the file path of where a theme's widget container would expect to be located.
159+
/// </summary>
160+
public static string GetThemeWidgetContainerFilePath(bool existenceCheck)
161+
{
162+
return HostingEnvironment.MapPath(GetThemeWidgetContainerVirtualPath(existenceCheck));
163+
}
164+
165+
/// <summary>
166+
/// Returns whether the theme contains a widget container file.
167+
/// </summary>
168+
public static bool DoesThemeWidgetContainerExist(bool existenceCheck)
169+
{
170+
// This is for compatibility with older themes that do not have a WidgetContainer control.
171+
return File.Exists(GetThemeWidgetContainerFilePath(existenceCheck));
172+
}
173+
174+
/// <summary>
175+
/// Loads the widget container (either the one located in the theme folder, or the default one if
176+
/// a theme widget container is missing), and adds the Widget to the widget container.
177+
/// </summary>
178+
public static WidgetContainer GetWidgetContainer(
179+
WidgetBase widgetControl, bool widgetContainerExists,
180+
string widgetContainerVirtualPath)
181+
{
182+
// If a custom WidgetContainer can't be found, create a new DefaultWidgetContainer instance as it
183+
// provides backwards compatibility with existing themes that may have depended on WidgetBase's
184+
// old rendering method.
185+
var widgetContainer = widgetContainerExists ? (WidgetContainer)widgetControl.Page.LoadControl(widgetContainerVirtualPath) : new DefaultWidgetContainer();
186+
187+
widgetContainer.ID = "widgetContainer" + widgetControl.ID;
188+
widgetContainer.Widget = widgetControl;
189+
190+
return widgetContainer;
191+
}
192+
193+
/// <summary>
194+
/// Loads the widget container (either the one located in the theme folder, or the default one if
195+
/// a theme widget container is missing), and adds the Widget to the widget container.
196+
/// </summary>
197+
public static WidgetContainer GetWidgetContainer(
198+
WidgetBase widgetControl)
199+
{
200+
return GetWidgetContainer(widgetControl, DoesThemeWidgetContainerExist(true), GetThemeWidgetContainerVirtualPath(false));
201+
}
202+
}
203+
204+
/// <summary>
205+
/// Default implementation of WidgetContainer that provides backwards compatibility with themes that do not have
206+
/// their own WidgetContainer user control.
207+
/// </summary>
208+
internal sealed class DefaultWidgetContainer : WidgetContainer
209+
{
210+
/// <summary>
211+
/// The widgetBody instance needed by all WidgetContainers.
212+
/// </summary>
213+
private readonly System.Web.UI.WebControls.PlaceHolder widgetBody = new System.Web.UI.WebControls.PlaceHolder
214+
{
215+
ID = "phWidgetBody"
216+
};
217+
218+
/// <summary>
219+
/// Initializes a new instance of the <see cref="DefaultWidgetContainer"/> class.
220+
/// </summary>
221+
internal DefaultWidgetContainer()
222+
{
223+
this.Controls.Add(this.widgetBody);
224+
}
225+
226+
/// <summary>
227+
/// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to be rendered on the client.
228+
/// </summary>
229+
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
230+
protected override void Render(HtmlTextWriter writer)
231+
{
232+
if (this.Widget == null)
233+
{
234+
throw new NullReferenceException("WidgetContainer requires its Widget property be set to a valid WidgetBase derived control");
235+
}
236+
237+
var widgetName = this.Widget.Name;
238+
var widgetId = this.Widget.WidgetId;
239+
240+
if (string.IsNullOrEmpty(this.Widget.Name))
241+
{
242+
throw new NullReferenceException("Name must be set on a widget");
243+
}
244+
245+
var sb = new StringBuilder();
246+
247+
sb.AppendFormat("<div class=\"widget {0}\" id=\"widget{1}\">", widgetName.Replace(" ", string.Empty).ToLowerInvariant(), widgetId);
248+
sb.Append(this.AdminLinks);
249+
if (this.Widget.ShowTitle)
250+
{
251+
sb.AppendFormat("<h4>{0}</h4>", this.Widget.Title);
252+
}
253+
254+
sb.Append("<div class=\"content\">");
255+
256+
writer.Write(sb.ToString());
257+
base.Render(writer);
258+
writer.Write("</div>");
259+
writer.Write("</div>");
260+
}
261+
}
262+
}

0 commit comments

Comments
 (0)