using System; using System.Collections; using System.Text.RegularExpressions; using System.Web; using System.Web.UI; using umbraco.BasePages; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.web; using umbraco.editorControls.wysiwyg; using umbraco.interfaces; using umbraco.uicontrols; using umbraco.editorControls.tinymce; namespace umbraco.editorControls.tinyMCE3 { public class TinyMCE : webcontrol.TinyMCEWebControl , IDataEditor, IMenuElement, ILiveEditingDataEditor { private IData _data; private bool m_isInLiveEditingMode = false; private bool _enableContextMenu = false; private string _editorButtons = ""; private string _advancedUsers = ""; private bool _fullWidth = false; private int _width = 0; private int _height = 0; private bool _showLabel = false; private string _plugins = ""; private ArrayList _stylesheets = new ArrayList(); private ArrayList _menuIcons = new ArrayList(); private SortedList _buttons = new SortedList(); private SortedList _mceButtons = new SortedList(); private bool _isInitialized = false; private string _activateButtons = ""; private string _disableButtons = "help,visualaid,"; private int m_maxImageWidth = 500; public virtual string Plugins { get { return _plugins; } set { _plugins = value; } } public TinyMCE(IData Data, string Configuration) { _data = Data; try { string[] configSettings = Configuration.Split("|".ToCharArray()); if (configSettings.Length > 0) { _editorButtons = configSettings[0]; if (configSettings.Length > 1) if (configSettings[1] == "1") _enableContextMenu = true; if (configSettings.Length > 2) _advancedUsers = configSettings[2]; if (configSettings.Length > 3) { if (configSettings[3] == "1") _fullWidth = true; else if (configSettings[4].Split(',').Length > 1) { _width = int.Parse(configSettings[4].Split(',')[0]); _height = int.Parse(configSettings[4].Split(',')[1]); } } // default width/height if (_width < 1) _width = 500; if (_height < 1) _height = 400; // add stylesheets if (configSettings.Length > 4) { foreach (string s in configSettings[5].Split(",".ToCharArray())) _stylesheets.Add(s); } if (configSettings.Length > 6 && configSettings[6] != "") _showLabel = bool.Parse(configSettings[6]); if (configSettings.Length > 7 && configSettings[7] != "") m_maxImageWidth = int.Parse(configSettings[7].ToString()); // sizing if (!_fullWidth) { config.Add("width", _width.ToString()); config.Add("height", _height.ToString()); } if (_enableContextMenu) _plugins += ",contextmenu"; // safari compatibility if (HttpContext.Current.Request.Browser.Browser.ToLower().Contains("safari")) { _plugins += ",safari"; } // If the editor is used in umbraco, use umbraco's own toolbar bool onFront = false; if (GlobalSettings.RequestIsInUmbracoApplication(HttpContext.Current) || umbraco.presentation.UmbracoContext.Current.LiveEditingContext.Enabled) { config.Add("theme_umbraco_toolbar_location", "external"); config.Add("skin", "umbraco"); config.Add("inlinepopups_skin ", "umbraco"); } else { onFront = true; config.Add("theme_umbraco_toolbar_location", "top"); } // load plugins IDictionaryEnumerator pluginEnum = umbraco.editorControls.tinymce.tinyMCEConfiguration.Plugins.GetEnumerator(); while (pluginEnum.MoveNext()) { umbraco.editorControls.tinymce.tinyMCEPlugin plugin = (umbraco.editorControls.tinymce.tinyMCEPlugin)pluginEnum.Value; if (plugin.UseOnFrontend || (!onFront && !plugin.UseOnFrontend)) _plugins += "," + plugin.Name; } if (_plugins.StartsWith(",")) _plugins = _plugins.Substring(1, _plugins.Length - 1); if (_plugins.EndsWith(",")) _plugins = _plugins.Substring(0, _plugins.Length - 1); config.Add("plugins", _plugins); // Check advanced settings if (("," + _advancedUsers + ",").IndexOf("," + UmbracoEnsuredPage.CurrentUser.UserType.Id + ",") > -1) config.Add("umbraco_advancedMode", "true"); else config.Add("umbraco_advancedMode", "false"); // Check maximum image width config.Add("umbraco_maximumDefaultImageWidth", m_maxImageWidth.ToString()); // Styles string cssFiles = String.Empty; string styles = string.Empty; foreach (string styleSheetId in _stylesheets) { if (styleSheetId.Trim() != "") try { StyleSheet s = new StyleSheet(int.Parse(styleSheetId)); if (s.nodeObjectType == StyleSheet.ModuleObjectType) { cssFiles += GlobalSettings.Path + "/../css/" + s.Text + ".css"; foreach (StylesheetProperty p in s.Properties) { if (styles != string.Empty) { styles += ";"; } if (p.Alias.StartsWith(".")) styles += p.Text + "=" + p.Alias; else styles += p.Text + "=" + p.Alias; } cssFiles += ","; } } catch (Exception ee) { Log.Add(LogTypes.Error, -1, string.Format( string.Format("Error adding stylesheet to tinymce (id: {{0}}). {0}", ee), styleSheetId)); } } // remove any ending comma (,) if (!string.IsNullOrEmpty(cssFiles)) { cssFiles = cssFiles.TrimEnd(','); } // language config.Add("language", User.GetCurrent().Language); config.Add("content_css", cssFiles); config.Add("theme_umbraco_styles", styles); // Add buttons IDictionaryEnumerator ide = umbraco.editorControls.tinymce.tinyMCEConfiguration.Commands.GetEnumerator(); while (ide.MoveNext()) { umbraco.editorControls.tinymce.tinyMCECommand cmd = (umbraco.editorControls.tinymce.tinyMCECommand)ide.Value; if (_editorButtons.IndexOf("," + cmd.Alias + ",") > -1) _activateButtons += cmd.Alias + ","; else _disableButtons += cmd.Alias + ","; } if (_activateButtons.Length > 0) _activateButtons = _activateButtons.Substring(0, _activateButtons.Length - 1); if (_disableButtons.Length > 0) _disableButtons = _disableButtons.Substring(0, _disableButtons.Length - 1); // Add buttons initButtons(); _activateButtons = ""; int separatorPriority = 0; ide = _mceButtons.GetEnumerator(); while (ide.MoveNext()) { string mceCommand = ide.Value.ToString(); int curPriority = (int)ide.Key; // Check priority if (separatorPriority > 0 && Math.Floor(decimal.Parse(curPriority.ToString()) / 10) > Math.Floor(decimal.Parse(separatorPriority.ToString()) / 10)) _activateButtons += "separator,"; _activateButtons += mceCommand + ","; separatorPriority = curPriority; } config.Add("theme_umbraco_buttons1", _activateButtons); config.Add("theme_umbraco_buttons2", ""); config.Add("theme_umbraco_buttons3", ""); config.Add("theme_umbraco_toolbar_align", "left"); config.Add("theme_umbraco_disable", _disableButtons); config.Add("theme_umbraco_path ", "true"); config.Add("extended_valid_elements", "div[*]"); config.Add("document_base_url", "/"); config.Add("relative_urls", "false"); config.Add("remove_script_host", "true"); config.Add("event_elements", "div"); config.Add("paste_auto_cleanup_on_paste", "true"); config.Add("valid_elements", tinyMCEConfiguration.ValidElements.Substring(1, tinyMCEConfiguration.ValidElements.Length-2)); config.Add("invalid_elements", tinyMCEConfiguration.InvalidElements); // custom commands if (tinyMCEConfiguration.ConfigOptions.Count > 0) { ide = tinyMCEConfiguration.ConfigOptions.GetEnumerator(); while (ide.MoveNext()) { config.Add(ide.Key.ToString(), ide.Value.ToString()); } } //if (HttpContext.Current.Request.Path.IndexOf(GlobalSettings.Path) > -1) // config.Add("language", User.GetUser(BasePage.GetUserId(BasePage.umbracoUserContextID)).Language); //else // config.Add("language", System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName); if (_fullWidth) { config.Add("auto_resize", "true"); base.Columns = 30; base.Rows = 30; } else { base.Columns = 0; base.Rows = 0; } EnableViewState = false; } } catch (Exception ex) { throw new ArgumentException("Incorrect TinyMCE configuration.", "Configuration", ex); } } #region IDataEditor Members #region TreatAsRichTextEditor public virtual bool TreatAsRichTextEditor { get { return false; } } #endregion #region ShowLabel public virtual bool ShowLabel { get { return _showLabel; } } #endregion #region Editor public Control Editor { get { return this; } } #endregion #region Save() public virtual void Save() { string parsedString = base.Text.Trim(); if (parsedString != string.Empty) { parsedString = replaceMacroTags(parsedString).Trim(); // clean macros and add paragraph element for tidy bool removeParagraphs = false; if (parsedString.Length > 16 && parsedString.ToLower().Substring(0, 17) == "|||?umbraco_macro") { removeParagraphs = true; parsedString = "
" + parsedString + "
"; } // tidy html if (UmbracoSettings.TidyEditorContent) { string tidyTxt = library.Tidy(parsedString, false); if (tidyTxt != "[error]") { // compensate for breaking macro tags by tidy parsedString = tidyTxt.Replace("/?>", "/>"); if (removeParagraphs) { if (parsedString.Length - parsedString.Replace("<", "").Length == 2) parsedString = parsedString.Replace("", "").Replace("
", ""); } } else { // TODO // How to log errors? _data.NodeId does not exist? //BusinessLogic.Log.Add(BusinessLogic.LogTypes.Error, BusinessLogic.User.GetUser(0), _data.NodeId, "Error tidying txt from property: " + _data.PropertyId.ToString()); } } // rescue umbraco tags parsedString = parsedString.Replace("|||?", "").Replace("/|||", "/>").Replace("|*|", "\""); // fix images parsedString = umbraco.editorControls.tinymce.tinyMCEImageHelper.cleanImages(parsedString); // parse current domain and instances of slash before anchor (to fix anchor bug) // NH 31-08-2007 if (HttpContext.Current.Request.ServerVariables != null) { parsedString = parsedString.Replace(helper.GetBaseUrl(HttpContext.Current) + "/#", "#"); parsedString = parsedString.Replace(helper.GetBaseUrl(HttpContext.Current), ""); } // if text is an empty parargraph, make it all empty if (parsedString.ToLower() == "") parsedString = ""; } _data.Value = parsedString; // update internal webcontrol value with parsed result base.Text = parsedString; } #endregion protected override void OnLoad(EventArgs e) { try { // add current page info base.NodeId = ((cms.businesslogic.datatype.DefaultData)_data).NodeId; base.VersionId = ((cms.businesslogic.datatype.DefaultData)_data).Version; config.Add("theme_umbraco_pageId", base.NodeId.ToString()); config.Add("theme_umbraco_versionId", base.VersionId.ToString()); // we'll need to make an extra check for the liveediting as that value is set after the constructor have initialized if (IsInLiveEditingMode) { if (config["theme_umbraco_toolbar_location"] == null) config.Add("theme_umbraco_toolbar_location", ""); config["theme_umbraco_toolbar_location"] = "external"; config.Add("umbraco_toolbar_id", "LiveEditingClientToolbar"); } else { config.Add("umbraco_toolbar_id", ElementIdPreFix + ((cms.businesslogic.datatype.DefaultData)_data).PropertyId.ToString()); } } catch { // Empty catch as this is caused by the document doesn't exists yet, // like when using this on an autoform } base.OnLoad(e); } protected override void OnInit(EventArgs e) { base.OnInit(e); if (_data != null && _data.Value != null) base.Text = _data.Value.ToString(); } private string replaceMacroTags(string text) { while (findStartTag(text) > -1) { string result = text.Substring(findStartTag(text), findEndTag(text) - findStartTag(text)); text = text.Replace(result, generateMacroTag(result)); } return text; } private string generateMacroTag(string macroContent) { string macroAttr = macroContent.Substring(5, macroContent.IndexOf(">") - 5); string macroTag = "|||?UMBRACO_MACRO "; Hashtable attributes = ReturnAttributes(macroAttr); IDictionaryEnumerator ide = attributes.GetEnumerator(); while (ide.MoveNext()) { if (ide.Key.ToString().IndexOf("umb_") != -1) { // Hack to compensate for Firefox adding all attributes as lowercase string orgKey = ide.Key.ToString(); if (orgKey == "umb_macroalias") orgKey = "umb_macroAlias"; macroTag += orgKey.Substring(4, orgKey.ToString().Length - 4) + "=|*|" + ide.Value.ToString() + "|*| "; } } macroTag += "/|||"; return macroTag; } public static Hashtable ReturnAttributes(String tag) { Hashtable ht = new Hashtable(); MatchCollection m = Regex.Matches(tag, "(?