#region Using
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Hosting;
using System.Xml;
using System.IO;
using System.Text;
using BlogEngine.Core;
using BlogEngine.Core.DataStore;
#endregion
public partial class User_controls_WidgetEditor : System.Web.UI.Page
{
#region Event handlers
///
/// Handles the Load event of the Page control.
///
/// The source of the event.
/// The instance containing the event data.
protected void Page_Init(object sender, EventArgs e)
{
if (!User.IsInRole(BlogSettings.Instance.AdministratorRole))
{
Response.StatusCode = 403;
Response.Clear();
Response.End();
}
string widget = Request.QueryString["widget"];
string id = Request.QueryString["id"];
string move = Request.QueryString["move"];
string add = Request.QueryString["add"];
string remove = Request.QueryString["remove"];
string zone = Request.QueryString["zone"];
string getMoveItems = Request.QueryString["getmoveitems"];
if (!string.IsNullOrEmpty(widget) && !string.IsNullOrEmpty(id))
InitEditor(widget, id, zone);
if (!string.IsNullOrEmpty(move))
MoveWidgets(move);
if (!string.IsNullOrEmpty(add))
AddWidget(add, zone);
if (!string.IsNullOrEmpty(remove) && remove.Length == 36)
RemoveWidget(remove, zone);
if (!string.IsNullOrEmpty(getMoveItems))
GetMoveItems(getMoveItems);
}
///
/// Handles the Click event of the btnSave control.
///
/// The source of the event.
/// The instance containing the event data.
private void btnSave_Click(object sender, EventArgs e)
{
WidgetEditBase widget = (WidgetEditBase)FindControl("widget");
string zone = Request.QueryString["zone"];
if (widget != null)
widget.Save();
XmlDocument doc = GetXmlDocument(zone);
XmlNode node = doc.SelectSingleNode("//widget[@id=\"" + Request.QueryString["id"] + "\"]");
bool isChanged = false;
if (node.Attributes["title"].InnerText != txtTitle.Text.Trim())
{
node.Attributes["title"].InnerText = txtTitle.Text.Trim();
isChanged = true;
}
if (node.Attributes["showTitle"].InnerText != cbShowTitle.Checked.ToString())
{
node.Attributes["showTitle"].InnerText = cbShowTitle.Checked.ToString();
isChanged = true;
}
if (isChanged)
SaveXmlDocument(doc, zone);
WidgetEditBase.OnSaved();
Cache.Remove("widget_" + Request.QueryString["id"]);
// To avoid JS errors with TextBox widget loading tinyMce scripts while
// the edit window is closing, don't output phEdit.
phEdit.Visible = false;
string script = "PostEdit();";
Page.ClientScript.RegisterStartupScript(this.GetType(), "closeWindow", script, true);
}
#endregion
///
/// Sends a list of the widget zones and containing widgets in the Response.
///
/// The list of zones to retrieve a list of widgets for.
private void GetMoveItems(string zoneNames)
{
string moveWidgetTo = (string)GetGlobalResourceObject("labels", "moveWidgetTo") ?? string.Empty;
StringBuilder sb = new StringBuilder();
sb.Append("{ moveWidgetTo: '" + moveWidgetTo.Replace("'", "\\'") + "', zones: [");
if (!string.IsNullOrEmpty(zoneNames))
{
bool isFirstZone = true;
string[] zones = zoneNames.Split(',');
foreach (string zone in zones)
{
if (!isFirstZone)
sb.Append(",");
// Zone names won't have single quotation marks in their names, because they were ran
// through Utils.RemoveIllegalCharacters(). Therefore, escaping is unnecessary.
sb.Append(" { zoneName: '" + zone + "', widgets: [ ");
XmlDocument doc = GetXmlDocument(zone);
bool isFirstWidget = true;
foreach (XmlNode node in doc.SelectSingleNode("widgets").ChildNodes)
{
if (!isFirstWidget)
sb.Append(",");
// Shorten excessively long titles. Since the title/description is only
// used for display purposes in the "move to" dropdown list, this is okay.
// Also strip HTML. The Visitor Widget (for example) has an
tag in
// its Title by default which causes issues when added an an option to the
// dropdown list.
string title = Utils.StripHtml(node.Attributes["title"].InnerText ?? string.Empty);
if (title.Length > 20)
title = title.Substring(0, 20) + "...";
// Need to escape single quotation marks in widget type and widget title.
string description =
Utils.StripHtml(node.InnerText).Replace("'", "\\'") +
(!string.IsNullOrEmpty(title) &&
bool.Parse(node.Attributes["showTitle"].InnerText) ?
" (" + title.Replace("'", "\\'") + ")" : string.Empty);
sb.Append(
" { id: '" + node.Attributes["id"].InnerText + "', " +
" desc: '" + description + "' } ");
isFirstWidget = false;
}
sb.Append(" ] } ");
isFirstZone = false;
}
}
sb.Append(" ] } ");
Response.Clear();
Response.Write(sb.ToString());
Response.End();
}
///
/// Removes the widget from the XML file.
///
/// The id of the widget to remove.
/// The zone a widget is being removed from.
private void RemoveWidget(string id, string zone)
{
XmlDocument doc = GetXmlDocument(zone);
XmlNode node = doc.SelectSingleNode("//widget[@id=\"" + id + "\"]");
if (node != null)
{
// remove widget reference in the widget zone
node.ParentNode.RemoveChild(node);
SaveXmlDocument(doc, zone);
// remove widget itself
BlogEngine.Core.Providers.BlogService.RemoveFromDataStore(ExtensionType.Widget, id);
Cache.Remove("be_widget_" + id);
WidgetEditBase.OnSaved();
Response.Clear();
Response.Write(id + zone);
Response.End();
}
}
///
/// Adds a widget of the specified type.
///
/// The type of widget.
/// The zone a widget is being added to.
private void AddWidget(string type, string zone)
{
WidgetBase widget = (WidgetBase)LoadControl(Utils.RelativeWebRoot + "widgets/" + type + "/widget.ascx");
widget.WidgetID = Guid.NewGuid();
widget.ID = widget.WidgetID.ToString().Replace("-", string.Empty);
widget.Title = type;
widget.Zone = zone;
widget.ShowTitle = widget.DisplayHeader;
widget.LoadWidget();
Response.Clear();
try
{
using (StringWriter sw = new StringWriter())
{
widget.RenderControl(new HtmlTextWriter(sw));
// Using ? as a delimiter. ? is a safe delimiter because it cannot appear in a
// zonename because ? is one of the characters removed by Utils.RemoveIllegalCharacters().
Response.Write(zone + "?" + sw);
}
}
catch (System.Web.HttpException)
{
Response.Write("reload");
}
SaveNewWidget(widget, zone);
WidgetEditBase.OnSaved();
Response.End();
}
///
/// Saves the new widget to the XML file.
///
/// The widget to add.
/// The zone a widget is being added to.
private void SaveNewWidget(WidgetBase widget, string zone)
{
XmlDocument doc = GetXmlDocument(zone);
XmlNode node = doc.CreateElement("widget");
node.InnerText = widget.Name;
XmlAttribute id = doc.CreateAttribute("id");
id.InnerText = widget.WidgetID.ToString();
node.Attributes.Append(id);
XmlAttribute title = doc.CreateAttribute("title");
title.InnerText = widget.Title;
node.Attributes.Append(title);
XmlAttribute show = doc.CreateAttribute("showTitle");
show.InnerText = "True";
node.Attributes.Append(show);
doc.SelectSingleNode("widgets").AppendChild(node);
SaveXmlDocument(doc, zone);
}
///
/// Moves the widgets as specified while dragging and dropping.
///
/// Data containing which widget is moving, where it's moving from and where it's moving to.
private void MoveWidgets(string moveData)
{
string responseData = string.Empty;
string[] data = moveData.Split(',');
if (data.Length == 4)
{
string oldZone = data[0];
string widgetToMoveId = data[1];
string newZone = data[2];
string moveBeforeWidgetId = data[3];
// Ensure widgetToMoveId and moveBeforeWidgetId are not the same.
if (!widgetToMoveId.Equals(moveBeforeWidgetId))
{
XmlDocument oldZoneDoc = GetXmlDocument(oldZone);
XmlDocument newZoneDoc = GetXmlDocument(newZone);
// If a widget is moving within its own widget, oldZoneDoc and newZoneDoc will
// be referencing the same XmlDocument. This is okay.
if (oldZoneDoc != null && newZoneDoc != null)
{
// Make sure we can find all required elements before moving anything.
XmlNode widgetToMove = oldZoneDoc.SelectSingleNode("//widget[@id=\"" + widgetToMoveId + "\"]");
// If a Zone was selected from the dropdown box (rather than a Widget), moveBeforeWidgetId
// will be null. In this case, the widget is moved to the bottom of the new zone.
XmlNode moveBeforeWidget = null;
if (!string.IsNullOrEmpty(moveBeforeWidgetId))
moveBeforeWidget = newZoneDoc.SelectSingleNode("//widget[@id=\"" + moveBeforeWidgetId + "\"]");
if (widgetToMove != null)
{
// If the XmlNode is moving into a different XmlDocument, need to ImportNode() to
// create a copy of the XmlNode that is compatible with the new XmlDocument.
XmlNode widgetToMoveIntoNewDoc = newZoneDoc.ImportNode(widgetToMove, true);
widgetToMove.ParentNode.RemoveChild(widgetToMove);
if (moveBeforeWidget == null)
newZoneDoc.SelectSingleNode("widgets").AppendChild(widgetToMoveIntoNewDoc);
else
moveBeforeWidget.ParentNode.InsertBefore(widgetToMoveIntoNewDoc, moveBeforeWidget);
SaveXmlDocument(oldZoneDoc, oldZone);
if (!oldZone.Equals(newZone))
SaveXmlDocument(newZoneDoc, newZone);
WidgetEditBase.OnSaved();
// Pass back the same data that was sent in to indicate success.
responseData = moveData;
}
}
}
}
Response.Clear();
Response.Write(responseData);
Response.End();
}
#region Helper methods
private static readonly string FILE_NAME = HostingEnvironment.MapPath(BlogSettings.Instance.StorageLocation + "widgetzone.xml");
///
/// Gets the XML document.
///
/// The zone Xml Document to get.
///
private XmlDocument GetXmlDocument(string zone)
{
XmlDocument doc;
if (Cache[zone] == null)
{
WidgetSettings ws = new WidgetSettings(zone);
ws.SettingsBehavior = new XMLDocumentBehavior();
doc = (XmlDocument)ws.GetSettings();
if (doc.SelectSingleNode("widgets") == null)
{
XmlNode widgets = doc.CreateElement("widgets");
doc.AppendChild(widgets);
}
Cache[zone] = doc;
}
return (XmlDocument)Cache[zone];
}
///
/// Saves the XML document.
///
/// The doc.
/// The zone to save the Xml Document for.
private void SaveXmlDocument(XmlDocument doc, string zone)
{
WidgetSettings ws = new WidgetSettings(zone);
ws.SettingsBehavior = new XMLDocumentBehavior();
ws.SaveSettings(doc);
Cache[zone] = doc;
}
///
/// Inititiates the editor for widget editing.
///
/// The type of widget to edit.
/// The id of the particular widget to edit.
/// The zone the widget to be edited is in.
private void InitEditor(string type, string id, string zone)
{
XmlDocument doc = GetXmlDocument(zone);
XmlNode node = doc.SelectSingleNode("//widget[@id=\"" + id + "\"]");
string fileName = Utils.RelativeWebRoot + "widgets/" + type + "/edit.ascx";
if (File.Exists(Server.MapPath(fileName)))
{
WidgetEditBase edit = (WidgetEditBase)LoadControl(fileName);
edit.WidgetID = new Guid(node.Attributes["id"].InnerText);
edit.Title = node.Attributes["title"].InnerText;
edit.ID = "widget";
edit.ShowTitle = bool.Parse(node.Attributes["showTitle"].InnerText);
phEdit.Controls.Add(edit);
}
if (!Page.IsPostBack)
{
cbShowTitle.Checked = bool.Parse(node.Attributes["showTitle"].InnerText);
txtTitle.Text = node.Attributes["title"].InnerText;
txtTitle.Focus();
btnSave.Text = Resources.labels.save;
}
btnSave.Click += new EventHandler(btnSave_Click);
}
#endregion
}