From 471a2113999e47d72f76ff466ddbd6684698c004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ton=C4=87i=20Vatavuk?= Date: Tue, 1 Oct 2024 12:56:58 +0200 Subject: [PATCH] Add content workflow tab action buttons in edit mode https://github.com/dnnsoftware/Dnn.Platform/issues/6115 --- .../ContentWorkflowServiceController.cs | 88 +++++++++++++++++++ .../Content/Workflow/WorkflowSecurity.cs | 8 +- .../Dnn.EditBar.UI/Dnn.EditBar.UI.csproj | 12 +++ .../Dnn.EditBar.UI/Items/CompleteStateMenu.cs | 54 ++++++++++++ .../Items/CompleteWorkflowMenu.cs | 53 +++++++++++ .../Dnn.EditBar.UI/Items/DiscardStateMenu.cs | 54 ++++++++++++ .../Items/DiscardWorkflowMenu.cs | 54 ++++++++++++ .../editBar/css/CompleteState.css | 9 ++ .../editBar/css/CompleteWorkflow.css | 9 ++ .../editBar/css/DiscardState.css | 9 ++ .../editBar/css/DiscardWorkflow.css | 9 ++ .../editBar/scripts/CompleteState.js | 26 ++++++ .../editBar/scripts/CompleteWorkflow.js | 26 ++++++ .../editBar/scripts/DiscardState.js | 26 ++++++ .../editBar/scripts/DiscardWorkflow.js | 26 ++++++ 15 files changed, 460 insertions(+), 3 deletions(-) create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteStateMenu.cs create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteWorkflowMenu.cs create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardStateMenu.cs create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardWorkflowMenu.cs create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteState.css create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteWorkflow.css create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardState.css create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardWorkflow.css create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteState.js create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteWorkflow.js create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardState.js create mode 100644 Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardWorkflow.js diff --git a/DNN Platform/DotNetNuke.Web/InternalServices/ContentWorkflowServiceController.cs b/DNN Platform/DotNetNuke.Web/InternalServices/ContentWorkflowServiceController.cs index cee46f166df..80bdf2118a3 100644 --- a/DNN Platform/DotNetNuke.Web/InternalServices/ContentWorkflowServiceController.cs +++ b/DNN Platform/DotNetNuke.Web/InternalServices/ContentWorkflowServiceController.cs @@ -10,8 +10,10 @@ namespace DotNetNuke.Web.InternalServices using System.Net.Http; using System.Web.Http; + using DotNetNuke.Entities.Content.Common; using DotNetNuke.Entities.Content.Workflow; using DotNetNuke.Entities.Content.Workflow.Dto; + using DotNetNuke.Entities.Tabs; using DotNetNuke.Framework; using DotNetNuke.Internal.SourceGenerators; using DotNetNuke.Services.Exceptions; @@ -149,5 +151,91 @@ public partial HttpResponseMessage Review(NotificationDTO postData) return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "unable to process notification"); } + + [HttpPost] + [ValidateAntiForgeryToken] + public HttpResponseMessage CompleteState() + { + try + { + this.workflowEngine.CompleteState(this.BuildStateTransaction()); + return this.Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + catch (Exception exc) + { + Exceptions.LogException(exc); + } + + return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "unable to process notification"); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public HttpResponseMessage DiscardState() + { + try + { + this.workflowEngine.DiscardState(this.BuildStateTransaction()); + return this.Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + catch (Exception exc) + { + Exceptions.LogException(exc); + } + + return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "unable to process notification"); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public HttpResponseMessage CompleteWorkflow() + { + try + { + this.workflowEngine.CompleteWorkflow(this.BuildStateTransaction()); + return this.Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + catch (Exception exc) + { + Exceptions.LogException(exc); + } + + return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "unable to process notification"); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public HttpResponseMessage DiscardWorkflow() + { + try + { + this.workflowEngine.DiscardWorkflow(this.BuildStateTransaction()); + return this.Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + catch (Exception exc) + { + Exceptions.LogException(exc); + } + + return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "unable to process notification"); + } + + private StateTransaction BuildStateTransaction() + { + var portalId = this.PortalSettings.PortalId; + var tabId = this.Request.FindTabId(); + var currentPage = TabController.Instance.GetTab(tabId, portalId); + var contentItemId = currentPage.ContentItemId; + var contentController = Util.GetContentController(); + var contentItem = contentController.GetContentItem(contentItemId); + var stateTransaction = new StateTransaction + { + ContentItemId = contentItem.ContentItemId, + CurrentStateId = contentItem.StateID, + Message = new StateTransactionMessage(), + UserId = this.UserInfo.UserID, + }; + return stateTransaction; + } } } diff --git a/DNN Platform/Library/Entities/Content/Workflow/WorkflowSecurity.cs b/DNN Platform/Library/Entities/Content/Workflow/WorkflowSecurity.cs index 151aa727fd7..66cc1132bfd 100644 --- a/DNN Platform/Library/Entities/Content/Workflow/WorkflowSecurity.cs +++ b/DNN Platform/Library/Entities/Content/Workflow/WorkflowSecurity.cs @@ -17,7 +17,8 @@ namespace DotNetNuke.Entities.Content.Workflow public class WorkflowSecurity : ServiceLocator, IWorkflowSecurity { private const string ReviewPermissionKey = "REVIEW"; - private const string ReviewPermissionCode = "SYSTEM_CONTENTWORKFLOWSTATE"; + private const string ReviewPermissionCode = "SYSTEM_CONTENTWORKFLOWSTATE"; + private const string ContentManagers = "Content Managers"; private readonly IUserController userController = UserController.Instance; private readonly IWorkflowManager workflowManager = WorkflowManager.Instance; private readonly IWorkflowStatePermissionsRepository statePermissionsRepository = WorkflowStatePermissionsRepository.Instance; @@ -27,8 +28,9 @@ public bool HasStateReviewerPermission(PortalSettings settings, UserInfo user, i { var permissions = this.statePermissionsRepository.GetWorkflowStatePermissionByState(stateId); - return user.IsSuperUser || - PortalSecurity.IsInRoles(user, settings, settings.AdministratorRoleName) || + return user.IsSuperUser || + PortalSecurity.IsInRoles(user, settings, settings.AdministratorRoleName) || + PortalSecurity.IsInRoles(user, settings, ContentManagers) || PortalSecurity.IsInRoles(user, settings, PermissionController.BuildPermissions(permissions.ToList(), ReviewPermissionKey)); } diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Dnn.EditBar.UI.csproj b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Dnn.EditBar.UI.csproj index 7f4e197f089..1aba0e78aeb 100644 --- a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Dnn.EditBar.UI.csproj +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Dnn.EditBar.UI.csproj @@ -96,6 +96,10 @@ + + + + @@ -123,9 +127,17 @@ + + + + + + + + Designer diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteStateMenu.cs b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteStateMenu.cs new file mode 100644 index 00000000000..5329eafdb82 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteStateMenu.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace Dnn.EditBar.UI.Items +{ + using System; + + using Dnn.EditBar.Library; + using Dnn.EditBar.Library.Items; + using DotNetNuke.Application; + using DotNetNuke.Entities.Content.Common; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Security.Permissions; + using DotNetNuke.Services.Personalization; + + [Serializable] + public class CompleteStateMenu : BaseMenuItem + { + /// + public override string Name { get; } = "CompleteState"; + + /// + public override string Text => "Submit"; + + /// + public override string CssClass => string.Empty; + + /// + public override string Template { get; } = string.Empty; + + /// + public override string Parent { get; } = Constants.LeftMenu; + + /// + public override string Loader { get; } = "CompleteState"; + + /// + public override int Order { get; } = 77; + + /// + public override bool Visible() + { + var contentItem = Util.GetContentController().GetContentItem(TabController.CurrentPage.ContentItemId); + return Personalization.GetUserMode() == PortalSettings.Mode.Edit + && DotNetNukeContext.Current.Application.SKU == "DNN" // IsPlatform + && TabWorkflowSettings.Instance.IsWorkflowEnabled(PortalSettings.Current.PortalId) // workflow is enabled + && ((WorkflowEngine.Instance.IsWorkflowOnDraft(contentItem) && PermissionProvider.Instance().CanAddContentToPage(TabController.CurrentPage)) + || (!WorkflowEngine.Instance.IsWorkflowCompleted(contentItem) && WorkflowSecurity.Instance.HasStateReviewerPermission(contentItem.StateID))); + } + } +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteWorkflowMenu.cs b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteWorkflowMenu.cs new file mode 100644 index 00000000000..148ce00d5d3 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/CompleteWorkflowMenu.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace Dnn.EditBar.UI.Items +{ + using System; + + using Dnn.EditBar.Library; + using Dnn.EditBar.Library.Items; + using DotNetNuke.Application; + using DotNetNuke.Entities.Content.Common; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Services.Personalization; + + [Serializable] + public class CompleteWorkflowMenu : BaseMenuItem + { + /// + public override string Name { get; } = "CompleteWorkflow"; + + /// + public override string Text => "Approve"; + + /// + public override string CssClass => string.Empty; + + /// + public override string Template { get; } = string.Empty; + + /// + public override string Parent { get; } = Constants.LeftMenu; + + /// + public override string Loader { get; } = "CompleteWorkflow"; + + /// + public override int Order { get; } = 79; + + /// + public override bool Visible() + { + var contentItem = Util.GetContentController().GetContentItem(TabController.CurrentPage.ContentItemId); + return Personalization.GetUserMode() == PortalSettings.Mode.Edit + && DotNetNukeContext.Current.Application.SKU == "DNN" // IsPlatform + && TabWorkflowSettings.Instance.IsWorkflowEnabled(PortalSettings.Current.PortalId) // workflow is enabled + && !WorkflowEngine.Instance.IsWorkflowCompleted(contentItem) // tab has new version that is not published + && WorkflowSecurity.Instance.HasStateReviewerPermission(contentItem.StateID); // user has workflow approval permission + } + } +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardStateMenu.cs b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardStateMenu.cs new file mode 100644 index 00000000000..9fc915c7f97 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardStateMenu.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace Dnn.EditBar.UI.Items +{ + using System; + + using Dnn.EditBar.Library; + using Dnn.EditBar.Library.Items; + using DotNetNuke.Application; + using DotNetNuke.Entities.Content.Common; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Security.Permissions; + using DotNetNuke.Services.Personalization; + + [Serializable] + public class DiscardStateMenu : BaseMenuItem + { + /// + public override string Name { get; } = "DiscardState"; + + /// + public override string Text => "Discard"; + + /// + public override string CssClass => string.Empty; + + /// + public override string Template { get; } = string.Empty; + + /// + public override string Parent { get; } = Constants.LeftMenu; + + /// + public override string Loader { get; } = "DiscardState"; + + /// + public override int Order { get; } = 78; + + /// + public override bool Visible() + { + var contentItem = Util.GetContentController().GetContentItem(TabController.CurrentPage.ContentItemId); + return Personalization.GetUserMode() == PortalSettings.Mode.Edit + && DotNetNukeContext.Current.Application.SKU == "DNN" // IsPlatform + && TabWorkflowSettings.Instance.IsWorkflowEnabled(PortalSettings.Current.PortalId) // workflow is enabled + && ((WorkflowEngine.Instance.IsWorkflowOnDraft(contentItem) && PermissionProvider.Instance().CanAddContentToPage(TabController.CurrentPage)) + || (!WorkflowEngine.Instance.IsWorkflowCompleted(contentItem) && WorkflowSecurity.Instance.HasStateReviewerPermission(contentItem.StateID))); + } + } +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardWorkflowMenu.cs b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardWorkflowMenu.cs new file mode 100644 index 00000000000..2a9af9d996f --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/Items/DiscardWorkflowMenu.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace Dnn.EditBar.UI.Items +{ + using System; + + using Dnn.EditBar.Library; + using Dnn.EditBar.Library.Items; + using DotNetNuke.Application; + using DotNetNuke.Entities.Content.Common; + using DotNetNuke.Entities.Content.Workflow; + using DotNetNuke.Entities.Portals; + using DotNetNuke.Entities.Tabs; + using DotNetNuke.Security.Permissions; + using DotNetNuke.Services.Personalization; + + [Serializable] + public class DiscardWorkflowMenu : BaseMenuItem + { + /// + public override string Name { get; } = "DiscardWorkflow"; + + /// + public override string Text => "Reject"; + + /// + public override string CssClass => string.Empty; + + /// + public override string Template { get; } = string.Empty; + + /// + public override string Parent { get; } = Constants.LeftMenu; + + /// + public override string Loader { get; } = "DiscardWorkflow"; + + /// + public override int Order { get; } = 80; + + /// + public override bool Visible() + { + var contentItem = Util.GetContentController().GetContentItem(TabController.CurrentPage.ContentItemId); + return Personalization.GetUserMode() == PortalSettings.Mode.Edit + && DotNetNukeContext.Current.Application.SKU == "DNN" // IsPlatform + && TabWorkflowSettings.Instance.IsWorkflowEnabled(PortalSettings.Current.PortalId) // workflow is enabled + && !WorkflowEngine.Instance.IsWorkflowCompleted(contentItem) // tab has new version that is not published + && WorkflowSecurity.Instance.HasStateReviewerPermission(contentItem.StateID); // user has workflow approval permission + } + } +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteState.css b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteState.css new file mode 100644 index 00000000000..94d99a61f86 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteState.css @@ -0,0 +1,9 @@ +#menu-CompleteState button { + width: auto; + -ms-border-radius: 3px; + border-radius: 3px; + background-color: transparent; + border-style: solid; + border-width: 1px; + text-indent: 0; +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteWorkflow.css b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteWorkflow.css new file mode 100644 index 00000000000..9e1096100c8 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/CompleteWorkflow.css @@ -0,0 +1,9 @@ +#menu-CompleteWorkflow button { + width: auto; + -ms-border-radius: 3px; + border-radius: 3px; + background-color: transparent; + border-style: solid; + border-width: 1px; + text-indent: 0; +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardState.css b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardState.css new file mode 100644 index 00000000000..5a9d783de1f --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardState.css @@ -0,0 +1,9 @@ +#menu-DiscardState button { + width: auto; + -ms-border-radius: 3px; + border-radius: 3px; + background-color: transparent; + border-style: solid; + border-width: 1px; + text-indent: 0; +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardWorkflow.css b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardWorkflow.css new file mode 100644 index 00000000000..fa9ecbbc479 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/css/DiscardWorkflow.css @@ -0,0 +1,9 @@ +#menu-DiscardWorkflow button { + width: auto; + -ms-border-radius: 3px; + border-radius: 3px; + background-color: transparent; + border-style: solid; + border-width: 1px; + text-indent: 0; +} diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteState.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteState.js new file mode 100644 index 00000000000..3eb9ee08f2b --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteState.js @@ -0,0 +1,26 @@ +define(['jquery'], function ($) { + 'use strict'; + var menuItem, util; + + var init = function (menu, utility, params, callback) { + menuItem = menu; + util = utility; + + if (typeof callback === 'function') { + callback(); + } + }; + + var onClick = function () { + util.sf.moduleRoot = 'internalservices'; + util.sf.controller = "contentWorkflowService"; + util.sf.post('CompleteState', {}, function done() { + window.top.location = window.top.location.protocol + '//' + window.top.location.host + window.top.location.pathname + window.top.location.search; + }); + } + + return { + init: init, + onClick: onClick + }; +}); diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteWorkflow.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteWorkflow.js new file mode 100644 index 00000000000..0a001101002 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/CompleteWorkflow.js @@ -0,0 +1,26 @@ +define(['jquery'], function ($) { + 'use strict'; + var menuItem, util; + + var init = function (menu, utility, params, callback) { + menuItem = menu; + util = utility; + + if (typeof callback === 'function') { + callback(); + } + }; + + var onClick = function () { + util.sf.moduleRoot = 'internalservices'; + util.sf.controller = "contentWorkflowService"; + util.sf.post('CompleteWorkflow', {}, function done() { + window.top.location = window.top.location.protocol + '//' + window.top.location.host + window.top.location.pathname + window.top.location.search; + }); + } + + return { + init: init, + onClick: onClick + }; +}); diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardState.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardState.js new file mode 100644 index 00000000000..d0b2663c9d1 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardState.js @@ -0,0 +1,26 @@ +define(['jquery'], function ($) { + 'use strict'; + var menuItem, util; + + var init = function (menu, utility, params, callback) { + menuItem = menu; + util = utility; + + if (typeof callback === 'function') { + callback(); + } + }; + + var onClick = function () { + util.sf.moduleRoot = 'internalservices'; + util.sf.controller = "contentWorkflowService"; + util.sf.post('DiscardState', {}, function done() { + window.top.location = window.top.location.protocol + '//' + window.top.location.host + window.top.location.pathname + window.top.location.search; + }); + } + + return { + init: init, + onClick: onClick + }; +}); diff --git a/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardWorkflow.js b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardWorkflow.js new file mode 100644 index 00000000000..c8184912451 --- /dev/null +++ b/Dnn.AdminExperience/EditBar/Dnn.EditBar.UI/editBar/scripts/DiscardWorkflow.js @@ -0,0 +1,26 @@ +define(['jquery'], function ($) { + 'use strict'; + var menuItem, util; + + var init = function (menu, utility, params, callback) { + menuItem = menu; + util = utility; + + if (typeof callback === 'function') { + callback(); + } + }; + + var onClick = function () { + util.sf.moduleRoot = 'internalservices'; + util.sf.controller = "contentWorkflowService"; + util.sf.post('DiscardWorkflow', {}, function done() { + window.top.location = window.top.location.protocol + '//' + window.top.location.host + window.top.location.pathname + window.top.location.search; + }); + } + + return { + init: init, + onClick: onClick + }; +});