775 lines
28 KiB
C#
775 lines
28 KiB
C#
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Data;
|
|
using System.Web;
|
|
using System.Web.Security;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.UI.WebControls.WebParts;
|
|
using System.Web.UI.HtmlControls;
|
|
using ScrewTurn.Wiki.PluginFramework;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Linq;
|
|
|
|
namespace ScrewTurn.Wiki {
|
|
|
|
public partial class Edit : BasePage {
|
|
|
|
private PageInfo currentPage = null;
|
|
private PageContent currentContent = null;
|
|
private bool isDraft = false;
|
|
private int currentSection = -1;
|
|
|
|
private bool canEdit = false;
|
|
private bool canEditWithApproval = false;
|
|
private bool canCreateNewPages = false;
|
|
private bool canCreateNewCategories = false;
|
|
private bool canManagePageCategories = false;
|
|
private bool canDownloadAttachments = false;
|
|
|
|
/// <summary>
|
|
/// Detects the permissions for the current user.
|
|
/// </summary>
|
|
/// <remarks><b>currentPage</b> should be set before calling this method.</remarks>
|
|
private void DetectPermissions() {
|
|
string currentUser = SessionFacade.GetCurrentUsername();
|
|
string[] currentGroups = SessionFacade.GetCurrentGroupNames();
|
|
|
|
if(currentPage != null) {
|
|
Pages.CanEditPage(currentPage, currentUser, currentGroups, out canEdit, out canEditWithApproval);
|
|
canCreateNewPages = false; // Least privilege
|
|
canCreateNewCategories = AuthChecker.CheckActionForNamespace(Pages.FindNamespace(NameTools.GetNamespace(currentPage.FullName)),
|
|
Actions.ForNamespaces.ManageCategories, currentUser, currentGroups);
|
|
canManagePageCategories = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ManageCategories, currentUser, currentGroups);
|
|
canDownloadAttachments = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.DownloadAttachments, currentUser, currentGroups);
|
|
}
|
|
else {
|
|
NamespaceInfo ns = DetectNamespaceInfo();
|
|
canCreateNewPages = AuthChecker.CheckActionForNamespace(ns, Actions.ForNamespaces.CreatePages, currentUser, currentGroups);
|
|
canCreateNewCategories = AuthChecker.CheckActionForNamespace(ns, Actions.ForNamespaces.ManageCategories, currentUser, currentGroups);
|
|
canManagePageCategories = canCreateNewCategories;
|
|
canDownloadAttachments = AuthChecker.CheckActionForNamespace(ns, Actions.ForNamespaces.DownloadAttachments, currentUser, currentGroups);
|
|
}
|
|
}
|
|
|
|
protected void Page_Load(object sender, EventArgs e) {
|
|
|
|
Page.Title = Properties.Messages.EditTitle + " - " + Settings.WikiTitle;
|
|
|
|
lblEditNotice.Text = Formatter.FormatPhase3(Formatter.Format(Settings.Provider.GetMetaDataItem(
|
|
MetaDataItem.EditNotice, DetectNamespace()), false, FormattingContext.Other, null), FormattingContext.Other, null);
|
|
|
|
// Prepare page unload warning
|
|
string ua = Request.UserAgent;
|
|
if(!string.IsNullOrEmpty(ua)) {
|
|
ua = ua.ToLowerInvariant();
|
|
StringBuilder sbua = new StringBuilder(50);
|
|
sbua.Append(@"<script type=""text/javascript"">");
|
|
sbua.Append("\r\n<!--\r\n");
|
|
if(ua.Contains("gecko")) {
|
|
// Mozilla
|
|
sbua.Append("addEventListener('beforeunload', __UnloadPage, true);");
|
|
}
|
|
else {
|
|
// IE
|
|
sbua.Append("window.attachEvent('onbeforeunload', __UnloadPage);");
|
|
}
|
|
sbua.Append("\r\n// -->\r\n");
|
|
sbua.Append("</script>");
|
|
lblUnloadPage.Text = sbua.ToString();
|
|
}
|
|
|
|
if(!Page.IsPostBack) {
|
|
PopulateCategories(new CategoryInfo[0]);
|
|
|
|
if(Settings.AutoGeneratePageNames) {
|
|
pnlPageName.Visible = false;
|
|
pnlManualName.Visible = true;
|
|
}
|
|
}
|
|
|
|
// Load requested page, if any
|
|
if(Request["Page"] != null) {
|
|
string name = Request["Page"];
|
|
|
|
currentPage = Pages.FindPage(name);
|
|
|
|
// If page already exists, load the content and disable page name,
|
|
// otherwise pre-fill page name
|
|
if(currentPage != null) {
|
|
// Look for a draft
|
|
currentContent = Pages.GetDraft(currentPage);
|
|
|
|
if(currentContent == null) {
|
|
// No cache because the page will be probably modified in a few minutes
|
|
currentContent = Content.GetPageContent(currentPage, false);
|
|
}
|
|
else isDraft = true;
|
|
|
|
// Set current page for editor and attachment manager
|
|
editor.CurrentPage = currentPage;
|
|
attachmentManager.CurrentPage = currentPage;
|
|
|
|
if(!int.TryParse(Request["Section"], out currentSection)) currentSection = -1;
|
|
|
|
// Fill data, if not posted back
|
|
if(!Page.IsPostBack) {
|
|
// Set keywords, description
|
|
SetKeywords(currentContent.Keywords);
|
|
txtDescription.Text = currentContent.Description;
|
|
|
|
txtName.Text = NameTools.GetLocalName(currentPage.FullName);
|
|
txtName.Enabled = false;
|
|
pnlPageName.Visible = false;
|
|
pnlManualName.Visible = false;
|
|
|
|
PopulateCategories(Pages.GetCategoriesForPage(currentPage));
|
|
|
|
txtTitle.Text = currentContent.Title;
|
|
|
|
// Manage section, if appropriate (disable if draft)
|
|
if(!isDraft && currentSection != -1) {
|
|
int startIndex, len;
|
|
string dummy = "";
|
|
ExtractSection(currentContent.Content, currentSection, out startIndex, out len, out dummy);
|
|
editor.SetContent(currentContent.Content.Substring(startIndex, len), Settings.UseVisualEditorAsDefault);
|
|
}
|
|
else {
|
|
// Select default editor view (WikiMarkup or Visual) and populate content
|
|
editor.SetContent(currentContent.Content, Settings.UseVisualEditorAsDefault);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Pre-fill name, if not posted back
|
|
if(!Page.IsPostBack) {
|
|
// Set both name and title, as the NAME was provided from the query-string and must be preserved
|
|
pnlPageName.Visible = true;
|
|
pnlManualName.Visible = false;
|
|
txtName.Text = NameTools.GetLocalName(name);
|
|
txtTitle.Text = txtName.Text;
|
|
editor.SetContent(LoadTemplateIfAppropriate(), Settings.UseVisualEditorAsDefault);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if(!Page.IsPostBack) {
|
|
chkMinorChange.Visible = false;
|
|
chkSaveAsDraft.Visible = false;
|
|
|
|
editor.SetContent(LoadTemplateIfAppropriate(), Settings.UseVisualEditorAsDefault);
|
|
}
|
|
}
|
|
|
|
// Here is centralized all permissions-checking code
|
|
DetectPermissions();
|
|
|
|
// Verify the following permissions:
|
|
// - if new page, check for page creation perms
|
|
// - else, check for editing perms
|
|
// - full edit or edit with approval
|
|
// - categories management
|
|
// - attachment manager
|
|
// - CAPTCHA if enabled and user is anonymous
|
|
// ---> recheck every time an action is performed
|
|
|
|
if(currentPage == null) {
|
|
// Check permissions for creating new pages
|
|
if(!canCreateNewPages) {
|
|
if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Request.Url.ToString()));
|
|
else UrlTools.Redirect("AccessDenied.aspx");
|
|
}
|
|
}
|
|
else {
|
|
// Check permissions for editing current page
|
|
if(!canEdit && !canEditWithApproval) {
|
|
if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Request.Url.ToString()));
|
|
else UrlTools.Redirect("AccessDenied.aspx");
|
|
}
|
|
}
|
|
|
|
if(!canEdit && canEditWithApproval) {
|
|
// Hard-wire status of draft and minor change checkboxes
|
|
chkMinorChange.Enabled = false;
|
|
chkSaveAsDraft.Enabled = false;
|
|
chkSaveAsDraft.Checked = true;
|
|
}
|
|
|
|
// Setup categories
|
|
lstCategories.Enabled = canManagePageCategories;
|
|
pnlCategoryCreation.Visible = canCreateNewCategories;
|
|
|
|
// Setup attachment manager (require at least download permissions)
|
|
attachmentManager.Visible = canDownloadAttachments;
|
|
|
|
// CAPTCHA
|
|
pnlCaptcha.Visible = SessionFacade.LoginKey == null && !Settings.DisableCaptchaControl;
|
|
captcha.Visible = pnlCaptcha.Visible;
|
|
|
|
// Moderation notice
|
|
pnlApprovalRequired.Visible = !canEdit && canEditWithApproval;
|
|
|
|
// Check and manage editing collisions
|
|
ManageEditingCollisions();
|
|
|
|
if(!Page.IsPostBack) {
|
|
ManageTemplatesDisplay();
|
|
|
|
// Display draft status
|
|
ManageDraft();
|
|
}
|
|
|
|
// Setup session refresh iframe
|
|
PrintSessionRefresh();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Manages the display of the template selection controls.
|
|
/// </summary>
|
|
private void ManageTemplatesDisplay() {
|
|
// Hide templates selection if there aren't any or if the editor is not in WikiMarkup mode
|
|
if(Templates.GetTemplates().Count == 0 || !editor.IsInWikiMarkup()) {
|
|
btnTemplates.Visible = false;
|
|
pnlTemplates.Visible = false;
|
|
}
|
|
else btnTemplates.Visible = true;
|
|
}
|
|
|
|
protected void editor_SelectedTabChanged(object sender, SelectedTabChangedEventArgs e) {
|
|
ManageTemplatesDisplay();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads a content template when the query strings specifies it.
|
|
/// </summary>
|
|
/// <returns>The content of the selected template.</returns>
|
|
private string LoadTemplateIfAppropriate() {
|
|
if(string.IsNullOrEmpty(Request["Template"])) return "";
|
|
ContentTemplate template = Templates.Find(Request["Template"]);
|
|
if(template == null) return "";
|
|
else {
|
|
lblAutoTemplate.Text = lblAutoTemplate.Text.Replace("##TEMPLATE##", template.Name);
|
|
pnlAutoTemplate.Visible = true;
|
|
return template.Content;
|
|
}
|
|
}
|
|
|
|
protected void btnAutoTemplateOK_Click(object sender, EventArgs e) {
|
|
pnlAutoTemplate.Visible = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints the session refresh code in the page.
|
|
/// </summary>
|
|
public void PrintSessionRefresh() {
|
|
StringBuilder sb = new StringBuilder(50);
|
|
sb.Append(@"<iframe src=""");
|
|
if(currentPage != null) sb.AppendFormat("SessionRefresh.aspx?Page={0}", Tools.UrlEncode(currentPage.FullName));
|
|
else sb.Append("SessionRefresh.aspx");
|
|
sb.Append(@""" style=""width: 1px; height: 1px; border: none;"" scrolling=""no""></iframe>");
|
|
|
|
lblSessionRefresh.Text = sb.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies for editing collisions, and if no collision is found, "locks" the page
|
|
/// </summary>
|
|
private void ManageEditingCollisions() {
|
|
if(currentPage == null) return;
|
|
|
|
lblRefreshLink.Text = @"<a href=""" +
|
|
UrlTools.BuildUrl("Edit.aspx?Page=", Tools.UrlEncode(currentPage.FullName), (Request["Section"] != null ? "&Section=" + currentSection.ToString() : "")) +
|
|
@""">" + Properties.Messages.Refresh + " »</a>";
|
|
|
|
string username = Request.UserHostAddress;
|
|
if(SessionFacade.LoginKey != null) username = SessionFacade.CurrentUsername;
|
|
|
|
if(Collisions.IsPageBeingEdited(currentPage, username)) {
|
|
pnlCollisions.Visible = true;
|
|
lblConcurrentEditingUsername.Text = "(" + Users.UserLink(Collisions.WhosEditing(currentPage)) + ")";
|
|
if(Settings.DisableConcurrentEditing) {
|
|
lblSaveDisabled.Visible = true;
|
|
lblSaveDangerous.Visible = false;
|
|
btnSave.Enabled = false;
|
|
btnSaveAndContinue.Enabled = false;
|
|
}
|
|
else {
|
|
lblSaveDisabled.Visible = false;
|
|
lblSaveDangerous.Visible = true;
|
|
btnSave.Enabled = true;
|
|
btnSaveAndContinue.Enabled = true;
|
|
}
|
|
}
|
|
else {
|
|
pnlCollisions.Visible = false;
|
|
btnSave.Enabled = true;
|
|
btnSaveAndContinue.Enabled = true;
|
|
Collisions.RenewEditingSession(currentPage, username);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Manages the draft status display.
|
|
/// </summary>
|
|
private void ManageDraft() {
|
|
if(isDraft) {
|
|
chkSaveAsDraft.Checked = true;
|
|
chkMinorChange.Enabled = false;
|
|
pnlDraft.Visible = true;
|
|
lblDraftInfo.Text = lblDraftInfo.Text.Replace("##USER##",
|
|
Users.UserLink(currentContent.User, true)).Replace("##DATETIME##",
|
|
Preferences.AlignWithTimezone(currentContent.LastModified).ToString(Settings.DateTimeFormat)).Replace("##VIEWCHANGES##",
|
|
string.Format("<a href=\"{0}\" target=\"_blank\">{1}</a>", UrlTools.BuildUrl("Diff.aspx?Page=",
|
|
Tools.UrlEncode(currentPage.FullName), "&Rev1=Current&Rev2=Draft"),
|
|
Properties.Messages.ViewChanges));
|
|
}
|
|
else {
|
|
pnlDraft.Visible = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the categories for the current namespace and provider, selecting the ones specified.
|
|
/// </summary>
|
|
/// <param name="toSelect">The categories to select.</param>
|
|
private void PopulateCategories(CategoryInfo[] toSelect) {
|
|
IPagesStorageProviderV30 provider = FindAppropriateProvider();
|
|
List<CategoryInfo> cats = Pages.GetCategories(DetectNamespaceInfo());
|
|
lstCategories.Items.Clear();
|
|
foreach(CategoryInfo c in cats) {
|
|
if(c.Provider == provider) {
|
|
ListItem itm = new ListItem(NameTools.GetLocalName(c.FullName), c.FullName);
|
|
if(Array.Find<CategoryInfo>(toSelect, delegate(CategoryInfo s) { return s.FullName == c.FullName; }) != null)
|
|
itm.Selected = true;
|
|
lstCategories.Items.Add(itm);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void btnManualName_Click(object sender, EventArgs e) {
|
|
pnlPageName.Visible = true;
|
|
pnlManualName.Visible = false;
|
|
txtName.Text = GenerateAutoName(txtTitle.Text);
|
|
pnlManualName.UpdateAfterCallBack = true;
|
|
pnlPageName.UpdateAfterCallBack = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates an automatic page name.
|
|
/// </summary>
|
|
/// <param name="title">The page title.</param>
|
|
/// <returns>The name.</returns>
|
|
private static string GenerateAutoName(string title) {
|
|
// Replace all non-alphanumeric characters with dashes
|
|
if(title.Length == 0) return "";
|
|
|
|
StringBuilder buffer = new StringBuilder(title.Length);
|
|
|
|
foreach(char ch in title.Normalize(NormalizationForm.FormD).Replace("\"", "").Replace("'", "")) {
|
|
var unicat = char.GetUnicodeCategory(ch);
|
|
if(unicat == System.Globalization.UnicodeCategory.LowercaseLetter ||
|
|
unicat == System.Globalization.UnicodeCategory.UppercaseLetter ||
|
|
unicat == System.Globalization.UnicodeCategory.DecimalDigitNumber) {
|
|
buffer.Append(ch);
|
|
}
|
|
else if(unicat != System.Globalization.UnicodeCategory.NonSpacingMark) buffer.Append("-");
|
|
}
|
|
|
|
while(buffer.ToString().IndexOf("--") >= 0) {
|
|
buffer.Replace("--", "-");
|
|
}
|
|
|
|
return buffer.ToString().Trim('-');
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the start and end positions of a section of the content.
|
|
/// </summary>
|
|
/// <param name="content">The content.</param>
|
|
/// <param name="section">The section ID.</param>
|
|
/// <param name="start">The index of the first character of the section.</param>
|
|
/// <param name="len">The length of the section.</param>
|
|
/// <param name="anchor">The anchor ID of the section.</param>
|
|
private static void ExtractSection(string content, int section, out int start, out int len, out string anchor) {
|
|
List<HPosition> hPos = Formatter.DetectHeaders(content);
|
|
start = 0;
|
|
len = content.Length;
|
|
anchor = "";
|
|
int level = -1;
|
|
bool found = false;
|
|
for(int i = 0; i < hPos.Count; i++) {
|
|
if(hPos[i].ID == section) {
|
|
start = hPos[i].Index;
|
|
len = len - start;
|
|
level = hPos[i].Level; // Level is used to edit the current section AND all the subsections
|
|
// Set the anchor value so that it's possible to redirect the user to the just edited section
|
|
anchor = Formatter.BuildHAnchor(hPos[i].Text);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if(found) {
|
|
int diff = len;
|
|
for(int i = 0; i < hPos.Count; i++) {
|
|
if(hPos[i].Index > start && // Next section (Hx)
|
|
hPos[i].Index - start < diff && // The nearest section
|
|
hPos[i].Level <= level) { // Of the same level or higher
|
|
len = hPos[i].Index - start - 1;
|
|
diff = hPos[i].Index - start;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void btnCancel_Click(object sender, EventArgs e) {
|
|
if(currentPage == null && txtName.Visible) currentPage = Pages.FindPage(NameTools.GetFullName(DetectNamespace(), txtName.Text));
|
|
if(currentPage != null) UrlTools.Redirect(Tools.UrlEncode(currentPage.FullName) + Settings.PageExtension);
|
|
else UrlTools.Redirect(UrlTools.BuildUrl("Default.aspx"));
|
|
}
|
|
|
|
protected void cvName1_ServerValidate(object sender, ServerValidateEventArgs e) {
|
|
e.IsValid = !txtName.Enabled || Pages.IsValidName(txtName.Text);
|
|
}
|
|
|
|
protected void cvName2_ServerValidate(object sender, ServerValidateEventArgs e) {
|
|
e.IsValid = !txtName.Enabled || Pages.FindPage(NameTools.GetFullName(DetectNamespace(), txtName.Text)) == null;
|
|
}
|
|
|
|
protected void chkMinorChange_CheckedChanged(object sender, EventArgs e) {
|
|
if(chkMinorChange.Checked) {
|
|
// Save as draft is not available
|
|
chkSaveAsDraft.Checked = false;
|
|
chkSaveAsDraft.Enabled = false;
|
|
}
|
|
else {
|
|
chkSaveAsDraft.Enabled = true;
|
|
}
|
|
}
|
|
|
|
protected void chkSaveAsDraft_CheckedChanged(object sender, EventArgs e) {
|
|
if(chkSaveAsDraft.Checked) {
|
|
// Minor change is not available
|
|
chkMinorChange.Checked = false;
|
|
chkMinorChange.Enabled = false;
|
|
}
|
|
else {
|
|
chkMinorChange.Enabled = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the appropriate provider to use for operations.
|
|
/// </summary>
|
|
/// <returns>The provider.</returns>
|
|
private IPagesStorageProviderV30 FindAppropriateProvider() {
|
|
IPagesStorageProviderV30 provider = null;
|
|
|
|
if(currentPage != null) provider = currentPage.Provider;
|
|
else {
|
|
NamespaceInfo currentNamespace = DetectNamespaceInfo();
|
|
provider =
|
|
currentNamespace == null ?
|
|
Collectors.PagesProviderCollector.GetProvider(Settings.DefaultPagesProvider) :
|
|
currentNamespace.Provider;
|
|
}
|
|
|
|
return provider;
|
|
}
|
|
|
|
protected void btnSave_Click(object sender, EventArgs e) {
|
|
bool wasVisible = pnlPageName.Visible;
|
|
pnlPageName.Visible = true;
|
|
|
|
if(!wasVisible && Settings.AutoGeneratePageNames && txtName.Enabled) {
|
|
txtName.Text = GenerateAutoName(txtTitle.Text);
|
|
}
|
|
|
|
Page.Validate("nametitle");
|
|
Page.Validate("captcha");
|
|
if(!Page.IsValid) {
|
|
if(!rfvTitle.IsValid || !rfvName.IsValid || !cvName1.IsValid || !cvName2.IsValid) {
|
|
pnlPageName.Visible = true;
|
|
pnlManualName.Visible = false;
|
|
pnlPageName.UpdateAfterCallBack = true;
|
|
pnlManualName.UpdateAfterCallBack = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pnlPageName.Visible = wasVisible;
|
|
|
|
// Check permissions
|
|
if(currentPage == null) {
|
|
// Check permissions for creating new pages
|
|
if(!canCreateNewPages) UrlTools.Redirect("AccessDenied.aspx");
|
|
}
|
|
else {
|
|
// Check permissions for editing current page
|
|
if(!canEdit && !canEditWithApproval) UrlTools.Redirect("AccessDenied.aspx");
|
|
}
|
|
|
|
chkMinorChange.Visible = true;
|
|
chkSaveAsDraft.Visible = true;
|
|
|
|
// Verify edit with approval
|
|
if(!canEdit && canEditWithApproval) {
|
|
chkSaveAsDraft.Checked = true;
|
|
}
|
|
|
|
// Check for scripts (Administrators can always add SCRIPT tags)
|
|
if(!SessionFacade.GetCurrentGroupNames().Contains(Settings.AdministratorsGroup) && !Settings.ScriptTagsAllowed) {
|
|
Regex r = new Regex(@"\<script.*?\>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
if(r.Match(editor.GetContent()).Success) {
|
|
lblResult.Text = @"<span style=""color: #FF0000;"">" + Properties.Messages.ScriptDetected + "</span>";
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool redirect = true;
|
|
if(sender == btnSaveAndContinue) redirect = false;
|
|
|
|
lblResult.Text = "";
|
|
lblResult.CssClass = "";
|
|
|
|
string username = "";
|
|
if(SessionFacade.LoginKey == null) username = Request.UserHostAddress;
|
|
else username = SessionFacade.CurrentUsername;
|
|
|
|
IPagesStorageProviderV30 provider = FindAppropriateProvider();
|
|
|
|
// Create list of selected categories
|
|
List<CategoryInfo> categories = new List<CategoryInfo>();
|
|
for(int i = 0; i < lstCategories.Items.Count; i++) {
|
|
if(lstCategories.Items[i].Selected) {
|
|
CategoryInfo cat = Pages.FindCategory(lstCategories.Items[i].Value);
|
|
|
|
// Sanity check
|
|
if(cat.Provider == provider) categories.Add(cat);
|
|
}
|
|
}
|
|
|
|
txtComment.Text = txtComment.Text.Trim();
|
|
txtDescription.Text = txtDescription.Text.Trim();
|
|
|
|
SaveMode saveMode = SaveMode.Backup;
|
|
if(chkSaveAsDraft.Checked) saveMode = SaveMode.Draft;
|
|
if(chkMinorChange.Checked) saveMode = SaveMode.Normal;
|
|
|
|
if(txtName.Enabled) {
|
|
// Find page, if inexistent create it
|
|
PageInfo pg = Pages.FindPage(NameTools.GetFullName(DetectNamespace(), txtName.Text), provider);
|
|
if(pg == null) {
|
|
Pages.CreatePage(DetectNamespaceInfo(), txtName.Text, provider);
|
|
pg = Pages.FindPage(NameTools.GetFullName(DetectNamespace(), txtName.Text), provider);
|
|
saveMode = SaveMode.Normal;
|
|
attachmentManager.CurrentPage = pg;
|
|
}
|
|
Log.LogEntry("Page update requested for " + txtName.Text, EntryType.General, username);
|
|
|
|
Pages.ModifyPage(pg, txtTitle.Text, username, DateTime.Now, txtComment.Text, editor.GetContent(),
|
|
GetKeywords(), txtDescription.Text, saveMode);
|
|
|
|
// Save categories binding
|
|
Pages.Rebind(pg, categories.ToArray());
|
|
|
|
// If not a draft, remove page draft
|
|
if(saveMode != SaveMode.Draft) {
|
|
Pages.DeleteDraft(currentPage);
|
|
isDraft = false;
|
|
}
|
|
else isDraft = true;
|
|
|
|
ManageDraft();
|
|
|
|
lblResult.CssClass = "resultok";
|
|
lblResult.Text = Properties.Messages.PageSaved;
|
|
|
|
// This is a new page, so only who has page management permissions can execute this code
|
|
// No notification must be sent for drafts awaiting approval
|
|
if(redirect) {
|
|
Collisions.CancelEditingSession(pg, username);
|
|
string target = UrlTools.BuildUrl(Tools.UrlEncode(txtName.Text), Settings.PageExtension, "?NoRedirect=1");
|
|
UrlTools.Redirect(target);
|
|
}
|
|
else {
|
|
// Disable PageName, because the name cannot be changed anymore
|
|
txtName.Enabled = false;
|
|
pnlManualName.Visible = false;
|
|
}
|
|
}
|
|
else {
|
|
// Used for redirecting to a specific section after editing it
|
|
string anchor = "";
|
|
|
|
if(currentPage == null) currentPage = Pages.FindPage(NameTools.GetFullName(DetectNamespace(), txtName.Text));
|
|
|
|
// Save data
|
|
Log.LogEntry("Page update requested for " + currentPage.FullName, EntryType.General, username);
|
|
if(!isDraft && currentSection != -1) {
|
|
PageContent cont = Content.GetPageContent(currentPage, false);
|
|
StringBuilder sb = new StringBuilder(cont.Content.Length);
|
|
int start, len;
|
|
ExtractSection(cont.Content, currentSection, out start, out len, out anchor);
|
|
if(start > 0) sb.Append(cont.Content.Substring(0, start));
|
|
sb.Append(editor.GetContent());
|
|
if(start + len < cont.Content.Length - 1) sb.Append(cont.Content.Substring(start + len));
|
|
Pages.ModifyPage(currentPage, txtTitle.Text, username, DateTime.Now, txtComment.Text, sb.ToString(),
|
|
GetKeywords(), txtDescription.Text, saveMode);
|
|
}
|
|
else {
|
|
Pages.ModifyPage(currentPage, txtTitle.Text, username, DateTime.Now, txtComment.Text, editor.GetContent(),
|
|
GetKeywords(), txtDescription.Text, saveMode);
|
|
}
|
|
|
|
// Save Categories binding
|
|
Pages.Rebind(currentPage, categories.ToArray());
|
|
|
|
// If not a draft, remove page draft
|
|
if(saveMode != SaveMode.Draft) {
|
|
Pages.DeleteDraft(currentPage);
|
|
isDraft = false;
|
|
}
|
|
else isDraft = true;
|
|
|
|
ManageDraft();
|
|
|
|
lblResult.CssClass = "resultok";
|
|
lblResult.Text = Properties.Messages.PageSaved;
|
|
|
|
// This code is executed every time the page is saved, even when "Save & Continue" is clicked
|
|
// This causes a draft approval notification to be sent multiple times for the same page,
|
|
// but this is the only solution because the user might navigate away from the page after
|
|
// clicking "Save & Continue" but not "Save" or "Cancel" - in other words, it is necessary
|
|
// to take every chance to send a notification because no more chances might be available
|
|
if(!canEdit && canEditWithApproval) {
|
|
Pages.SendEmailNotificationForDraft(currentPage, txtTitle.Text, txtComment.Text, username);
|
|
}
|
|
|
|
if(redirect) {
|
|
Collisions.CancelEditingSession(currentPage, username);
|
|
string target = UrlTools.BuildUrl(Tools.UrlEncode(currentPage.FullName), Settings.PageExtension, "?NoRedirect=1",
|
|
(!string.IsNullOrEmpty(anchor) ? ("#" + anchor) : ""));
|
|
UrlTools.Redirect(target);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the keywords entered in the appropriate textbox.
|
|
/// </summary>
|
|
/// <returns>The keywords.</returns>
|
|
private string[] GetKeywords() {
|
|
string[] keywords = txtKeywords.Text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
|
for(int i = 0; i < keywords.Length; i++) {
|
|
keywords[i] = keywords[i].Trim();
|
|
}
|
|
return keywords;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets a set of keywords in the appropriate textbox.
|
|
/// </summary>
|
|
/// <param name="keywords">The keywords.</param>
|
|
private void SetKeywords(string[] keywords) {
|
|
if(keywords == null || keywords.Length == 0) txtKeywords.Text = "";
|
|
|
|
StringBuilder sb = new StringBuilder(50);
|
|
for(int i = 0; i < keywords.Length; i++) {
|
|
sb.Append(keywords[i]);
|
|
if(i != keywords.Length - 1) sb.Append(",");
|
|
}
|
|
txtKeywords.Text = sb.ToString();
|
|
}
|
|
|
|
protected void cvCategory1_ServerValidate(object sender, ServerValidateEventArgs e) {
|
|
e.IsValid = Pages.IsValidName(txtCategory.Text);
|
|
}
|
|
|
|
protected void cvCategory2_ServerValidate(object sender, ServerValidateEventArgs e) {
|
|
e.IsValid = Pages.FindCategory(NameTools.GetFullName(DetectNamespace(), txtCategory.Text)) == null;
|
|
}
|
|
|
|
protected void btnCreateCategory_Click(object sender, EventArgs e) {
|
|
if(canManagePageCategories) {
|
|
lblCategoryResult.Text = "";
|
|
lblCategoryResult.CssClass = "";
|
|
|
|
string fullName = NameTools.GetFullName(DetectNamespace(), txtCategory.Text);
|
|
Pages.CreateCategory(DetectNamespaceInfo(), txtCategory.Text, FindAppropriateProvider());
|
|
|
|
// Save selected categories
|
|
List<CategoryInfo> selected = new List<CategoryInfo>();
|
|
for(int i = 0; i < lstCategories.Items.Count; i++) {
|
|
if(lstCategories.Items[i].Selected) {
|
|
selected.Add(Pages.FindCategory(lstCategories.Items[i].Value));
|
|
}
|
|
}
|
|
|
|
PopulateCategories(selected.ToArray());
|
|
|
|
// Re-select previously selected categories
|
|
for(int i = 0; i < lstCategories.Items.Count; i++) {
|
|
if(selected.Find(delegate(CategoryInfo c) { return c.FullName == lstCategories.Items[i].Value; }) != null) {
|
|
lstCategories.Items[i].Selected = true;
|
|
}
|
|
if(lstCategories.Items[i].Value == fullName) lstCategories.Items[i].Selected = true;
|
|
}
|
|
txtCategory.Text = "";
|
|
}
|
|
}
|
|
|
|
protected void btnTemplates_Click(object sender, EventArgs e) {
|
|
pnlTemplates.Visible = true;
|
|
btnTemplates.Visible = false;
|
|
pnlAutoTemplate.Visible = false;
|
|
|
|
// Load templates
|
|
lstTemplates.Items.Clear();
|
|
lstTemplates.Items.Add(new ListItem(Properties.Messages.SelectTemplate, ""));
|
|
foreach(ContentTemplate temp in Templates.GetTemplates()) {
|
|
lstTemplates.Items.Add(new ListItem(temp.Name, temp.Name));
|
|
}
|
|
// Hide select button and preview text because the user hasn't selected a template yet
|
|
btnUseTemplate.Visible = false;
|
|
lblTemplatePreview.Text = "";
|
|
}
|
|
|
|
protected void lstTemplates_SelectedIndexChanged(object sender, EventArgs e) {
|
|
ContentTemplate template = Templates.Find(lstTemplates.SelectedValue);
|
|
|
|
if(template != null) {
|
|
lblTemplatePreview.Text = template.Content;
|
|
btnUseTemplate.Visible = true;
|
|
}
|
|
else {
|
|
lblTemplatePreview.Text = "";
|
|
btnUseTemplate.Visible = false;
|
|
}
|
|
}
|
|
|
|
protected void btnUseTemplate_Click(object sender, EventArgs e) {
|
|
ContentTemplate template = Templates.Find(lstTemplates.SelectedValue);
|
|
|
|
editor.SetContent(template.Content, Settings.UseVisualEditorAsDefault);
|
|
btnCancelTemplate_Click(sender, e);
|
|
// If there's a category matching the selected template name, select it automatically
|
|
for (int i = 0; i < lstCategories.Items.Count; i++) {
|
|
if (lstCategories.Items[i].Value.ToLower().Trim() == lstTemplates.SelectedValue.ToLower().Trim()) {
|
|
lstCategories.Items[i].Selected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void btnCancelTemplate_Click(object sender, EventArgs e) {
|
|
pnlTemplates.Visible = false;
|
|
btnTemplates.Visible = true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|