using System; using System.Collections.Generic; using System.Text; using System.Web; using umbraco.BasePages; using System.Web.UI; using umbraco.IO; using umbraco.BusinessLogic; namespace umbraco.BasePages { /// /// Renders the client side code necessary to interact with the Umbraco client side API. /// Each method returns an instance of this class so you can chain calls together. /// public sealed class ClientTools { public ClientTools(Page page) { m_page = page; } /// /// Returns the string markup for the JavaScript that is rendered. /// If referencing JavaScript scripts in the backend, this class should be used /// in case future changes to the client code is change, this will remain intact. /// public static class Scripts { internal const string ClientMgrScript = "UmbClientMgr"; public static string GetAppActions { get { return string.Format("{0}.appActions()", ClientMgrScript); } } public static string GetMainWindow { get { return string.Format("{0}.mainWindow()", ClientMgrScript); } } public static string GetMainTree { get { return string.Format("{0}.mainTree()", ClientMgrScript); } } public static string GetContentFrame() { return string.Format("{0}.contentFrame()", ClientMgrScript); } public static string ShiftApp(string appAlias) { return string.Format(ClientMgrScript + ".historyManager().addHistory('{0}')", appAlias); } public static string OpenDashboard(string app) { return string.Format(GetAppActions + ".openDashboard('{0}');", app); } public static string RefreshAdmin { get { return "setTimeout('" + GetMainWindow + ".location.reload()', {0});"; } } public static string ShowSpeechBubble { get { return GetMainWindow + ".UmbSpeechBubble.ShowMessage('{0}','{1}', '{2}');"; } } public static string ChangeContentFrameUrl(string url) { return string.Format(ClientMgrScript + ".contentFrame('{0}');", url); } public static string ChildNodeCreated = GetMainTree + ".childNodeCreated();"; public static string SyncTree { get { return GetMainTree + ".syncTree('{0}', {1});"; } } public static string ClearTreeCache { get { return GetMainTree + ".clearTreeCache();"; } } public static string CopyNode { get { return GetMainTree + ".copyNode('{0}', '{1}');"; } } public static string MoveNode { get { return GetMainTree + ".moveNode('{0}', '{1}');"; } } public static string ReloadActionNode { get { return GetMainTree + ".reloadActionNode({0}, {1}, null);"; } } public static string SetActiveTreeType { get { return GetMainTree + ".setActiveTreeType('{0}');"; } } public static string CloseModalWindow() { return string.Format("{0}.closeModalWindow();", ClientMgrScript); } public static string CloseModalWindow(string rVal) { return string.Format("{0}.closeModalWindow('{1}');", ClientMgrScript, rVal); } public static string OpenModalWindow(string url, string name, int width, int height) { return OpenModalWindow(url, name, true, width, height, 0, 0, "", ""); } public static string OpenModalWindow(string url, string name, bool showHeader, int width, int height, int top, int leftOffset, string closeTriggers, string onCloseCallback) { return string.Format("{0}.openModalWindow('{1}', '{2}', {3}, {4}, {5}, {6}, {7}, '{8}', '{9}');", new object[] { ClientMgrScript, url, name, showHeader.ToString().ToLower(), width, height, top, leftOffset, closeTriggers, onCloseCallback }); } } private Page m_page; /// /// This removes all tree JSON data cached in the client browser. /// Useful when you want to ensure that the tree is reloaded from live data. /// /// public ClientTools ClearClientTreeCache() { RegisterClientScript(Scripts.ClearTreeCache); return this; } /// /// Change applications /// /// public ClientTools ShiftApp(string appAlias) { RegisterClientScript(Scripts.ShiftApp(appAlias)); return this; } /// /// Refresh the entire administration console after a specified amount of time. /// /// /// public ClientTools RefreshAdmin(int seconds) { RegisterClientScript(string.Format(Scripts.RefreshAdmin, seconds * 1000)); return this; } /// /// A reference to the umbraco UI component "speechbubble". The speechbubble appears in the lower right corner of the screen, notifying users of events /// /// The speechbubble icon. /// The speechbubble header. /// The body text public ClientTools ShowSpeechBubble(BasePage.speechBubbleIcon i, string header, string body) { RegisterClientScript(string.Format(Scripts.ShowSpeechBubble, i.ToString(), header.Replace("'", "\\'"), body.Replace("'", "\\'"))); return this; } /// /// Changes the content in the content frame to the specified URL /// /// public ClientTools ChangeContentFrameUrl(string url) { //don't load if there is no url if (string.IsNullOrEmpty(url)) return this; if (url.StartsWith("/") && !url.StartsWith(IOHelper.ResolveUrl(SystemDirectories.Umbraco))) url = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/" + url; if (url.Trim().StartsWith("~")) url = IOHelper.ResolveUrl(url); RegisterClientScript(Scripts.ChangeContentFrameUrl(url)); return this; } /// /// Shows the dashboard for the given application /// /// /// public ClientTools ShowDashboard(string app) { return ChangeContentFrameUrl(SystemDirectories.Umbraco + string.Format("/dashboard.aspx?app={0}", app)); } /// /// Reloads the children of the current action node and selects the node that didn't exist there before. /// If the client side system cannot determine which node is new, then no node is selected. /// /// /// This is used by many create dialogs, however the sync method should be used based on the full path of the /// node but because the current Umbraco implementation of ITask only returns a url to load, there's no way /// to determine what the full path of the new child is. /// /// public ClientTools ChildNodeCreated() { RegisterClientScript(Scripts.ChildNodeCreated); return this; } /// /// Synchronizes the tree to the path specified. /// /// /// /// If set to true, will ensure that the node to be synced has it's data /// reloaded from the server. Otherwise, if the node already exists, the tree will simply sync to the node /// that is already there. /// /// /// This will work for any tree, however you would need to know the path of the node. Currently, media and content /// are the only trees that store a path, however, if you were working in the template tree for example, a path to a /// node could be "init,1090" and this method would still work. /// /// Sync tree will works by syncing the active tree type. This can be specified explicitly by calling SetActiveTreeType. /// This will allow developers to sync many trees in one application at one time if needed. /// /// /// /// public ClientTools SyncTree(string path, bool forceReload) { RegisterClientScript(string.Format(Scripts.SyncTree, path, forceReload.ToString().ToLower())); return this; } public ClientTools CopyNode(string currNodeId, string newParentPath) { RegisterClientScript(string.Format(Scripts.CopyNode, currNodeId, newParentPath)); return this; } public ClientTools MoveNode(string currNodeId, string newParentPath) { RegisterClientScript(string.Format(Scripts.MoveNode, currNodeId, newParentPath)); return this; } /// /// Reloads only the active node in the tree. /// /// /// /// /// If for whatever reason the client side system cannot just refresh the one node, the system will use jsTree's built in /// refresh tool, this however won't allow for reselect or reloadChildren. Most trees will work with the single node /// refresh but 3rd party tools may have poorly built tree data models. /// public ClientTools ReloadActionNode(bool reselect, bool reloadChildren) { RegisterClientScript(string.Format(Scripts.ReloadActionNode, (!reselect).ToString().ToLower(), (!reloadChildren).ToString().ToLower())); return this; } /// /// When the application searches for a node, it searches for nodes in specific tree types. /// If SyncTree is used, it will sync the tree nodes with the active tree type, therefore if /// a developer wants to sync a specific tree, they can call this method to set the type to sync. /// /// /// Each branch of a particular tree should theoretically be the same type, however, developers can /// override the type of each branch in their BaseTree's but this is not standard practice. If there /// are multiple types of branches in one tree, then only those branches that have the Active tree type /// will be searched for syncing. /// /// /// public ClientTools SetActiveTreeType(string treeType) { RegisterClientScript(string.Format(Scripts.SetActiveTreeType, treeType)); return this; } /// /// Closes the Umbraco dialog window if it is open /// /// specify a value to return to add to the onCloseCallback method if one was specified in the OpenModalWindow method /// public ClientTools CloseModalWindow(string returnVal) { RegisterClientScript(Scripts.CloseModalWindow(returnVal)); return this; } /// /// Closes the umbraco dialog window if it is open /// /// public ClientTools CloseModalWindow() { return CloseModalWindow(""); } /// /// Opens a modal window /// /// /// /// /// /// public ClientTools OpenModalWindow(string url, string name, bool showHeader, int width, int height, int top, int leftOffset, string closeTriggers, string onCloseCallback) { RegisterClientScript(Scripts.OpenModalWindow(url, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback)); return this; } private Page GetCurrentPage() { return HttpContext.Current.CurrentHandler as Page; } private void RegisterClientScript(string script) { //use the hash code of the script to generate the key, this way, the exact same script won't be //inserted more than once. //m_page.ClientScript.RegisterClientScriptBlock(m_page.GetType(), script.GetHashCode().ToString(), script, true); m_page.ClientScript.RegisterStartupScript(m_page.GetType(), script.GetHashCode().ToString(), script, true); } } }