예제 #1
0
        /// <summary>
        /// Handles the OnSave event of the masterPage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void masterPage_OnSave(object sender, EventArgs e)
        {
            Page.Validate(BlockValidationGroup);
            if (Page.IsValid && _pageId.HasValue)
            {
                var rockContext    = new RockContext();
                var pageService    = new PageService(rockContext);
                var routeService   = new PageRouteService(rockContext);
                var contextService = new PageContextService(rockContext);

                var page = pageService.Get(_pageId.Value);

                int parentPageId = ppParentPage.SelectedValueAsInt() ?? 0;
                if (page.ParentPageId != parentPageId)
                {
                    if (page.ParentPageId.HasValue)
                    {
                        PageCache.Flush(page.ParentPageId.Value);
                    }

                    if (parentPageId != 0)
                    {
                        PageCache.Flush(parentPageId);
                    }
                }

                page.InternalName = tbPageName.Text;
                page.PageTitle    = tbPageTitle.Text;
                page.BrowserTitle = tbBrowserTitle.Text;
                if (parentPageId != 0)
                {
                    page.ParentPageId = parentPageId;
                }
                else
                {
                    page.ParentPageId = null;
                }

                page.LayoutId = ddlLayout.SelectedValueAsInt().Value;

                int?orphanedIconFileId = null;

                page.IconCssClass = tbIconCssClass.Text;

                page.PageDisplayTitle       = cbPageTitle.Checked;
                page.PageDisplayBreadCrumb  = cbPageBreadCrumb.Checked;
                page.PageDisplayIcon        = cbPageIcon.Checked;
                page.PageDisplayDescription = cbPageDescription.Checked;

                page.DisplayInNavWhen       = (DisplayInNavWhen)Enum.Parse(typeof(DisplayInNavWhen), ddlMenuWhen.SelectedValue);
                page.MenuDisplayDescription = cbMenuDescription.Checked;
                page.MenuDisplayIcon        = cbMenuIcon.Checked;
                page.MenuDisplayChildPages  = cbMenuChildPages.Checked;

                page.BreadCrumbDisplayName = cbBreadCrumbName.Checked;
                page.BreadCrumbDisplayIcon = cbBreadCrumbIcon.Checked;

                page.RequiresEncryption  = cbRequiresEncryption.Checked;
                page.EnableViewState     = cbEnableViewState.Checked;
                page.IncludeAdminFooter  = cbIncludeAdminFooter.Checked;
                page.OutputCacheDuration = int.Parse(tbCacheDuration.Text);
                page.Description         = tbDescription.Text;
                page.HeaderContent       = ceHeaderContent.Text;

                // new or updated route
                foreach (var pageRoute in page.PageRoutes.ToList())
                {
                    var existingRoute = RouteTable.Routes.OfType <Route>().FirstOrDefault(a => a.RouteId() == pageRoute.Id);
                    if (existingRoute != null)
                    {
                        RouteTable.Routes.Remove(existingRoute);
                    }

                    routeService.Delete(pageRoute);
                }

                page.PageRoutes.Clear();

                foreach (string route in tbPageRoute.Text.SplitDelimitedValues())
                {
                    var pageRoute = new PageRoute();
                    pageRoute.Route = route.TrimStart(new char[] { '/' });
                    pageRoute.Guid  = Guid.NewGuid();
                    page.PageRoutes.Add(pageRoute);
                }

                foreach (var pageContext in page.PageContexts.ToList())
                {
                    contextService.Delete(pageContext);
                }

                page.PageContexts.Clear();
                foreach (var control in phContext.Controls)
                {
                    if (control is RockTextBox)
                    {
                        var tbContext = control as RockTextBox;
                        if (!string.IsNullOrWhiteSpace(tbContext.Text))
                        {
                            var pageContext = new PageContext();
                            pageContext.Entity      = tbContext.ID.Substring(8).Replace('_', '.');
                            pageContext.IdParameter = tbContext.Text;
                            page.PageContexts.Add(pageContext);
                        }
                    }
                }

                if (page.IsValid)
                {
                    rockContext.SaveChanges();

                    foreach (var pageRoute in new PageRouteService(rockContext).GetByPageId(page.Id))
                    {
                        RouteTable.Routes.AddPageRoute(pageRoute);
                    }

                    if (orphanedIconFileId.HasValue)
                    {
                        BinaryFileService binaryFileService = new BinaryFileService(rockContext);
                        var binaryFile = binaryFileService.Get(orphanedIconFileId.Value);
                        if (binaryFile != null)
                        {
                            // marked the old images as IsTemporary so they will get cleaned up later
                            binaryFile.IsTemporary = true;
                            rockContext.SaveChanges();
                        }
                    }

                    Rock.Web.Cache.PageCache.Flush(page.Id);

                    string script = "if (typeof window.parent.Rock.controls.modal.close === 'function') window.parent.Rock.controls.modal.close('PAGE_UPDATED');";
                    ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "close-modal", script, true);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Handles the OnSave event of the masterPage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void masterPage_OnSave(object sender, EventArgs e)
        {
            Page.Validate(BlockValidationGroup);
            if (Page.IsValid && _pageId.HasValue)
            {
                var rockContext    = new RockContext();
                var pageService    = new PageService(rockContext);
                var routeService   = new PageRouteService(rockContext);
                var contextService = new PageContextService(rockContext);

                var page = pageService.Get(_pageId.Value);

                // validate/check for removed routes
                var editorRoutes       = tbPageRoute.Text.SplitDelimitedValues().Distinct();
                var databasePageRoutes = page.PageRoutes.ToList();
                var deletedRouteIds    = new List <int>();
                var addedRoutes        = new List <string>();

                if (editorRoutes.Any())
                {
                    int?siteId = null;
                    if (page != null && page.Layout != null)
                    {
                        siteId = page.Layout.SiteId;
                    }

                    // validate for any duplicate routes
                    var duplicateRouteQry = routeService.Queryable()
                                            .Where(r =>
                                                   r.PageId != _pageId &&
                                                   editorRoutes.Contains(r.Route));
                    if (siteId.HasValue)
                    {
                        duplicateRouteQry = duplicateRouteQry
                                            .Where(r =>
                                                   r.Page != null &&
                                                   r.Page.Layout != null &&
                                                   r.Page.Layout.SiteId == siteId.Value);
                    }

                    var duplicateRoutes = duplicateRouteQry
                                          .Select(r => r.Route)
                                          .Distinct()
                                          .ToList();

                    if (duplicateRoutes.Any())
                    {
                        // Duplicate routes
                        nbPageRouteWarning.Title       = "Duplicate Route(s)";
                        nbPageRouteWarning.Text        = string.Format("<p>The page route <strong>{0}</strong>, already exists for another page in the same site. Please choose a different route name.</p>", duplicateRoutes.AsDelimited("</strong> and <strong>"));
                        nbPageRouteWarning.Dismissable = true;
                        nbPageRouteWarning.Visible     = true;
                        CurrentTab = "Advanced Settings";

                        rptProperties.DataSource = _tabs;
                        rptProperties.DataBind();
                        ShowSelectedPane();
                        return;
                    }
                }

                // validate if removed routes can be deleted
                foreach (var pageRoute in databasePageRoutes)
                {
                    if (!editorRoutes.Contains(pageRoute.Route))
                    {
                        // make sure the route can be deleted
                        string errorMessage;
                        if (!routeService.CanDelete(pageRoute, out errorMessage))
                        {
                            nbPageRouteWarning.Text = string.Format("The page route <strong>{0}</strong>, cannot be removed. {1}", pageRoute.Route, errorMessage);
                            nbPageRouteWarning.NotificationBoxType = NotificationBoxType.Warning;
                            nbPageRouteWarning.Dismissable         = true;
                            nbPageRouteWarning.Visible             = true;
                            CurrentTab = "Advanced Settings";

                            rptProperties.DataSource = _tabs;
                            rptProperties.DataBind();
                            ShowSelectedPane();
                            return;
                        }
                    }
                }

                // take care of deleted routes
                foreach (var pageRoute in databasePageRoutes)
                {
                    if (!editorRoutes.Contains(pageRoute.Route))
                    {
                        // if they removed the Route, remove it from the database
                        page.PageRoutes.Remove(pageRoute);

                        routeService.Delete(pageRoute);
                        deletedRouteIds.Add(pageRoute.Id);
                    }
                }

                // take care of added routes
                foreach (string route in editorRoutes)
                {
                    // if they added the Route, add it to the database
                    if (!databasePageRoutes.Any(a => a.Route == route))
                    {
                        var pageRoute = new PageRoute();
                        pageRoute.Route = route.TrimStart(new char[] { '/' });
                        pageRoute.Guid  = Guid.NewGuid();
                        page.PageRoutes.Add(pageRoute);
                        addedRoutes.Add(route);
                    }
                }

                int parentPageId = ppParentPage.SelectedValueAsInt() ?? 0;
                if (page.ParentPageId != parentPageId)
                {
                    if (page.ParentPageId.HasValue)
                    {
                        PageCache.Flush(page.ParentPageId.Value);
                    }

                    if (parentPageId != 0)
                    {
                        PageCache.Flush(parentPageId);
                    }
                }

                page.InternalName = tbPageName.Text;
                page.PageTitle    = tbPageTitle.Text;
                page.BrowserTitle = tbBrowserTitle.Text;
                page.BodyCssClass = tbBodyCssClass.Text;

                if (parentPageId != 0)
                {
                    page.ParentPageId = parentPageId;
                }
                else
                {
                    page.ParentPageId = null;
                }

                page.LayoutId = ddlLayout.SelectedValueAsInt().Value;

                int?orphanedIconFileId = null;

                page.IconCssClass = tbIconCssClass.Text;

                page.PageDisplayTitle       = cbPageTitle.Checked;
                page.PageDisplayBreadCrumb  = cbPageBreadCrumb.Checked;
                page.PageDisplayIcon        = cbPageIcon.Checked;
                page.PageDisplayDescription = cbPageDescription.Checked;

                page.DisplayInNavWhen       = ddlMenuWhen.SelectedValue.ConvertToEnumOrNull <DisplayInNavWhen>() ?? DisplayInNavWhen.WhenAllowed;
                page.MenuDisplayDescription = cbMenuDescription.Checked;
                page.MenuDisplayIcon        = cbMenuIcon.Checked;
                page.MenuDisplayChildPages  = cbMenuChildPages.Checked;

                page.BreadCrumbDisplayName = cbBreadCrumbName.Checked;
                page.BreadCrumbDisplayIcon = cbBreadCrumbIcon.Checked;

                page.RequiresEncryption  = cbRequiresEncryption.Checked;
                page.EnableViewState     = cbEnableViewState.Checked;
                page.IncludeAdminFooter  = cbIncludeAdminFooter.Checked;
                page.AllowIndexing       = cbAllowIndexing.Checked;
                page.OutputCacheDuration = tbCacheDuration.Text.AsIntegerOrNull() ?? 0;
                page.Description         = tbDescription.Text;
                page.HeaderContent       = ceHeaderContent.Text;

                // update PageContexts
                foreach (var pageContext in page.PageContexts.ToList())
                {
                    contextService.Delete(pageContext);
                }

                page.PageContexts.Clear();
                foreach (var control in phContext.Controls)
                {
                    if (control is RockTextBox)
                    {
                        var tbContext = control as RockTextBox;
                        if (!string.IsNullOrWhiteSpace(tbContext.Text))
                        {
                            var pageContext = new PageContext();
                            pageContext.Entity      = tbContext.ID.Substring(8).Replace('_', '.');
                            pageContext.IdParameter = tbContext.Text;
                            page.PageContexts.Add(pageContext);
                        }
                    }
                }

                // save page and it's routes
                if (page.IsValid)
                {
                    rockContext.SaveChanges();

                    // remove any routes for this page that are no longer configured
                    foreach (var existingRoute in RouteTable.Routes.OfType <Route>().Where(a => a.PageIds().Contains(page.Id)))
                    {
                        if (!editorRoutes.Any(a => a == existingRoute.Url))
                        {
                            var pageAndRouteIds = existingRoute.DataTokens["PageRoutes"] as List <Rock.Web.PageAndRouteId>;
                            pageAndRouteIds = pageAndRouteIds.Where(p => p.PageId != page.Id).ToList();
                            if (pageAndRouteIds.Any())
                            {
                                existingRoute.DataTokens["PageRoutes"] = pageAndRouteIds;
                            }
                            else
                            {
                                RouteTable.Routes.Remove(existingRoute);
                            }
                        }
                    }

                    // Add any routes that were added
                    foreach (var pageRoute in new PageRouteService(rockContext).GetByPageId(page.Id))
                    {
                        if (addedRoutes.Contains(pageRoute.Route))
                        {
                            var pageAndRouteId = new Rock.Web.PageAndRouteId {
                                PageId = pageRoute.PageId, RouteId = pageRoute.Id
                            };

                            var existingRoute = RouteTable.Routes.OfType <Route>().FirstOrDefault(r => r.Url == pageRoute.Route);
                            if (existingRoute != null)
                            {
                                var pageAndRouteIds = existingRoute.DataTokens["PageRoutes"] as List <Rock.Web.PageAndRouteId>;
                                pageAndRouteIds.Add(pageAndRouteId);
                                existingRoute.DataTokens["PageRoutes"] = pageAndRouteIds;
                            }
                            else
                            {
                                var pageAndRouteIds = new List <Rock.Web.PageAndRouteId>();
                                pageAndRouteIds.Add(pageAndRouteId);
                                RouteTable.Routes.AddPageRoute(pageRoute.Route, pageAndRouteIds);
                            }
                        }
                    }

                    if (orphanedIconFileId.HasValue)
                    {
                        BinaryFileService binaryFileService = new BinaryFileService(rockContext);
                        var binaryFile = binaryFileService.Get(orphanedIconFileId.Value);
                        if (binaryFile != null)
                        {
                            // marked the old images as IsTemporary so they will get cleaned up later
                            binaryFile.IsTemporary = true;
                            rockContext.SaveChanges();
                        }
                    }

                    Rock.Web.Cache.PageCache.Flush(page.Id);

                    string script = "if (typeof window.parent.Rock.controls.modal.close === 'function') window.parent.Rock.controls.modal.close('PAGE_UPDATED');";
                    ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "close-modal", script, true);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Handles the OnSave event of the masterPage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void masterPage_OnSave(object sender, EventArgs e)
        {
            Page.Validate(BlockValidationGroup);
            if (!Page.IsValid)
            {
                throw new Exception("Page is not valid");
            }

            var rockContext    = new RockContext();
            var pageService    = new PageService(rockContext);
            var routeService   = new PageRouteService(rockContext);
            var contextService = new PageContextService(rockContext);

            int pageId = hfPageId.Value.AsInteger();

            var page = pageService.Get(pageId);

            if (page == null)
            {
                page = new Rock.Model.Page();
                pageService.Add(page);
            }

            // validate/check for removed routes
            var editorRoutes       = tbPageRoute.Text.SplitDelimitedValues().Distinct();
            var databasePageRoutes = page.PageRoutes.ToList();
            var deletedRouteIds    = new List <int>();
            var addedRoutes        = new List <string>();

            if (editorRoutes.Any())
            {
                int?siteId = null;
                if (page != null && page.Layout != null)
                {
                    siteId = page.Layout.SiteId;
                }

                // validate for any duplicate routes
                var duplicateRouteQry = routeService.Queryable()
                                        .Where(r =>
                                               r.PageId != pageId &&
                                               editorRoutes.Contains(r.Route));
                if (siteId.HasValue)
                {
                    duplicateRouteQry = duplicateRouteQry
                                        .Where(r =>
                                               r.Page != null &&
                                               r.Page.Layout != null &&
                                               r.Page.Layout.SiteId == siteId.Value);
                }

                var duplicateRoutes = duplicateRouteQry
                                      .Select(r => r.Route)
                                      .Distinct()
                                      .ToList();

                if (duplicateRoutes.Any())
                {
                    // Duplicate routes
                    nbPageRouteWarning.Title       = "Duplicate Route(s)";
                    nbPageRouteWarning.Text        = string.Format("<p>The page route <strong>{0}</strong>, already exists for another page in the same site. Please choose a different route name.</p>", duplicateRoutes.AsDelimited("</strong> and <strong>"));
                    nbPageRouteWarning.Dismissable = true;
                    nbPageRouteWarning.Visible     = true;
                    CurrentTab = "Advanced Settings";

                    rptProperties.DataSource = _tabs;
                    rptProperties.DataBind();
                    ShowSelectedPane();
                    throw new Exception(string.Format("The page route {0} already exists for another page in the same site.", duplicateRoutes.AsDelimited(" and ")));
                }
            }

            // validate if removed routes can be deleted
            foreach (var pageRoute in databasePageRoutes)
            {
                if (!editorRoutes.Contains(pageRoute.Route))
                {
                    // make sure the route can be deleted
                    string errorMessage;
                    if (!routeService.CanDelete(pageRoute, out errorMessage))
                    {
                        nbPageRouteWarning.Text = string.Format("The page route <strong>{0}</strong>, cannot be removed. {1}", pageRoute.Route, errorMessage);
                        nbPageRouteWarning.NotificationBoxType = NotificationBoxType.Warning;
                        nbPageRouteWarning.Dismissable         = true;
                        nbPageRouteWarning.Visible             = true;
                        CurrentTab = "Advanced Settings";

                        rptProperties.DataSource = _tabs;
                        rptProperties.DataBind();
                        ShowSelectedPane();
                        throw new Exception(string.Format("The page route {0} cannot be removed. {1}", pageRoute.Route, errorMessage));
                    }
                }
            }

            // take care of deleted routes
            foreach (var pageRoute in databasePageRoutes)
            {
                if (!editorRoutes.Contains(pageRoute.Route))
                {
                    // if they removed the Route, remove it from the database
                    page.PageRoutes.Remove(pageRoute);

                    routeService.Delete(pageRoute);
                    deletedRouteIds.Add(pageRoute.Id);
                }
            }

            // take care of added routes
            foreach (string route in editorRoutes)
            {
                // if they added the Route, add it to the database
                if (!databasePageRoutes.Any(a => a.Route == route))
                {
                    var pageRoute = new PageRoute();
                    pageRoute.Route = route.TrimStart(new char[] { '/' });
                    pageRoute.Guid  = Guid.NewGuid();
                    page.PageRoutes.Add(pageRoute);
                    addedRoutes.Add(pageRoute.Route);
                }
            }

            int parentPageId = ppParentPage.SelectedValueAsInt() ?? 0;

            page.InternalName = tbPageName.Text;
            page.PageTitle    = tbPageTitle.Text;
            page.BrowserTitle = tbBrowserTitle.Text;
            page.BodyCssClass = tbBodyCssClass.Text;

            if (parentPageId != 0)
            {
                page.ParentPageId = parentPageId;

                if (page.Id == 0)
                {
                    // newly added page, make sure the Order is correct
                    Rock.Model.Page lastPage = pageService.GetByParentPageId(parentPageId).OrderByDescending(b => b.Order).FirstOrDefault();
                    if (lastPage != null)
                    {
                        page.Order = lastPage.Order + 1;
                    }
                }
            }
            else
            {
                page.ParentPageId = null;
            }

            page.LayoutId = ddlLayout.SelectedValueAsInt().Value;

            int?orphanedIconFileId = null;

            page.IconCssClass = tbIconCssClass.Text;

            page.PageDisplayTitle       = cbPageTitle.Checked;
            page.PageDisplayBreadCrumb  = cbPageBreadCrumb.Checked;
            page.PageDisplayIcon        = cbPageIcon.Checked;
            page.PageDisplayDescription = cbPageDescription.Checked;

            page.DisplayInNavWhen       = ddlMenuWhen.SelectedValue.ConvertToEnumOrNull <DisplayInNavWhen>() ?? DisplayInNavWhen.WhenAllowed;
            page.MenuDisplayDescription = cbMenuDescription.Checked;
            page.MenuDisplayIcon        = cbMenuIcon.Checked;
            page.MenuDisplayChildPages  = cbMenuChildPages.Checked;

            page.BreadCrumbDisplayName = cbBreadCrumbName.Checked;
            page.BreadCrumbDisplayIcon = cbBreadCrumbIcon.Checked;

            page.RequiresEncryption = cbRequiresEncryption.Checked;
            page.EnableViewState    = cbEnableViewState.Checked;
            page.IncludeAdminFooter = cbIncludeAdminFooter.Checked;
            page.AllowIndexing      = cbAllowIndexing.Checked;

            page.CacheControlHeaderSettings = cpCacheSettings.CurrentCacheability.ToJson();

            page.Description   = tbDescription.Text;
            page.HeaderContent = ceHeaderContent.Text;

            // update PageContexts
            foreach (var pageContext in page.PageContexts.ToList())
            {
                contextService.Delete(pageContext);
            }

            page.PageContexts.Clear();
            foreach (var control in phContext.Controls)
            {
                if (control is RockTextBox)
                {
                    var tbContext = control as RockTextBox;
                    if (!string.IsNullOrWhiteSpace(tbContext.Text))
                    {
                        var pageContext = new PageContext();
                        pageContext.Entity      = tbContext.ID.Substring(8).Replace('_', '.');
                        pageContext.IdParameter = tbContext.Text;
                        page.PageContexts.Add(pageContext);
                    }
                }
            }

            // Page Attributes
            page.LoadAttributes();

            Rock.Attribute.Helper.GetEditValues(phPageAttributes, page);

            // save page and it's routes
            if (page.IsValid)
            {
                // use WrapTransaction since SaveAttributeValues does its own RockContext.SaveChanges()
                rockContext.WrapTransaction(() =>
                {
                    rockContext.SaveChanges();

                    page.SaveAttributeValues(rockContext);
                });

                Rock.Web.RockRouteHandler.ReregisterRoutes();

                if (orphanedIconFileId.HasValue)
                {
                    BinaryFileService binaryFileService = new BinaryFileService(rockContext);
                    var binaryFile = binaryFileService.Get(orphanedIconFileId.Value);
                    if (binaryFile != null)
                    {
                        // marked the old images as IsTemporary so they will get cleaned up later
                        binaryFile.IsTemporary = true;
                        rockContext.SaveChanges();
                    }
                }

                string script = "if (typeof window.parent.Rock.controls.modal.close === 'function') window.parent.Rock.controls.modal.close('PAGE_UPDATED');";
                ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "close-modal", script, true);

                hfPageId.Value = page.Id.ToString();
            }
        }
예제 #4
0
        /// <summary>
        /// Recursively saves Pages and associated Blocks, PageRoutes and PageContexts.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="page">The current Page to save</param>
        /// <param name="newBlockTypes">List of BlockTypes not currently installed</param>
        /// <param name="parentPageId">Id of the current Page's parent</param>
        /// <param name="siteId">Id of the site the current Page is being imported into</param>
        private void SavePages(RockContext rockContext, Page page, IEnumerable <BlockType> newBlockTypes, int parentPageId, int siteId)
        {
            rockContext = rockContext ?? new RockContext();

            // find layout
            var    layoutService = new LayoutService(rockContext);
            Layout layout        = new Layout();

            if (page.Layout != null)
            {
                layout = layoutService.GetBySiteId(siteId).Where(l => l.Name == page.Layout.Name && l.FileName == page.Layout.FileName).FirstOrDefault();
                if (layout == null)
                {
                    layout          = new Layout();
                    layout.FileName = page.Layout.FileName;
                    layout.Name     = page.Layout.Name;
                    layout.SiteId   = siteId;
                    layoutService.Add(layout);
                    rockContext.SaveChanges();
                }
            }
            else
            {
                layout = layoutService.GetBySiteId(siteId).Where(l => l.Name.Contains("Full") || l.Name.Contains("Home")).First();
            }
            int layoutId = layout.Id;

            // Force shallow copies on entities so save operations are more atomic and don't get hosed
            // by nested object references.
            var pg         = page.Clone(deepCopy: false);
            var blockTypes = newBlockTypes.ToList();

            pg.ParentPageId = parentPageId;
            pg.LayoutId     = layoutId;

            var pageService = new PageService(rockContext);

            pageService.Add(pg);
            rockContext.SaveChanges();

            var blockService = new BlockService(rockContext);

            foreach (var block in page.Blocks ?? new List <Block>())
            {
                var blockType = blockTypes.FirstOrDefault(bt => block.BlockType.Path == bt.Path);
                var b         = block.Clone(deepCopy: false);
                b.PageId = pg.Id;

                if (blockType != null)
                {
                    b.BlockTypeId = blockType.Id;
                }

                blockService.Add(b);
            }
            rockContext.SaveChanges();

            var pageRouteService = new PageRouteService(rockContext);

            foreach (var pageRoute in page.PageRoutes ?? new List <PageRoute>())
            {
                var pr = pageRoute.Clone(deepCopy: false);
                pr.PageId = pg.Id;
                pageRouteService.Add(pr);
            }
            rockContext.SaveChanges();

            var pageContextService = new PageContextService(rockContext);

            foreach (var pageContext in page.PageContexts ?? new List <PageContext>())
            {
                var pc = pageContext.Clone(deepCopy: false);
                pc.PageId = pg.Id;
                pageContextService.Add(pc);
            }
            rockContext.SaveChanges();

            foreach (var p in page.Pages ?? new List <Page>())
            {
                SavePages(rockContext, p, blockTypes, pg.Id, siteId);
            }
        }
        /// <summary>
        /// Handles the OnSave event of the masterPage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void masterPage_OnSave(object sender, EventArgs e)
        {
            if (Page.IsValid)
            {
                using (new UnitOfWorkScope())
                {
                    var pageService    = new PageService();
                    var routeService   = new PageRouteService();
                    var contextService = new PageContextService();

                    var page = pageService.Get(_page.Id);

                    int parentPageId = ppParentPage.SelectedValueAsInt() ?? 0;
                    if (page.ParentPageId != parentPageId)
                    {
                        if (page.ParentPageId.HasValue)
                        {
                            PageCache.Flush(page.ParentPageId.Value);
                        }

                        if (parentPageId != 0)
                        {
                            PageCache.Flush(parentPageId);
                        }
                    }

                    page.Name  = tbPageName.Text;
                    page.Title = tbPageTitle.Text;
                    if (parentPageId != 0)
                    {
                        page.ParentPageId = parentPageId;
                    }
                    else
                    {
                        page.ParentPageId = null;
                    }

                    page.Layout       = ddlLayout.Text;
                    page.IconFileId   = imgIcon.BinaryFileId;
                    page.IconCssClass = tbIconCssClass.Text;

                    page.PageDisplayTitle       = cbPageTitle.Checked;
                    page.PageDisplayBreadCrumb  = cbPageBreadCrumb.Checked;
                    page.PageDisplayIcon        = cbPageIcon.Checked;
                    page.PageDisplayDescription = cbPageDescription.Checked;

                    page.DisplayInNavWhen       = (DisplayInNavWhen)Enum.Parse(typeof(DisplayInNavWhen), ddlMenuWhen.SelectedValue);
                    page.MenuDisplayDescription = cbMenuDescription.Checked;
                    page.MenuDisplayIcon        = cbMenuIcon.Checked;
                    page.MenuDisplayChildPages  = cbMenuChildPages.Checked;

                    page.BreadCrumbDisplayName = cbBreadCrumbName.Checked;
                    page.BreadCrumbDisplayIcon = cbBreadCrumbIcon.Checked;

                    page.RequiresEncryption  = cbRequiresEncryption.Checked;
                    page.EnableViewState     = cbEnableViewState.Checked;
                    page.IncludeAdminFooter  = cbIncludeAdminFooter.Checked;
                    page.OutputCacheDuration = int.Parse(tbCacheDuration.Text);
                    page.Description         = tbDescription.Text;

                    // new or updated route
                    foreach (var pageRoute in page.PageRoutes.ToList())
                    {
                        var existingRoute = RouteTable.Routes.OfType <Route>().FirstOrDefault(a => a.RouteId() == pageRoute.Id);
                        if (existingRoute != null)
                        {
                            RouteTable.Routes.Remove(existingRoute);
                        }

                        routeService.Delete(pageRoute, CurrentPersonId);
                    }

                    page.PageRoutes.Clear();

                    foreach (string route in tbPageRoute.Text.SplitDelimitedValues())
                    {
                        var pageRoute = new PageRoute();
                        pageRoute.Route = route;
                        pageRoute.Guid  = Guid.NewGuid();
                        page.PageRoutes.Add(pageRoute);
                    }

                    foreach (var pageContext in page.PageContexts.ToList())
                    {
                        contextService.Delete(pageContext, CurrentPersonId);
                    }

                    page.PageContexts.Clear();

                    if (phContextPanel.Visible)
                    {
                        foreach (var control in phContext.Controls)
                        {
                            if (control is RockTextBox)
                            {
                                var tbContext   = control as RockTextBox;
                                var pageContext = new PageContext();
                                pageContext.Entity      = tbContext.Label;
                                pageContext.IdParameter = tbContext.Text;
                                page.PageContexts.Add(pageContext);
                            }
                        }
                    }

                    pageService.Save(page, CurrentPersonId);

                    foreach (var pageRoute in new PageRouteService().GetByPageId(page.Id))
                    {
                        RouteTable.Routes.AddPageRoute(pageRoute);
                    }

                    Rock.Attribute.Helper.GetEditValues(phAttributes, _page);
                    _page.SaveAttributeValues(CurrentPersonId);

                    Rock.Web.Cache.PageCache.Flush(_page.Id);
                }

                string script = "if (typeof window.parent.Rock.controls.modal.close === 'function') window.parent.Rock.controls.modal.close();";
                ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "close-modal", script, true);
            }
        }