using System; using System.Data; using System.Collections; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using CMS.CMSHelper; using CMS.Forums; using CMS.GlobalHelper; using CMS.IO; using CMS.SettingsProvider; using CMS.UIControls; using CMS.ExtendedControls; public partial class CMSModules_Forums_Controls_PostTree : ForumViewer { #region "Variables" /// /// Forum Post tree provider. /// private ForumPostTreeProvider mForumPostTreeProvider = null; private bool mAllowReply = true; private string mPostPath = "/%"; private bool mAdministrationMode = false; private int mSelected = 0; private bool mSelectOnlyApproved = false; private bool mRegularLoad = false; private int mMaxPostNodes = 0; private bool mUseMaxPostNodes = false; private ForumPostInfo mSelectedPost = null; private string mMaxTreeNodeText = null; private bool? mCanBeModerated = null; private bool? mUserIsModerator = null; /// /// If is true unapproved post is higlighted. /// protected bool mHighlightUnApproved = false; /// /// Item CSS class. /// protected string mItemCssClass = "ThreadPost"; /// /// Selcted item CSS class. /// protected string mSelectedItemCssClass = "ThreadPostSelected"; #endregion #region "Public events and delegates" /// /// Image delegate. /// public delegate string GetIconEventHandler(ForumPostTreeNode node); /// /// Gets image Url. /// public event GetIconEventHandler OnGetPostIconUrl; #endregion #region "Public properties" /// /// If is true unapproved post is higlighted. /// public bool HighlightUnApprove { get { return mHighlightUnApproved; } set { mHighlightUnApproved = value; } } /// /// Enable subscription. /// public bool AllowReply { get { return mAllowReply; } set { mAllowReply = value; } } /// /// Path. /// public string PostPath { get { return mPostPath; } set { mPostPath = value; } } /// /// Select only approved. /// public bool SelectOnlyApproved { get { return mSelectOnlyApproved; } set { mSelectOnlyApproved = value; } } /// /// Selected post id. /// public int Selected { get { return mSelected; } set { mSelected = value; } } /// /// Selected post info. /// public ForumPostInfo SelectedPost { get { if ((mSelectedPost == null) && (Selected > 0)) { mSelectedPost = ForumPostInfoProvider.GetForumPostInfo(Selected); } return mSelectedPost; } set { mSelectedPost = value; } } /// /// Maximum number of forum post nodes displayed within one level of the tree. /// Setting CMSForumMaxPostNode is used by default. /// Note: UseMaxPostNodes property can suppress use of MaxPostNodes /// public int MaxPostNodes { get { if (mMaxPostNodes <= 0) { mMaxPostNodes = SettingsKeyProvider.GetIntValue(SiteName + ".CMSForumMaxPostNode"); } return mMaxPostNodes; } set { mMaxPostNodes = value; MapProvider.MaxPostNodes = value + 1; } } /// /// Enables or disables use of MaxPostNodes property, which limits maximum number of posts /// displayed in tree. /// public bool UseMaxPostNodes { get { return mUseMaxPostNodes; } set { mUseMaxPostNodes = value; } } /// /// Enables or disables administration mode. /// public bool AdministrationMode { get { return mAdministrationMode; } set { mAdministrationMode = value; } } /// /// Post tree provider that the tree uses. /// public ForumPostTreeProvider MapProvider { get { if (mForumPostTreeProvider == null) { mForumPostTreeProvider = new ForumPostTreeProvider(); // Set Map provider values mForumPostTreeProvider.BindNodeData = true; mForumPostTreeProvider.Path = PostPath; if (ExpandTree || DetailModeIE) { // Load all posts mForumPostTreeProvider.MaxRelativeLevel = ForumPostTreeProvider.ALL_LEVELS; } else { // Load only first level mForumPostTreeProvider.MaxRelativeLevel = 1; } mForumPostTreeProvider.SelectOnlyApproved = SelectOnlyApproved; mForumPostTreeProvider.ForumID = ForumID; mForumPostTreeProvider.WhereCondition = WhereCondition; mForumPostTreeProvider.Columns = GetColumns(); // Limit number of displayed posts, usually in CMSDesk if (UseMaxPostNodes) { mForumPostTreeProvider.MaxPostNodes = MaxPostNodes + 1; } } return mForumPostTreeProvider; } } /// /// Provides acces to treeElem property. /// public TreeView TreeView { get { return treeElem; } } /// /// Item CSS class. /// public string ItemCssClass { get { return mItemCssClass; } set { mItemCssClass = value; } } /// /// Selected item CSS class. /// public string SelectedItemCssClass { get { return mSelectedItemCssClass; } set { mSelectedItemCssClass = value; } } /// /// Text to appear within the latest node when max tree nodes applied. /// public string MaxTreeNodeText { get { if (mMaxTreeNodeText == null) { mMaxTreeNodeText = GetString("general.seelisting"); } return mMaxTreeNodeText; } set { mMaxTreeNodeText = value; } } /// /// Indicates whether posts can be moderated in current context, /// therefore unapproved post could be displayed. /// public bool CanBeModerated { get { if (!mCanBeModerated.HasValue) { ForumInfo fi = ForumContext.CurrentForum; mCanBeModerated = ((fi != null) && EnableOnSiteManagement && fi.ForumModerated && UserIsModerator); } return mCanBeModerated.Value; } } /// /// Indicates whether the current user is a moderator. That means: forum moderator or group admin or global admin. /// private bool UserIsModerator { get { if (!mUserIsModerator.HasValue) { bool result = false; ForumInfo fi = ForumContext.CurrentForum; result = (fi != null) && ForumContext.UserIsModerator(fi.ForumID, CommunityGroupID); if (!result && (CommunityGroupID > 0)) { result = CMSContext.CurrentUser.IsAuthorizedPerResource("cms.groups", CMSAdminControl.PERMISSION_MANAGE); } mUserIsModerator = result; } return mUserIsModerator.Value; } } /// /// Indicates if special mode for treating (dynamic) detail mode in IE should be used. /// The cause is that, IE can't handle too long parameters of TreeView_PopulateNode javascript function /// private bool DetailModeIE { get { return (((ShowMode == ShowModeEnum.DetailMode) || (ShowMode == ShowModeEnum.DynamicDetailMode)) && BrowserHelper.IsIE()); } } #endregion #region "Helper methods and properties" /// /// Gets or sets the value that indicates whether data has been loaded or current load is /// called on demand /// protected bool RegularLoad { get { return mRegularLoad; } set { mRegularLoad = value; } } /// /// Returns list of required columns if current mode is tree, otherwise returns null => load all columns /// protected string GetColumns() { if (ShowMode == ShowModeEnum.TreeMode) { return "PostSubject, PostIDPath, PostParentID, PostApproved, PostID, PostThreadPosts, PostThreadPostsAbsolute, PostLevel"; } return null; } /// /// Returns node text for dynamic mode. /// /// Forum post data row private string CreateDetailModeNode(DataRow postRow) { StringBuilder sbRendered = null; // Render forum post control string forumPostControlId = DynamicForumPostRender(postRow, out sbRendered); string nodeText = String.Format("
{1}
", forumPostControlId, sbRendered.ToString()); return nodeText; } /// /// Returns node text for dynamic details mode. /// /// Forum post data row /// CSS class /// Image tag /// Post subject private string CreateDynamicDetailModeNode(DataRow postRow, string cssClass, string imageTag, string postSubject) { StringBuilder sbRendered = null; // Render forum post control string forumPostControlId = DynamicForumPostRender(postRow, out sbRendered); string nodeText = String.Format( "" + "{2}{3}" + //imagetag + postsubject "
{4}
", forumPostControlId, cssClass, imageTag, HTMLHelper.HTMLEncode(postSubject), sbRendered.ToString()); return nodeText; } /// /// Renders ForumPost control for specified node. /// /// Forum post data row /// String builder instance containing rendered text of control private string DynamicForumPostRender(DataRow postRow, out StringBuilder sbRendered) { // Create detail of post to string sbRendered = new StringBuilder(); string mId = ""; ForumPostInfo fpi = new ForumPostInfo(postRow); if (ShowMode != ShowModeEnum.TreeMode) { StringWriter sw = new StringWriter(sbRendered); Html32TextWriter writer = new Html32TextWriter(sw); CMSModules_Forums_Controls_Posts_ForumPost post = (CMSModules_Forums_Controls_Posts_ForumPost)Page.LoadUserControl("~/CMSModules/Forums/Controls/Posts/ForumPost.ascx"); post.ID = "forumPost" + fpi.PostId; CopyValues(post); post.PostInfo = fpi; post.ReloadData(); post.RenderControl(writer); mId = ClientID + fpi.PostId; } return mId; } #endregion #region "Methods" /// /// Page load. /// protected void Page_Load(object sender, EventArgs e) { ForumContext.ForumID = ForumID; treeElem.ImageSet = TreeViewImageSet.Custom; if ((IsLiveSite && CultureHelper.IsPreferredCultureRTL()) || (!IsLiveSite && CultureHelper.IsUICultureRTL())) { treeElem.LineImagesFolder = GetImageUrl("RTL/Design/Controls/Tree", IsLiveSite, false); } else { treeElem.LineImagesFolder = GetImageUrl("Design/Controls/Tree", IsLiveSite, false); } // Loading image script string loadingScript = @" if (TreeView_PopulateNode) { base_TreeView_PopulateNode = TreeView_PopulateNode }; TreeView_PopulateNode = function(data, index, node, selectNode, selectImageNode, lineType, text, path, databound, datapath, parentIsLast) { if (!data) { return; } if (!node.blur) { node = node[0]; } node.blur(); node.firstChild.src = '" + GetImageUrl("Design/Preloaders/preload16pad.gif") + "';" + @" if (base_TreeView_PopulateNode) { base_TreeView_PopulateNode(data, index, node, selectNode, selectImageNode, lineType, text, path, databound, datapath, parentIsLast); } }"; ltlScript.Text = ScriptHelper.GetScript(loadingScript); treeElem.ExpandImageToolTip = GetString("ContentTree.Expand"); treeElem.CollapseImageToolTip = GetString("ContentTree.Collapse"); } /// /// OnPreRender. /// protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (!RequestHelper.IsCallback()) { ReloadData(); } } /// /// Reload data. /// public override void ReloadData() { if (StopProcessing) { return; } mForumPostTreeProvider = null; RegularLoad = true; // Some post should be preselected => load all posts leading to it in one query if (SelectedPost != null) { MapProvider.SelectPostPath = SelectedPost.PostIDPath; } if (MapProvider.RootNode != null) { TreeNode rootNode = CreateNode((ForumPostTreeNode)MapProvider.RootNode, 0); // Localize root node if (rootNode != null) { rootNode.Text = ResHelper.LocalizeString(rootNode.Text); } // Add root node treeElem.Nodes.Add(rootNode); treeElem.EnableViewState = false; } } /// /// Creates tree node. /// /// Node with source data protected TreeNode CreateNode(ForumPostTreeNode sourceNode, int index) { if (sourceNode == null) { return null; } // Create tree node TreeNode newNode = new TreeNode(); DataRow dr = (DataRow)sourceNode.ItemData; // Check whether item data are defined, if not it is root node if (dr != null) { int sourceNodeId = (int)dr["PostID"]; int nodeLevel = (int)dr["PostLevel"]; // Check on maximum post in tree if (!UseMaxPostNodes || (index < MaxPostNodes)) { #region "Set node values and appearance" newNode.Value = sourceNodeId.ToString(); newNode.SelectAction = TreeNodeSelectAction.None; bool isApproved = ValidationHelper.GetBoolean(dr["PostApproved"], false); string postSubject = (string)dr["PostSubject"]; string cssClass = ItemCssClass; // Add CSS class for unapproved posts if (HighlightUnApprove && !isApproved) { cssClass += " PostUnApproved"; } string imageTag = ""; if (OnGetPostIconUrl != null) { string imageUrl = OnGetPostIconUrl(sourceNode); imageTag = "\"post\" "; } // Set by display mode switch (ShowMode) { // Dynamic detail mode case ShowModeEnum.DynamicDetailMode: newNode.Text = CreateDynamicDetailModeNode(dr, cssClass, imageTag, postSubject); break; // Detail mode case ShowModeEnum.DetailMode: newNode.Text = CreateDetailModeNode(dr); break; // Tree mode default: if (Selected == sourceNodeId) { cssClass = SelectedItemCssClass; string spanId = String.Empty; if (AdministrationMode) { spanId = "id=\"treeSelectedNode\""; } newNode.Text = String.Format("{3}{4}", spanId, cssClass, newNode.Value, imageTag, HTMLHelper.HTMLEncode(postSubject)); } else { newNode.Text = String.Format("{2}{3}", cssClass, newNode.Value, imageTag, HTMLHelper.HTMLEncode(postSubject)); } break; } #endregion if (!ExpandTree) { #region "Populate deeper levels on demand" // Check if can expand string childCountColumn = "PostThreadPosts"; // Check if unapproved posts can be included if (AdministrationMode || UserIsModerator) { childCountColumn = "PostThreadPostsAbsolute"; } int childNodesCount = ValidationHelper.GetInteger(dr[childCountColumn], 0); // If the post is thread(level = 0) then childnodes count 1 means no real child-post if ((childNodesCount == 0) || ((childNodesCount == 1) && (nodeLevel == 0))) { newNode.PopulateOnDemand = false; // No children -> expand newNode.Expanded = true; } else { if (!sourceNode.ChildNodesLoaded) { newNode.PopulateOnDemand = true; newNode.Expanded = false; } } #endregion #region "Expand nodes on the current path" // If preselect is set = first load if (RegularLoad) { string currentNodePath = (string)dr["PostIDPath"]; string currentSelectedPath = String.Empty; if (SelectedPost != null) { currentSelectedPath = SelectedPost.PostIDPath; } // Expand if node is on the path if (currentSelectedPath.StartsWithCSafe(currentNodePath)) { // Raise OnTreeNodePopulate newNode.PopulateOnDemand = true; newNode.Expanded = true; } else { newNode.Expanded = false; } } #endregion } else { // Populate will be called on each node newNode.PopulateOnDemand = true; newNode.Expanded = true; } } else { string parentNodeId = ValidationHelper.GetString(dr["PostParentID"], ""); newNode.Value = sourceNodeId.ToString(); newNode.Text = MaxTreeNodeText.Replace("##PARENTNODEID##", parentNodeId); newNode.SelectAction = TreeNodeSelectAction.None; } } // Root node populate by default else { // Root node as forum display name ForumInfo fi = ForumInfoProvider.GetForumInfo(ForumID); if (fi != null) { newNode.Text = "" + HTMLHelper.HTMLEncode(fi.ForumDisplayName) + ""; newNode.Value = "0"; newNode.SelectAction = TreeNodeSelectAction.None; } newNode.PopulateOnDemand = true; newNode.Expanded = true; } return newNode; } /// /// On populate create child nodes. /// protected void treeElem_TreeNodePopulate(object sender, TreeNodeEventArgs e) { e.Node.ChildNodes.Clear(); e.Node.PopulateOnDemand = false; int postId = ValidationHelper.GetInteger(e.Node.Value, 0); // Set the ForumID if not set already if (ForumContext.ForumID == 0) { ForumPostInfo postInfo = ForumPostInfoProvider.GetForumPostInfo(postId); if (postInfo != null) { ForumContext.ForumID = postInfo.PostForumID; ForumID = postInfo.PostForumID; } } // Get child nodes SiteMapNodeCollection childNodes = MapProvider.GetChildNodes(postId, RegularLoad); int index = 0; foreach (ForumPostTreeNode childNode in childNodes) { int childNodeId = (int)((DataRow)childNode.ItemData)["PostID"]; if (childNodeId != postId) { TreeNode newNode = CreateNode(childNode, index); bool? originalExpanded = newNode.Expanded; // Force node to expand and load child posts if (DetailModeIE) { newNode.PopulateOnDemand = true; newNode.Expanded = true; } e.Node.ChildNodes.Add(newNode); // Restore original expanded state if (DetailModeIE) { newNode.Expanded = originalExpanded; } index++; } // Ensure there is only one 'click here for more' item if (UseMaxPostNodes && (index > MaxPostNodes)) { break; } } } /// /// Render /// protected override void Render(HtmlTextWriter writer) { if (!StopProcessing) { base.Render(writer); } } #endregion }