using System; using System.Collections.Generic; using System.Data; using System.Collections; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; using CMS.CMSHelper; using CMS.ExtendedControls; using CMS.GlobalHelper; using CMS.IO; using CMS.SettingsProvider; using CMS.SiteProvider; using CMS.UIControls; using Group = CMS.UIControls.UniMenuConfig.Group; public partial class CMSAdminControls_UI_UniMenu_UniMenu : CMSUserControl { #region "Variables" private bool? mIsRTL = null; private int identifier = 0; private bool mShowErrors = true; private bool mMenuEmpty = true; private UIElementInfo mFirstUIElement = null; private UIElementInfo mHighlightedUIElement = null; private Panel firstPanel = null; private Panel preselectedPanel = null; private List mGroups = null; private bool mHorizontalLayout = true; #endregion #region "Properties" /// /// Gets the current panel control /// protected Panel CurrentPanelControl { get { if (DisableScrollPanel) { return pnlControls; } return pnlScrollControls; } } /// /// Gets or sets the value that indicates whether scroll panel should be used /// public bool DisableScrollPanel { get; set; } /// /// Width of the menu. Applies only for vertical layout. /// public int Width { get; set; } /// /// Indicates whether to repeat items horizontally. Value is true by default. Otherwise items will be rendered vertically. /// public bool HorizontalLayout { get { return mHorizontalLayout; } set { mHorizontalLayout = value; } } /// /// Returns the UIElementInfo representing the first button of first group displayed. /// public UIElementInfo FirstUIElement { get { return mFirstUIElement; } } /// /// Returns the UIElementInfo representing the explicitly highlighted UI element. /// public UIElementInfo HighlightedUIElement { get { return mHighlightedUIElement; } } /// /// Returns the UIElementInfo representing the selected (either explicitly highlighted or first) UI element. /// public UIElementInfo SelectedUIElement { get { return HighlightedUIElement ?? FirstUIElement; } } /// /// Indicates whether at least one group with at least one button is rendered in the menu. /// public bool MenuEmpty { get { return mMenuEmpty; } } /// /// Gets or sets the value that indicates whether first item should be highligted. /// public bool HighlightFirstItem { get; set; } /// /// Gets or sets the value that indicates which item should be selected (has higher priority than HighlightFirstItem). /// public string HighlightItem { get; set; } /// /// Indicates whether to remember item which was last selected and select it again. /// public bool RememberSelectedItem { get; set; } /// /// Target frameset in which the links generated from UI Elements are opened. /// public string TargetFrameset { get; set; } /// /// List of groups to display. /// public List Groups { get { if (mGroups == null) { mGroups = new List(); } return mGroups; } set { mGroups = value; } } /// /// Description. /// public List InnerControls { get; set; } /// /// Indicates whether to display errors in the control. /// public bool ShowErrors { get { return mShowErrors; } set { mShowErrors = value; } } /// /// Code name of the module. /// public string ModuleName { get; set; } /// /// Indicates if current UI culture is RTL. /// public bool IsRTL { get { if (mIsRTL == null) { mIsRTL = CultureHelper.IsUICultureRTL(); } return (mIsRTL == true ? true : false); } set { mIsRTL = value; } } /// /// Indicates if empty group captions are allowed /// public bool AllowEmptyCaptions { get; set; } #endregion #region "Custom events" /// /// Button filtered delegate. /// public delegate bool ButtonFilterEventHandler(object sender, UniMenuArgs e); /// /// Button created delegate. /// public delegate void ButtonCreatedEventHandler(object sender, UniMenuArgs e); /// /// Button filtered event handler. /// public event ButtonFilterEventHandler OnButtonFiltered; /// /// Button creating event handler. /// public event ButtonCreatedEventHandler OnButtonCreating; /// /// Button created event handler. /// public event ButtonCreatedEventHandler OnButtonCreated; #endregion #region "Methods" protected void Page_Load(object sender, EventArgs e) { if (Groups.Count > 0) { pnlScrollControls.IsRTL = IsRTL; pnlScrollControls.InnerItemClass = "MiddleBigButton"; if (RememberSelectedItem) { RegisterRememberSelectedItemScript(); RegisterSelectItemScript("SelectButton(this);"); } RegisterSelectItemScript(""); InnerControls = new List(Groups.Count); // Process the groups for (identifier = 0; identifier < Groups.Count; identifier++) { Group group = Groups[identifier]; if (!string.IsNullOrEmpty(group.ControlPath) && (group.Control == null)) { group.Control = TryToCreateGroupControlBy(group.ControlPath, identifier); } if (group.Control != null) { int index = identifier; if (InnerControls.Count < index) { index = InnerControls.Count; } InnerControls.Insert(index, group.Control); } CMSPanel groupPanel = CreateGroupPanelWith(group, identifier); if (groupPanel != null) { mMenuEmpty = false; CurrentPanelControl.Controls.Add(groupPanel); // Insert separator after group if (Groups.Count > 1) { CurrentPanelControl.Controls.Add(GetGroupSeparator(group)); } } } // Handle the pre-selection if (preselectedPanel != null) { // Add the selected class to the preselected button preselectedPanel.CssClass += " Selected"; } else if ((firstPanel != null) && HighlightFirstItem) { // Add the selected class to the first button firstPanel.CssClass += " Selected"; } if (!HorizontalLayout) { CurrentPanelControl.CssClass = "Vertical"; if (Width > 0) { CurrentPanelControl.Attributes.Add("style", "width:" + Width + "px"); } } } if (DisableScrollPanel) { pnlScrollControls.Visible = false; pnlLeftScroller.Visible = false; pnlRightScroller.Visible = false; } else { pnlControls.Visible = false; } } /// /// Register scripts /// protected override void OnPreRender(EventArgs e) { ScriptHelper.RegisterJQuery(Page); ScriptHelper.RegisterScriptFile(Page, "~/CMSAdminControls/UI/UniMenu/UniMenu.js"); base.OnPreRender(e); } /// /// Creates group control. /// /// Path to control to be created /// Identifier of control private CMSUserControl CreateGroupControl(string path, int identifier) { CMSUserControl contentControl; contentControl = (CMSUserControl)Page.LoadUserControl(path); contentControl.ID = "ctrlContent" + identifier; contentControl.ShortID = "c" + identifier; return contentControl; } /// /// Encapsulates operation of creating group control in try catch construction and returns result. /// /// Path of control to be created /// Identifier of control private CMSUserControl TryToCreateGroupControlBy(string path, int identifier) { try { return CreateGroupControl(path, identifier); } catch { Controls.Add(GetError(GetString("unimenu.errorloadingcontrol"))); return null; } } /// /// Method for registering JS function for selecting button. /// private void RegisterRememberSelectedItemScript() { StringBuilder selectionScript = new StringBuilder(); selectionScript.AppendLine("function SelectButton(elem)"); selectionScript.AppendLine("{"); selectionScript.AppendLine(" var selected = 'Selected';"); selectionScript.AppendLine(" var jElem =$j(elem);"); selectionScript.AppendFormat(" $j('#{0}').find('.'+selected).removeClass(selected);\n", CurrentPanelControl.ClientID); selectionScript.AppendLine(" jElem.addClass(selected);"); selectionScript.AppendLine("}"); ScriptHelper.RegisterClientScriptBlock(this, typeof(string), "UIToolbarSelectionScript", ScriptHelper.GetScript(selectionScript.ToString())); } /// /// Method for registering JS function for selecting item. /// /// Function call for selecting button private void RegisterSelectItemScript(string buttonSelection) { StringBuilder remoteSelectionScript = new StringBuilder(); remoteSelectionScript.AppendLine("var SelectedItemID = null;"); remoteSelectionScript.AppendLine("function SelectItem(elementID, elementUrl, forceSelection)"); remoteSelectionScript.AppendLine("{"); remoteSelectionScript.AppendLine(" if(forceSelection === undefined) forceSelection = true;"); remoteSelectionScript.AppendLine(" if(SelectedItemID == elementID && !forceSelection) { return; }"); remoteSelectionScript.AppendLine(" SelectedItemID = elementID;"); remoteSelectionScript.AppendLine(" var selected = 'Selected';"); remoteSelectionScript.AppendFormat(" $j(\"#{0} .\"+selected).removeClass(selected);\n", CurrentPanelControl.ClientID); remoteSelectionScript.AppendFormat(" $j(\"#{0} div[name='\"+elementID+\"']\").addClass(selected);\n", CurrentPanelControl.ClientID); remoteSelectionScript.AppendLine(" if(elementUrl != null && elementUrl != '') {"); if (!String.IsNullOrEmpty(TargetFrameset)) { remoteSelectionScript.AppendLine(String.Format("{0}parent.frames['{1}'].location.href = elementUrl;", buttonSelection, TargetFrameset)); } else { remoteSelectionScript.AppendLine(buttonSelection + "self.location.href = elementUrl;"); } remoteSelectionScript.AppendLine(" }"); remoteSelectionScript.AppendLine("}"); ScriptHelper.RegisterClientScriptBlock(this, typeof(string), "UIToolbarRemoteSelectionScript", ScriptHelper.GetScript(remoteSelectionScript.ToString())); } /// /// Creates group panel from group. /// /// Definition of group /// Identifier of panel private CMSPanel CreateGroupPanelWith(Group group, int identifier) { Panel innerPanel = GetContent(group.Control, group.UIElementID, group.Caption); CMSPanel groupPanel = null; if (innerPanel != null) { groupPanel = new CMSPanel() { ID = "pnlGroup" + identifier, ShortID = "g" + identifier }; groupPanel.Controls.Add(GetLeftBorder()); groupPanel.Controls.Add(innerPanel); groupPanel.Controls.Add(GetRightBorder()); groupPanel.CssClass = group.CssClass; } return groupPanel; } /// /// Generates div with left border. /// /// Panel with left border protected Panel GetLeftBorder() { // Create panel and set up return new CMSPanel() { ID = "lb" + identifier, EnableViewState = false, CssClass = "UniMenuLeftBorder" }; } /// /// Generates div with right border. /// /// Panel with right border protected Panel GetRightBorder() { // Create panel and set up return new CMSPanel() { ID = "pnlRightBorder" + identifier, ShortID = "rb" + identifier, EnableViewState = false, CssClass = "UniMenuRightBorder" }; } /// /// Generates separator between groups. /// /// Group object /// Panel separating groups protected Panel GetGroupSeparator(Group group) { string css = String.IsNullOrEmpty(group.SeparatorCssClass) ? "UniMenuSeparator" : "UniMenuSeparator " + group.SeparatorCssClass; // Create panel and set up return new CMSPanel() { ID = "pnlGroupSeparator" + identifier, ShortID = "gs" + identifier, EnableViewState = false, CssClass = css }; } /// /// Generates div with right border. /// /// Caption of group /// Panel with right border protected Panel GetCaption(string captionText) { // Create literal with caption Literal caption = new Literal() { ID = "ltlCaption" + identifier, EnableViewState = false, Text = captionText }; // Create panel and add caption literal CMSPanel captionPanel = new CMSPanel() { ID = "pnlCaption" + identifier, ShortID = "cp" + identifier, EnableViewState = false, CssClass = "UniMenuDescription" }; captionPanel.Controls.Add(caption); return captionPanel; } /// /// Generates panel with buttons loaded from given UI Element. /// /// ID of the UI Element protected Panel GetButtons(int uiElementId) { const int bigButtonMinimalWidth = 40; const int smallButtonMinimalWidth = 66; Panel pnlButtons = null; // Load the buttons manually from UI Element DataSet ds = UIElementInfoProvider.GetChildUIElements(uiElementId); // When no child found if (DataHelper.DataSourceIsEmpty(ds)) { // Try to use group element as button ds = UIElementInfoProvider.GetUIElements("ElementID = " + uiElementId, null); if (!DataHelper.DataSourceIsEmpty(ds)) { DataRow dr = ds.Tables[0].Rows[0]; string url = ValidationHelper.GetString(dr["ElementTargetURL"], ""); // Use group element as button only if it has URL specified if (string.IsNullOrEmpty(url)) { ds = null; } } } if (!DataHelper.DataSourceIsEmpty(ds)) { // Filter the dataset according to UI Profile FilterElements(ds); int small = 0; int count = ds.Tables[0].Rows.Count; // No buttons, render nothing if (count == 0) { return null; } // Prepare the panel pnlButtons = new Panel(); pnlButtons.CssClass = "ActionButtons"; // Prepare the table Table tabGroup = new Table(); TableRow tabGroupRow = new TableRow(); tabGroup.CellPadding = 0; tabGroup.CellSpacing = 0; tabGroup.EnableViewState = false; tabGroupRow.EnableViewState = false; tabGroup.Rows.Add(tabGroupRow); List panels = new List(); for (int i = 0; i < count; i++) { // Get current and next button UIElementInfo uiElement = new UIElementInfo(ds.Tables[0].Rows[i]); // Raise button creating event if (OnButtonCreating != null) { OnButtonCreating(this, new UniMenuArgs { UIElement = uiElement }); } UIElementInfo uiElementNext = null; if (i < count - 1) { uiElementNext = new UIElementInfo(ds.Tables[0].Rows[i + 1]); } // Set the first button if (mFirstUIElement == null) { mFirstUIElement = uiElement; } // Get the sizes of current and next button. Button is large when it is the only in the group bool isSmall = (uiElement.ElementSize == UIElementSizeEnum.Regular) && (count > 1); bool isResized = (uiElement.ElementSize == UIElementSizeEnum.Regular) && (!isSmall); bool isNextSmall = (uiElementNext != null) && (uiElementNext.ElementSize == UIElementSizeEnum.Regular); // Set the CSS class according to the button size string cssClass = (isSmall ? "SmallButton" : "BigButton"); string elementName = uiElement.ElementName; string elementCaption = ResHelper.LocalizeString(uiElement.ElementCaption); // Create main button panel CMSPanel pnlButton = new CMSPanel() { ID = "pnlButton" + elementName, ShortID = "b" + elementName }; pnlButton.Attributes.Add("name", elementName); pnlButton.CssClass = cssClass; // Remember the first button if (firstPanel == null) { firstPanel = pnlButton; } // Remember the selected button if ((preselectedPanel == null) && elementName.EqualsCSafe(HighlightItem, true)) { preselectedPanel = pnlButton; // Set the selected button if (mHighlightedUIElement == null) { mHighlightedUIElement = uiElement; } } // URL or behavior string url = uiElement.ElementTargetURL; if (!string.IsNullOrEmpty(url) && url.StartsWithCSafe("javascript:", true)) { pnlButton.Attributes["onclick"] = url.Substring("javascript:".Length); } else if (!string.IsNullOrEmpty(url) && !url.StartsWithCSafe("javascript:", true)) { string buttonSelection = (RememberSelectedItem ? "SelectButton(this);" : ""); // Ensure hash code if required url = CMSContext.ResolveMacros(URLHelper.EnsureHashToQueryParameters(url)); if (!String.IsNullOrEmpty(TargetFrameset)) { pnlButton.Attributes["onclick"] = String.Format("{0}parent.frames['{1}'].location.href = '{2}';", buttonSelection, TargetFrameset, URLHelper.ResolveUrl(url)); } else { pnlButton.Attributes["onclick"] = String.Format("{0}self.location.href = '{1}';", buttonSelection, URLHelper.ResolveUrl(url)); } } // Tooltip if (!string.IsNullOrEmpty(uiElement.ElementDescription)) { pnlButton.ToolTip = ResHelper.LocalizeString(uiElement.ElementDescription); } else { pnlButton.ToolTip = elementCaption; } pnlButton.EnableViewState = false; // Ensure correct grouping of small buttons if (isSmall && (small == 0)) { small++; Panel pnlSmallGroup = new Panel() { ID = "pnlGroupSmall" + uiElement.ElementName }; if (IsRTL) { pnlSmallGroup.Style.Add("float", "right"); pnlSmallGroup.Style.Add("text-align", "right"); } else { pnlSmallGroup.Style.Add("float", "left"); pnlSmallGroup.Style.Add("text-align", "left"); } pnlSmallGroup.EnableViewState = false; pnlSmallGroup.Controls.Add(pnlButton); panels.Add(pnlSmallGroup); } // Generate button image Image buttonImage = new Image() { ID = "imgButton" + uiElement.ElementName, ImageAlign = (isSmall ? ImageAlign.AbsMiddle : ImageAlign.Top), AlternateText = elementCaption }; if (!string.IsNullOrEmpty(uiElement.ElementIconPath)) { string iconPath = GetImagePath(uiElement.ElementIconPath); // Check if element size was changed if (isResized) { // Try to get larger icon string largeIconPath = iconPath.Replace("list.png", "module.png"); if (FileHelper.FileExists(largeIconPath)) { iconPath = largeIconPath; } } buttonImage.ImageUrl = GetImageUrl(iconPath); } else { // Load default module icon if ElementIconPath is not specified buttonImage.ImageUrl = GetImageUrl("CMSModules/module.png"); } buttonImage.EnableViewState = false; // Generate button text Literal captionLiteral = new Literal() { ID = "ltlCaption" + uiElement.ElementName, Text = (isSmall ? "\n" : "
") + elementCaption, EnableViewState = false }; // Generate button link HyperLink buttonLink = new HyperLink() { ID = "lnkButton" + uiElement.ElementName }; buttonLink.Controls.Add(buttonImage); buttonLink.Controls.Add(captionLiteral); buttonLink.EnableViewState = false; //Generate button table (IE7 issue) Table tabButton = new Table(); TableRow tabRow = new TableRow(); TableCell tabCellLeft = new TableCell(); TableCell tabCellMiddle = new TableCell(); TableCell tabCellRight = new TableCell(); tabButton.CellPadding = 0; tabButton.CellSpacing = 0; tabButton.EnableViewState = false; tabRow.EnableViewState = false; tabCellLeft.EnableViewState = false; tabCellMiddle.EnableViewState = false; tabCellRight.EnableViewState = false; tabButton.Rows.Add(tabRow); tabRow.Cells.Add(tabCellLeft); tabRow.Cells.Add(tabCellMiddle); tabRow.Cells.Add(tabCellRight); // Generate left border Panel pnlLeft = new Panel() { ID = "pnlLeft" + uiElement.ElementName, CssClass = "Left" + cssClass, EnableViewState = false }; // Generate middle part of button Panel pnlMiddle = new Panel() { ID = "pnlMiddle" + uiElement.ElementName, CssClass = "Middle" + cssClass }; pnlMiddle.Controls.Add(buttonLink); Panel pnlMiddleTmp = new Panel() { EnableViewState = false }; if (isSmall) { pnlMiddle.Style.Add("min-width", smallButtonMinimalWidth + "px"); // IE7 issue with min-width pnlMiddleTmp.Style.Add("width", smallButtonMinimalWidth + "px"); pnlMiddle.Controls.Add(pnlMiddleTmp); } else { pnlMiddle.Style.Add("min-width", bigButtonMinimalWidth + "px"); // IE7 issue with min-width pnlMiddleTmp.Style.Add("width", bigButtonMinimalWidth + "px"); pnlMiddle.Controls.Add(pnlMiddleTmp); } pnlMiddle.EnableViewState = false; // Generate right border Panel pnlRight = new Panel() { ID = "pnlRight" + uiElement.ElementName, CssClass = "Right" + cssClass, EnableViewState = false }; // Add inner controls tabCellLeft.Controls.Add(pnlLeft); tabCellMiddle.Controls.Add(pnlMiddle); tabCellRight.Controls.Add(pnlRight); pnlButton.Controls.Add(tabButton); // If there were two small buttons in a row end the grouping div if ((small == 2) || (isSmall && !isNextSmall)) { small = 0; // Add the button to the small buttons grouping panel panels[panels.Count - 1].Controls.Add(pnlButton); } else { if (small == 0) { // Add the generated button into collection panels.Add(pnlButton); } } if (small == 1) { small++; } // Raise button created event if (OnButtonCreated != null) { OnButtonCreated(this, new UniMenuArgs { UIElement = uiElement, TargetUrl = url, ButtonControl = pnlButton, ImageControl = buttonImage }); } } // Add all panels to control foreach (Panel panel in panels) { TableCell tabGroupCell = new TableCell() { VerticalAlign = VerticalAlign.Top, EnableViewState = false }; tabGroupCell.Controls.Add(panel); tabGroupRow.Cells.Add(tabGroupCell); } pnlButtons.Controls.Add(tabGroup); } return pnlButtons; } /// /// Generates panel with content and caption. /// /// Control to add to the content /// Caption of group /// ID of the UI Element, if the content should be loaded from UI Elements protected Panel GetContent(Control control, int uiElementId, string captionText) { Panel content = null; if (string.IsNullOrEmpty(captionText) && !AllowEmptyCaptions) { if (ShowErrors) { Controls.Add(GetError(GetString("unimenu.captionempty"))); } } else if (control == null && uiElementId == 0) { if (ShowErrors) { Controls.Add(GetError(GetString("unimenu.pathempty"))); } } else { // Create panel and set up content = new Panel() { ID = "pnlContent" + identifier, CssClass = "UniMenuContent" }; // Add caption if (!HorizontalLayout && !string.IsNullOrEmpty(captionText)) { content.Controls.Add(GetCaption(captionText)); } // Add inner content control if (control != null) { content.Controls.Add(control); } else if (uiElementId > 0) { Panel innerPanel = GetButtons(uiElementId); if (innerPanel == null) { return null; } else { content.Controls.Add(innerPanel); } } // Add caption if (HorizontalLayout && !string.IsNullOrEmpty(captionText)) { content.Controls.Add(GetCaption(captionText)); } } return content; } /// /// Generates error label. /// /// Error message to display /// Label with error message protected Label GetError(string message) { // If error occurs skip this group return new Label() { ID = "lblError" + identifier, EnableViewState = false, Text = message, CssClass = "ErrorLabel" }; } /// /// Filters the dataset with UI Elements according to UI Profile of current user by default and according to custom event (if defined). /// protected void FilterElements(DataSet dsElements) { // For all tables in dataset foreach (DataTable dt in dsElements.Tables) { ArrayList deleteRows = new ArrayList(); // Find rows to filter out foreach (DataRow dr in dt.Rows) { UIElementInfo uiElement = new UIElementInfo(dr); bool allowed = CMSContext.CurrentUser.IsAuthorizedPerUIElement(ModuleName, uiElement.ElementName); if (OnButtonFiltered != null) { allowed = allowed && OnButtonFiltered(this, new UniMenuArgs { UIElement = uiElement }); } if (!allowed) { deleteRows.Add(dr); } } // Delete the filtered rows foreach (DataRow dr in deleteRows) { dt.Rows.Remove(dr); } } } #endregion }