From 69d3a91bcac77b0fc3abf27e9fc80325e11b6b3e Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 28 Jun 2024 16:45:27 +0800 Subject: [PATCH 01/15] new container dialog;fix l10n not install on insert demo contianer --- example/integration/pagebuilder_test.go | 45 ++++++- pagebuilder/builder.go | 31 +++-- pagebuilder/editor.go | 42 ++---- pagebuilder/model.go | 162 +++++++++++++++++++----- 4 files changed, 199 insertions(+), 81 deletions(-) diff --git a/example/integration/pagebuilder_test.go b/example/integration/pagebuilder_test.go index f314e653e..f47acdd91 100644 --- a/example/integration/pagebuilder_test.go +++ b/example/integration/pagebuilder_test.go @@ -51,11 +51,15 @@ SELECT setval('container_list_content_id_seq', 10, true); INSERT INTO public.container_headers (id, color) VALUES (10, 'black'); SELECT setval('container_headers_id_seq', 10, true); +`, []string{"page_builder_pages", "page_builder_containers", "container_list_content", "container_headers"})) + +var pageBuilderDemoContainerTestData = gofixtures.Data(gofixtures.Sql(` +INSERT INTO public.page_builder_pages (id, created_at, updated_at, deleted_at, title, slug, category_id, seo, status, online_url, scheduled_start_at, scheduled_end_at, actual_start_at, actual_end_at, version, version_name, parent_version, locale_code) VALUES + (10, '2024-05-21 01:54:45.280106 +00:00', '2024-05-21 01:54:57.983233 +00:00', null, '1234567', '12313', 0, '{"OpenGraphImageFromMediaLibrary":{"ID":0,"Url":"","VideoLink":"","FileName":"","Description":""}}', 'draft', '', null, null, null, null, '2024-05-21-v01', '2024-05-21-v01', '', 'International'); +SELECT setval('page_builder_pages_id_seq', 10, true); INSERT INTO public.container_in_numbers (id, add_top_space, add_bottom_space, anchor_id, heading, items) VALUES (1, false, false, 'test1', '', 'null'); INSERT INTO public.page_builder_demo_containers (id, created_at, updated_at, deleted_at, model_name, model_id, locale_code) VALUES (1, '2024-06-25 02:21:41.014915 +00:00', '2024-06-25 02:21:41.014915 +00:00', null, 'InNumbers', 1, 'International'); - - -`, []string{"page_builder_pages", "page_builder_containers", "container_list_content", "container_headers", "container_in_numbers", "page_builder_demo_containers"})) +`, []string{"page_builder_pages", "page_builder_containers", "container_in_numbers", "page_builder_demo_containers"})) func TestPageBuilder(t *testing.T) { h := admin.TestHandler(TestDB, nil) @@ -170,6 +174,7 @@ func TestPageBuilder(t *testing.T) { }, ExpectPortalUpdate0ContainsInOrder: []string{"@change-debounced"}, }, + { Name: "Page Builder add container", Debug: true, @@ -399,7 +404,7 @@ func TestPageBuilder(t *testing.T) { Name: "Add New Demo Container", Debug: true, ReqFunc: func() *http.Request { - pageBuilderContainerTestData.TruncatePut(dbr) + pageBuilderDemoContainerTestData.TruncatePut(dbr) return NewMultipartBuilder(). PageURL("/page_builder/pages-editors/1_v1_International"). EventFunc(pagebuilder.AddContainerEvent). @@ -410,8 +415,8 @@ func TestPageBuilder(t *testing.T) { EventResponseMatch: func(t *testing.T, er *TestEventResponse) { var cons []*pagebuilder.Container TestDB.Order("id desc").Find(&cons) - if len(cons) != 3 { - t.Fatalf("add container failed, expected 3 cons, got %d", len(cons)) + if len(cons) != 1 { + t.Fatalf("add container failed, expected 1 cons, got %d", len(cons)) return } if cons[0].ModelName != "InNumbers" { @@ -434,7 +439,7 @@ func TestPageBuilder(t *testing.T) { Name: "Edit Demo Container", Debug: true, ReqFunc: func() *http.Request { - pageBuilderContainerTestData.TruncatePut(dbr) + pageBuilderDemoContainerTestData.TruncatePut(dbr) return NewMultipartBuilder(). PageURL("/page_builder/in-numbers?__execute_event__=presets_Update&id=1"). AddField("AnchorID", "test_in_numbers"). @@ -465,6 +470,32 @@ func TestPageBuilder(t *testing.T) { } }, }, + { + Name: "Page Builder add container dialog", + Debug: true, + ReqFunc: func() *http.Request { + pageBuilderContainerTestData.TruncatePut(dbr) + req := NewMultipartBuilder(). + PageURL("/page_builder/pages-editors/10_2024-05-21-v01_International?__execute_event__=page_builder_NewContainerDialogEvent"). + BuildEventFuncRequest() + + return req + }, + ExpectPortalUpdate0ContainsInOrder: []string{"Navigation"}, + }, + { + Name: "Page Builder preview demo container ", + Debug: true, + ReqFunc: func() *http.Request { + pageBuilderDemoContainerTestData.TruncatePut(dbr) + req := NewMultipartBuilder(). + PageURL("/page_builder/pages-editors/10_2024-05-21-v01_International?__execute_event__=page_builder_ContainerPreviewEvent&modelName=InNumbers"). + BuildEventFuncRequest() + + return req + }, + ExpectPortalUpdate0ContainsInOrder: []string{"test1"}, + }, } for _, c := range cases { diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index dee5e38d9..a2b34c7be 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -1182,6 +1182,7 @@ func (b *Builder) configDemoContainer(pb *presets.Builder) (pm *presets.ModelBui return nil }) listing.RowMenu().Empty() + b.firstOrCreateDemoContainers() listing.CellWrapperFunc(func(cell h.MutableAttrHTMLComponent, id string, obj interface{}, dataTableID string) h.HTMLComponent { tdbind := cell c := obj.(*DemoContainer) @@ -1204,6 +1205,18 @@ func (b *Builder) configDemoContainer(pb *presets.Builder) (pm *presets.ModelBui return } +func (b *Builder) firstOrCreateDemoContainers() { + var localeCode string + if b.l10n != nil { + localeCode = "International" + } + for _, con := range b.containerBuilders { + if err := con.firstOrCreate(localeCode); err != nil { + panic(err) + } + } +} + func (b *Builder) defaultTemplateInstall(pb *presets.Builder, pm *presets.ModelBuilder) (err error) { db := b.db @@ -1346,13 +1359,6 @@ func (b *ContainerBuilder) Model(m interface{}) *ContainerBuilder { b.registerEventFuncs() b.uRIName(inflection.Plural(strcase.ToKebab(b.name))) b.warpSaver() - var localeCode string - if b.builder.l10n != nil { - localeCode = "International" - } - if err := b.firstOrCreate(m, localeCode); err != nil { - panic(err) - } return b } @@ -1508,10 +1514,13 @@ func (b *ContainerBuilder) getContainerDataID(id int) string { return fmt.Sprintf(inflection.Plural(strcase.ToKebab(b.name))+"_%v", id) } -func (b *ContainerBuilder) firstOrCreate(obj interface{}, locale string) (err error) { - db := b.builder.db - m := DemoContainer{} - db.Where("model_name = ?", b.name).First(&m) +func (b *ContainerBuilder) firstOrCreate(locale string) (err error) { + var ( + db = b.builder.db + obj = b.mb.NewModel() + m = DemoContainer{} + ) + db.Where("model_name = ? and locale_code = ? ", b.name, locale).First(&m) if m.ID > 0 { return } diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index 554b876af..498edbd8d 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -31,6 +31,8 @@ const ( ShowSortedContainerDrawerEvent = "page_builder_ShowSortedContainerDrawerEvent" ReloadRenderPageOrTemplateEvent = "page_builder_ReloadRenderPageOrTemplateEvent" AutoSaveContainerEvent = "page_builder_AutoSaveContainerEvent" + NewContainerDialogEvent = "page_builder_NewContainerDialogEvent" + ContainerPreviewEvent = "page_builder_ContainerPreviewEvent" paramPageID = "pageID" paramPageVersion = "pageVersion" @@ -63,7 +65,11 @@ const ( EditorTabLayers = "Layers" ) -const editorPreviewContentPortal = "editorPreviewContentPortal" +const ( + editorPreviewContentPortal = "editorPreviewContentPortal" + addContainerDialogPortal = "addContainerDialogPortal" + addContainerDialogContentPortal = "addContainerDialogContentPortal" +) func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { return func(ctx *web.EventContext) (r web.PageResponse, err error) { @@ -131,10 +137,10 @@ func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { Permanent(true). Width(350), VNavigationDrawer( - h.Div(web.Portal(editContainerDrawer).Name(pageBuilderRightContentPortal)).Attr("v-show", fmt.Sprintf(`vars.hasContainer&&vars.containerTab=="%s"`, EditorTabLayers)), + h.Div(web.Portal(editContainerDrawer).Name(pageBuilderRightContentPortal)), ).Location(LocationRight). Permanent(true). - Attr(":width", fmt.Sprintf(`vars.hasContainer&&vars.containerTab=="%s"?350:0`, EditorTabLayers)), + Width(350), ), VMain( vx.VXMessageListener().ListenFunc(b.generateEditorBarJsFunction(ctx)), @@ -182,36 +188,9 @@ type ContainerSorter struct { } func (b *Builder) renderNavigator(ctx *web.EventContext, m *ModelBuilder) (r h.HTMLComponent, err error) { - var listContainers h.HTMLComponent - if listContainers, err = m.renderContainersSortedList(ctx); err != nil { + if r, err = m.renderContainersSortedList(ctx); err != nil { return } - r = h.Components( - web.Slot( - VTabs( - VTab().Text("Layers").Value(EditorTabLayers).Attr("@click", - scrollToContainer(web.Var(fmt.Sprintf(`vars.%s`, paramContainerDataID)))+ - removeVirtualElement()+ - web.Plaid(). - EventFunc(ShowSortedContainerDrawerEvent). - Query(paramStatus, ctx.Param(paramStatus)). - Query(paramContainerDataID, web.Var(fmt.Sprintf(`vars.%s`, paramContainerDataID))). - MergeQuery(true). - Go()), - VTab().Text("Add"). - Value(EditorTabAdd).Attr("@click", - appendVirtualElement()+ - ";"+ - web.Plaid().PushState(true).MergeQuery(true). - ClearMergeQuery([]string{paramContainerID}).RunPushState(), - ), - ).Attr("v-model", "vars.containerTab").FixedTabs(true), - ).Name(VSlotPrepend), - VTabsWindow( - VTabsWindowItem(m.renderContainersList(ctx)).Value(EditorTabAdd), - VTabsWindowItem(web.Portal(listContainers).Name(pageBuilderLayerContainerPortal)).Value(EditorTabLayers), - ).Attr("v-model", "vars.containerTab").Attr(web.VAssign("vars", fmt.Sprintf(`{containerTab:"%s"}`, EditorTabLayers))...), - ) return } @@ -444,6 +423,7 @@ func (b *Builder) pageEditorLayout(in web.PageFunc, config *presets.LayoutConfig web.Portal().Name(presets.DeleteConfirmPortalName), web.Portal().Name(presets.ListingDialogPortalName), web.Portal().Name(dialogPortalName), + web.Portal().Name(addContainerDialogPortal), innerPr.Body.(h.HTMLComponent), ).Attr("id", "vt-app"). Attr(web.VAssign("vars", `{presetsRightDrawer: false, presetsDialog: false, dialogPortalName: false}`)...) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 54f3f08e2..16ae940ed 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -57,6 +57,8 @@ func (b *ModelBuilder) registerFuncs() { b.editor.RegisterEventFunc(RenameContainerEvent, b.renameContainer) b.editor.RegisterEventFunc(ReloadRenderPageOrTemplateEvent, b.reloadRenderPageOrTemplate) b.editor.RegisterEventFunc(MarkAsSharedContainerEvent, b.markAsSharedContainer) + b.editor.RegisterEventFunc(NewContainerDialogEvent, b.newContainerDialog) + b.editor.RegisterEventFunc(ContainerPreviewEvent, b.containerPreview) b.preview = web.Page(b.previewContent) } @@ -202,6 +204,13 @@ func (b *ModelBuilder) renderContainersSortedList(ctx *web.EventContext) (r h.HT ), ).Attr("#item", " { element } "), ), + VListItem( + web.Slot( + VIcon("mdi-plus-circle-outline"), + ).Name(VSlotPrepend), + h.Span("New Element"), + ).BaseColor(ColorPrimary).Class(W100, "ml-4"). + Attr("@click", web.Plaid().EventFunc(NewContainerDialogEvent).Go()), ), ).Class("pa-4 pt-2"), ).Init(h.JSONString(sorterData)).VSlot("{ locals:sortLocals,form }") @@ -450,20 +459,13 @@ func (b *ModelBuilder) renderContainersList(ctx *web.EventContext) (component h. } var listItems []h.HTMLComponent for _, builder := range group { - cover := builder.cover - if cover == "" { - cover = path.Join(b.builder.prefix, b.builder.imagesPrefix, strings.ReplaceAll(builder.name, " ", "")+".svg") - } containerName := i18n.T(ctx.R, presets.ModelsI18nModuleKey, builder.name) listItems = append(listItems, VListItem( VListItemTitle(h.Text(containerName)), - VListItemSubtitle(VImg().Src(cover).Height(100)).Class("border-xl mt-2"), ).Attr("@click", - web.Plaid().EventFunc(AddContainerEvent). - MergeQuery(true). + web.Plaid().EventFunc(ContainerPreviewEvent). Query(paramModelName, builder.name). - Query(paramContainerName, builder.name). Go(), )) } @@ -472,7 +474,7 @@ func (b *ModelBuilder) renderContainersList(ctx *web.EventContext) (component h. VListItem( VListItemTitle( h.Text(groupName), - ).Class("text-body-1"), + ), ).Attr("v-bind", "props"), ).Name("activator").Scope(" { props}"), h.Components(listItems...), @@ -499,23 +501,17 @@ func (b *ModelBuilder) renderContainersList(ctx *web.EventContext) (component h. var listItems []h.HTMLComponent for _, builder := range group { c := b.builder.ContainerByName(builder.ModelName) - cover := c.cover - if cover == "" { - cover = path.Join(b.builder.prefix, b.builder.imagesPrefix, strings.ReplaceAll(c.name, " ", "")+".svg") - } containerName := i18n.T(ctx.R, presets.ModelsI18nModuleKey, c.name) listItems = append(listItems, VListItem( - VListItemTitle(h.Text(containerName)), - VListItemSubtitle(VImg().Src(cover).Height(100)).Class("border-xl mt-2"). - Attr("@click", web.Plaid(). - EventFunc(AddContainerEvent). - MergeQuery(true). - Query(paramContainerName, builder.ModelName). - Query(paramModelName, builder.ModelName). - Query(paramModelID, builder.ModelID). - Query(paramSharedContainer, "true"). - Go()), + VListItemTitle(h.Text(containerName)).Attr("@click", web.Plaid(). + EventFunc(AddContainerEvent). + MergeQuery(true). + Query(paramContainerName, builder.ModelName). + Query(paramModelName, builder.ModelName). + Query(paramModelID, builder.ModelID). + Query(paramSharedContainer, "true"). + Go()), ).Value(containerName)) } @@ -523,7 +519,7 @@ func (b *ModelBuilder) renderContainersList(ctx *web.EventContext) (component h. web.Slot( VListItem( VListItemTitle(h.Text(groupName)), - ).Attr("v-bind", "props").Class("text-body-1"), + ).Attr("v-bind", "props"), ).Name("activator").Scope(" { props }"), h.Components(listItems...), ).Value(groupName)) @@ -566,7 +562,7 @@ func (b *ModelBuilder) reloadRenderPageOrTemplate(ctx *web.EventContext) (r web. var body h.HTMLComponent obj := b.mb.NewModel() - if body, err = b.renderPageOrTemplate(ctx, obj, true); err != nil { + if body, err = b.renderPageOrTemplate(ctx, obj, true, true); err != nil { return } r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{Name: editorPreviewContentPortal, Body: body}) @@ -713,7 +709,7 @@ func (b *ModelBuilder) addContainerToPage(pageID int, containerID, pageVersion, func (b *ModelBuilder) pageContent(ctx *web.EventContext, obj interface{}) (r web.PageResponse, err error) { var body h.HTMLComponent - if body, err = b.renderPageOrTemplate(ctx, obj, true); err != nil { + if body, err = b.renderPageOrTemplate(ctx, obj, true, true); err != nil { return } r.Body = web.Portal( @@ -738,7 +734,7 @@ func (b *ModelBuilder) getPrimaryColumnValuesBySlug(ctx *web.EventContext) (page return } -func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface{}, isEditor bool) (r h.HTMLComponent, err error) { +func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface{}, isEditor, isIframe bool) (r h.HTMLComponent, err error) { var ( isTpl = ctx.R.FormValue(paramsTpl) != "" status = publish.StatusDraft @@ -775,6 +771,11 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface if err != nil { return } + r = b.rendering(comps, ctx, obj, locale, isEditor, isIframe, isReadonly) + return +} + +func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, obj interface{}, locale string, isEditor, isIframe, isReadonly bool) (r h.HTMLComponent) { r = h.Components(comps...) if b.builder.pageLayoutFunc != nil { var seoTags h.HTMLComponent @@ -903,7 +904,7 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface } } - if isEditor { + if isIframe { iframeHeightCookie, _ := ctx.R.Cookie(iframeHeightName) iframeValue := "1000px" _ = iframeValue @@ -939,8 +940,7 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface "width", width, ":container-data-id", fmt.Sprintf(`vars.containerTab=="%s"?"%s":""`, EditorTabAdd, ctx.Param(paramContainerDataID)), "ref", "scrollIframe"). - Attr(web.VAssign("vars", - fmt.Sprintf(`{hasContainer:%v,el:$}`, len(comps)))...) + Attr(web.VAssign("vars", `{el:$}`)...) r = scrollIframe if !isReadonly && len(comps) == 0 { r = h.Components( @@ -959,7 +959,6 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface ctx.Injector.HeadHTMLComponent("style", b.builder.pageStyle, true) } } - return } @@ -1004,9 +1003,52 @@ func (b *ModelBuilder) renderContainers(ctx *web.EventContext, pageID int, pageV return } +func (b *ModelBuilder) renderPreviewContainer(ctx *web.EventContext, locale string, isEditor, IsReadonly bool) (r h.HTMLComponent, err error) { + var ( + modelName = ctx.Param(paramModelName) + sharedContainer = ctx.Param(paramSharedContainer) + modelID = ctx.ParamAsInt(paramModelID) + ) + if sharedContainer != "true" || modelID == 0 { + var con *DemoContainer + err = withLocale( + b.builder, + b.db. + Where("model_name = ?", modelName), + locale, + ). + First(&con).Error + if err != nil { + return + } + modelID = int(con.ModelID) + } + + containerBuilder := b.builder.ContainerByName(modelName) + device, _ := b.builder.getDevice(ctx) + + displayName := i18n.T(ctx.R, presets.ModelsI18nModuleKey, modelName) + input := RenderInput{ + IsEditor: isEditor, + IsReadonly: IsReadonly, + Device: device, + ContainerId: "", + DisplayName: displayName, + } + obj := containerBuilder.NewModel() + err = b.db.FirstOrCreate(obj, "id = ?", modelID).Error + if err != nil { + return + } + pure := containerBuilder.renderFunc(obj, &input, ctx) + r = b.builder.containerWrapper(pure.(*h.HTMLTagBuilder), ctx, isEditor, IsReadonly, false, false, + containerBuilder.getContainerDataID(modelID), modelName, &input) + return +} + func (b *ModelBuilder) previewContent(ctx *web.EventContext) (r web.PageResponse, err error) { obj := b.mb.NewModel() - r.Body, err = b.renderPageOrTemplate(ctx, obj, false) + r.Body, err = b.renderPageOrTemplate(ctx, obj, false, false) if err != nil { return } @@ -1257,3 +1299,59 @@ func (b *ModelBuilder) ContextValueProvider(in context.Context) context.Context func (b *ModelBuilder) ExistedL10n() bool { return b.builder.l10n != nil } + +func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventResponse, err error) { + containers := b.renderContainersList(ctx) + r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ + Name: addContainerDialogPortal, + Body: web.Scope( + VDialog( + VSheet( + VCard( + VCardTitle(h.Text("New Element")), + VCardText(containers), + ).Width("40%").Class("pa-4", "overflow-y-auto"), + VCard( + VToolbar( + VSpacer(), + VBtn("").Icon("mdi-close").Variant(VariantText).Attr("@click", "locals.dialog=false"), + ).Class("v-card--variant-tonal"), + VCardText( + web.Portal().Name(addContainerDialogContentPortal), + ).Class("px-6"), + ).Variant(VariantTonal).Width("60%").Class(H100), + ).Class("d-inline-flex"), + ).Width(665).Height(460).Attr("v-model", "locals.dialog"), + ).VSlot(`{locals}`).Init(`{dialog:true}`), + }) + return +} + +func (b *ModelBuilder) containerPreview(ctx *web.EventContext) (r web.EventResponse, err error) { + var previewContainer h.HTMLComponent + var ( + ID, _, locale = b.getPrimaryColumnValuesBySlug(ctx) + obj = b.mb.NewModel() + ) + if err = b.db.First(&obj, ID).Error; err != nil { + return + } + previewContainer, err = b.renderPreviewContainer(ctx, locale, false, true) + if err != nil { + return + } + addContainerEvent := web.Plaid().EventFunc(AddContainerEvent). + Queries(ctx.R.Form). + Go() + iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) + r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ + Name: addContainerDialogContentPortal, + Body: VCard( + VCardText( + h.Div(iframe).Style("pointer-events: none;"), + ).Class("pa-0"), + ).Attr("@click", addContainerEvent). + Elevation(2).Width("100%").Height(326), + }) + return +} From a9313265a0b8892f01390d5222cd893994508973 Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 28 Jun 2024 17:14:07 +0800 Subject: [PATCH 02/15] fix add container --- pagebuilder/builder.go | 19 +++---------------- pagebuilder/editor.go | 4 ++-- pagebuilder/model.go | 21 ++++----------------- 3 files changed, 9 insertions(+), 35 deletions(-) diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index a2b34c7be..ad466b31f 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -1575,15 +1575,8 @@ func (b *Builder) ServeHTTP(w http.ResponseWriter, r *http.Request) { b.ps.ServeHTTP(w, r) } -func (b *Builder) generateEditorBarJsFunction(ctx *web.EventContext) string { - editAction := fmt.Sprintf(`vars.%s=container_data_id;vars.containerTab="%s";`, paramContainerDataID, EditorTabLayers) + - removeVirtualElement() + ";" + - web.Plaid(). - EventFunc(ShowSortedContainerDrawerEvent). - Query(paramStatus, ctx.Param(paramStatus)). - Query(paramContainerDataID, web.Var("container_data_id")). - MergeQuery(true). - Go() + ";" + +func (b *Builder) generateEditorBarJsFunction(_ *web.EventContext) string { + editAction := fmt.Sprintf(`vars.%s=container_data_id;`, paramContainerDataID) + web.Plaid(). PushState(true). MergeQuery(true). @@ -1597,13 +1590,7 @@ func (b *Builder) generateEditorBarJsFunction(ctx *web.EventContext) string { Query(presets.ParamOverlay, actions.Content). Query(presets.ParamPortalName, pageBuilderRightContentPortal). Go() - addAction := web.Plaid().ClearMergeQuery([]string{paramContainerID, paramContainerDataID}).RunPushState() + - fmt.Sprintf(`;%s;vars.containerTab="%s";`, addVirtualELeToContainer(web.Var("container_data_id")), EditorTabAdd) + - web.Plaid(). - PushState(true). - MergeQuery(true). - Query(paramContainerID, web.Var("container_id")). - RunPushState() + addAction := web.Plaid().EventFunc(NewContainerDialogEvent).Query(paramContainerID, web.Var("container_id")).Go() deleteAction := web.POST(). EventFunc(DeleteContainerConfirmationEvent). Query(paramContainerID, web.Var("container_id")). diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index 498edbd8d..e5edc1569 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -132,12 +132,12 @@ func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { ).Elevation(0).Density(DensityCompact).Height(96).Class("align-center border-b"), h.If(readonly, VNavigationDrawer( - navigatorDrawer, + web.Portal(navigatorDrawer).Name(pageBuilderLayerContainerPortal), ).Location(LocationLeft). Permanent(true). Width(350), VNavigationDrawer( - h.Div(web.Portal(editContainerDrawer).Name(pageBuilderRightContentPortal)), + web.Portal(editContainerDrawer).Name(pageBuilderRightContentPortal), ).Location(LocationRight). Permanent(true). Width(350), diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 16ae940ed..443985f18 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -236,24 +236,10 @@ func (b *ModelBuilder) addContainer(ctx *web.EventContext) (r web.EventResponse, modelID = int(newModelId) } cb := b.builder.ContainerByName(modelName) - r.RunScript = fmt.Sprintf(`vars.%s="%s";`, paramContainerDataID, cb.getContainerDataID(modelID)) + - web.Plaid().PushState(true).MergeQuery(true). - Query(paramContainerDataID, cb.getContainerDataID(modelID)). - Query(paramContainerID, newContainerID).RunPushState() + - ";" + web.Plaid(). - EventFunc(ReloadRenderPageOrTemplateEvent). - MergeQuery(true). - Query(paramContainerDataID, cb.getContainerDataID(modelID)). - Query(paramContainerID, newContainerID). - Go() + ";" + - web.Plaid(). - URL(fmt.Sprintf(`%s/%s`, b.builder.prefix, inflection.Plural(strcase.ToKebab(cb.name)))). - EventFunc(actions.Edit). - Query(presets.ParamPortalName, pageBuilderRightContentPortal). - Query(presets.ParamOverlay, actions.Content). - Query(presets.ParamID, modelID). - Go() + r.RunScript = web.Plaid().PushState(true).MergeQuery(true). + Query(paramContainerDataID, cb.getContainerDataID(modelID)). + Query(paramContainerID, newContainerID).Go() return } @@ -1341,6 +1327,7 @@ func (b *ModelBuilder) containerPreview(ctx *web.EventContext) (r web.EventRespo return } addContainerEvent := web.Plaid().EventFunc(AddContainerEvent). + MergeQuery(true). Queries(ctx.R.Form). Go() iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) From 7128ab04bb3d00558b5497941bd7f8886bbab00c Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 28 Jun 2024 17:42:40 +0800 Subject: [PATCH 03/15] add wrap func --- pagebuilder/editor.go | 12 ---- pagebuilder/model.go | 134 ++++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 77 deletions(-) diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index e5edc1569..18b860254 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -435,18 +435,6 @@ func scrollToContainer(containerDataID interface{}) string { return fmt.Sprintf(`vars.el.refs.scrollIframe.scrollToCurrentContainer(%v);`, containerDataID) } -func addVirtualELeToContainer(containerDataID interface{}) string { - return fmt.Sprintf(`vars.el.refs.scrollIframe.addVirtualElement(%v);`, containerDataID) -} - -func removeVirtualElement() string { - return fmt.Sprintf(`vars.el.refs.scrollIframe.removeVirtualElement();`) -} - -func appendVirtualElement() string { - return fmt.Sprintf(`vars.el.refs.scrollIframe.appendVirtualElement();`) -} - func (b *Builder) containerWrapper(r *h.HTMLTagBuilder, ctx *web.EventContext, isEditor, isReadonly, isFirst, isEnd bool, containerDataID, modelName string, input *RenderInput) h.HTMLComponent { pmb := postMessageBody{ ContainerDataID: containerDataID, diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 443985f18..6ffdb8c44 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -15,7 +15,6 @@ import ( "strings" "github.com/qor5/admin/v3/presets/gorm2op" - "github.com/sunfmin/reflectutils" "github.com/qor5/admin/v3/utils" @@ -1183,86 +1182,91 @@ func (b *ModelBuilder) localizeContainersToAnotherPage(db *gorm.DB, pageID int, func (b *ModelBuilder) configDuplicate(mb *presets.ModelBuilder) { eb := mb.Editing() - eb.SaveFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) { - if p, ok := obj.(*Page); ok { - if p.Slug != "" { - p.Slug = path.Clean(p.Slug) + eb.WrapSaveFunc(func(in presets.SaveFunc) presets.SaveFunc { + return func(obj interface{}, id string, ctx *web.EventContext) (err error) { + if err = in(obj, id, ctx); err != nil { + return } - funcName := ctx.R.FormValue(web.EventFuncIDName) - if funcName == publish.EventDuplicateVersion { - var fromPage Page - eb.Fetcher(&fromPage, ctx.Param(presets.ParamID), ctx) - p.SEO = fromPage.SEO + if p, ok := obj.(*Page); ok { + if p.Slug != "" { + p.Slug = path.Clean(p.Slug) + } + funcName := ctx.R.FormValue(web.EventFuncIDName) + if funcName == publish.EventDuplicateVersion { + var fromPage Page + eb.Fetcher(&fromPage, ctx.Param(presets.ParamID), ctx) + p.SEO = fromPage.SEO + } } - } - var ( - pageID int - version, localeCode, parentVersion string - ) - if id != "" { - ctx.R.Form.Set(presets.ParamID, id) - pageID, _, _ = b.getPrimaryColumnValuesBySlug(ctx) - } - locale, _ := l10n.IsLocalizableFromContext(ctx.R.Context()) - - if p, ok := obj.(publish.VersionInterface); ok { - parentVersion = p.EmbedVersion().ParentVersion - version = p.EmbedVersion().Version - } - if p, ok := obj.(l10n.LocaleInterface); ok { - if p.EmbedLocale().LocaleCode == "" { - reflectutils.Set(obj, "LocaleCode", locale) + var ( + pageID int + version, localeCode, parentVersion string + ) + if id != "" { + ctx.R.Form.Set(presets.ParamID, id) + pageID, _, _ = b.getPrimaryColumnValuesBySlug(ctx) } - localeCode = p.EmbedLocale().LocaleCode - } - err = b.db.Transaction(func(tx *gorm.DB) (inerr error) { - if inerr = gorm2op.DataOperator(tx).Save(obj, id, ctx); inerr != nil { - return + locale, _ := l10n.IsLocalizableFromContext(ctx.R.Context()) + + if p, ok := obj.(publish.VersionInterface); ok { + parentVersion = p.EmbedVersion().ParentVersion + version = p.EmbedVersion().Version } - if strings.Contains(ctx.R.RequestURI, publish.EventDuplicateVersion) { - if inerr = b.copyContainersToNewPageVersion(tx, pageID, localeCode, parentVersion, version); inerr != nil { - return + if p, ok := obj.(l10n.LocaleInterface); ok { + if p.EmbedLocale().LocaleCode == "" { + reflectutils.Set(obj, "LocaleCode", locale) } - return + localeCode = p.EmbedLocale().LocaleCode } - - if v := ctx.R.FormValue(templateSelectedID); v != "" { - var tplID int - tplID, inerr = strconv.Atoi(v) - if inerr != nil { + err = b.db.Transaction(func(tx *gorm.DB) (inerr error) { + if inerr = gorm2op.DataOperator(tx).Save(obj, id, ctx); inerr != nil { return } - if b.builder.l10n == nil { - localeCode = "" - } - if inerr = b.copyContainersToAnotherPage(tx, tplID, templateVersion, localeCode, pageID, version, localeCode); inerr != nil { - panic(inerr) - } - } - if b.builder.l10n != nil && strings.Contains(ctx.R.RequestURI, l10n.DoLocalize) { - fromID := ctx.R.Context().Value(l10n.FromID).(string) - fromVersion := ctx.R.Context().Value(l10n.FromVersion).(string) - fromLocale := ctx.R.Context().Value(l10n.FromLocale).(string) - - var fromIDInt int - fromIDInt, err = strconv.Atoi(fromID) - if err != nil { + if strings.Contains(ctx.R.RequestURI, publish.EventDuplicateVersion) { + if inerr = b.copyContainersToNewPageVersion(tx, pageID, localeCode, parentVersion, version); inerr != nil { + return + } return } - if p, ok := obj.(*Page); ok { - if inerr = b.builder.localizeCategory(tx, p.CategoryID, fromLocale, locale); inerr != nil { + + if v := ctx.R.FormValue(templateSelectedID); v != "" { + var tplID int + tplID, inerr = strconv.Atoi(v) + if inerr != nil { + return + } + if b.builder.l10n == nil { + localeCode = "" + } + if inerr = b.copyContainersToAnotherPage(tx, tplID, templateVersion, localeCode, pageID, version, localeCode); inerr != nil { panic(inerr) } } - if inerr = b.localizeContainersToAnotherPage(tx, fromIDInt, fromVersion, fromLocale, pageID, version, localeCode); inerr != nil { - panic(inerr) + if b.builder.l10n != nil && strings.Contains(ctx.R.RequestURI, l10n.DoLocalize) { + fromID := ctx.R.Context().Value(l10n.FromID).(string) + fromVersion := ctx.R.Context().Value(l10n.FromVersion).(string) + fromLocale := ctx.R.Context().Value(l10n.FromLocale).(string) + + var fromIDInt int + fromIDInt, err = strconv.Atoi(fromID) + if err != nil { + return + } + if p, ok := obj.(*Page); ok { + if inerr = b.builder.localizeCategory(tx, p.CategoryID, fromLocale, locale); inerr != nil { + panic(inerr) + } + } + if inerr = b.localizeContainersToAnotherPage(tx, fromIDInt, fromVersion, fromLocale, pageID, version, localeCode); inerr != nil { + panic(inerr) + } + return } return - } - return - }) + }) - return err + return err + } }) } From 9d23561a0b728d6444b303910fa91347e6ccfcc6 Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 28 Jun 2024 17:50:20 +0800 Subject: [PATCH 04/15] fix visibility --- pagebuilder/model.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 6ffdb8c44..96049e56f 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -193,7 +193,7 @@ func (b *ModelBuilder) renderContainersSortedList(ctx *web.EventContext) (r h.HT ), ).Name("append"), ).Attr(":variant", fmt.Sprintf(` element.hidden &&!isHovering && !element.editShow?"%s":"%s"`, VariantPlain, VariantText)). - Attr(":class", fmt.Sprintf(`element.container_data_id==vars.%s?"bg-%s":""`, paramContainerDataID, ColorPrimaryLighten2)). + Attr(":class", fmt.Sprintf(`element.container_data_id==vars.%s && !element.hidden?"bg-%s":""`, paramContainerDataID, ColorPrimaryLighten2)). Attr("v-bind", "props", "@click", clickColumnEvent). Attr(web.VAssign("vars", fmt.Sprintf(`{%s:"%s"}`, paramContainerDataID, ctx.Param(paramContainerDataID)))...), @@ -318,6 +318,7 @@ func (b *ModelBuilder) toggleContainerVisibility(ctx *web.EventContext) (r web.E ";" + web.Plaid(). EventFunc(ShowSortedContainerDrawerEvent). + MergeQuery(true). Query(paramStatus, ctx.Param(paramStatus)). Go() return From d87f0f50d89b7945c92461061ed0bb8e1596fb72 Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 28 Jun 2024 19:02:36 +0800 Subject: [PATCH 05/15] fix some test;set locale error --- .../admin/integration_test.go | 15 +- .../page_builder_with_campaign_test.go | 23 +- example/integration/pagebuilder_test.go | 2 +- pagebuilder/example/integration_test.go | 264 ------------------ pagebuilder/model.go | 29 +- 5 files changed, 48 insertions(+), 285 deletions(-) delete mode 100644 pagebuilder/example/integration_test.go diff --git a/cmd/qor5/website-template/admin/integration_test.go b/cmd/qor5/website-template/admin/integration_test.go index a9808ba29..390ca726c 100644 --- a/cmd/qor5/website-template/admin/integration_test.go +++ b/cmd/qor5/website-template/admin/integration_test.go @@ -6,6 +6,8 @@ import ( "net/http/httptest" "testing" + "github.com/qor5/admin/v3/pagebuilder" + "github.com/qor5/admin/v3/cmd/qor5/website-template/admin" "github.com/qor5/web/v3/multipartestutils" "github.com/theplant/gofixtures" @@ -63,7 +65,18 @@ func TestAll(t *testing.T) { BuildEventFuncRequest() return req }, - ExpectRunScriptContainsInOrder: []string{"page_builder_ReloadRenderPageOrTemplateEvent"}, + EventResponseMatch: func(t *testing.T, er *multipartestutils.TestEventResponse) { + var container pagebuilder.Container + if err := TestDB.First(&container).Error; err != nil { + t.Error("containers not add", er) + } + if container.ModelName != "MyHeader" { + t.Error("containers not add", container.ModelName) + } + if container.PageModelName != "pages" { + t.Error("containers not add for page model name", container.PageModelName) + } + }, }, { Name: "add menu items to header", diff --git a/docs/docsrc/examples/examples_admin/page_builder_with_campaign_test.go b/docs/docsrc/examples/examples_admin/page_builder_with_campaign_test.go index bef26028c..126442747 100644 --- a/docs/docsrc/examples/examples_admin/page_builder_with_campaign_test.go +++ b/docs/docsrc/examples/examples_admin/page_builder_with_campaign_test.go @@ -25,6 +25,17 @@ INSERT INTO public.my_contents (id,text) values (1,'my-contents'); INSERT INTO public.campaign_contents (id,title,banner) values (1,'campaign-contents','banner'); INSERT INTO public.product_contents (id,name) values (1,'demo-product-contents'); INSERT INTO public.page_builder_containers (id, created_at, updated_at, deleted_at, page_id, page_version, page_model_name, model_name, model_id, display_order, shared, hidden, display_name, locale_code, localize_from_model_id) VALUES (1, '2024-06-05 07:20:58.435363 +00:00', '2024-06-05 07:20:58.435363 +00:00', null, 1, '2024-05-20-v01', 'campaigns', 'MyContent', 1, 1, false, false, 'MyContent', '', 0); + +`, []string{"campaigns", "campaign_products", "my_contents", "campaign_contents", "product_contents", "page_builder_containers"})) + +var pageBuilderDemoData = gofixtures.Data(gofixtures.Sql(` +INSERT INTO public.campaigns (id, created_at, updated_at, deleted_at, title, status, online_url, scheduled_start_at, scheduled_end_at, actual_start_at, actual_end_at, version, version_name, parent_version) VALUES (1, '2024-05-19 22:11:53.645941 +00:00', '2024-05-19 22:11:53.645941 +00:00', null, 'Hello Campaign', 'draft', '', null, null, null, null, '2024-05-20-v01', '2024-05-20-v01',''); +INSERT INTO public.campaigns (id, created_at, updated_at, deleted_at, title, status, online_url, scheduled_start_at, scheduled_end_at, actual_start_at, actual_end_at, version, version_name, parent_version) VALUES (2, '2024-05-19 22:11:53.645941 +00:00', '2024-05-19 22:11:53.645941 +00:00', null, 'UnPublish Campaign', 'online', 'campaigns/2/index.html', null, null, null, null, '2024-05-20-v01', '2024-05-20-v01',''); +INSERT INTO public.campaign_products (id, created_at, updated_at, deleted_at, name, status, online_url, scheduled_start_at, scheduled_end_at, actual_start_at, actual_end_at, version, version_name, parent_version) VALUES (1, '2024-05-19 22:11:53.645941 +00:00', '2024-05-19 22:11:53.645941 +00:00', null, 'Hello Product', 'draft', '', null, null, null, null, '2024-05-20-v01', '2024-05-20-v01',''); +INSERT INTO public.my_contents (id,text) values (1,'my-contents'); +INSERT INTO public.campaign_contents (id,title,banner) values (1,'campaign-contents','banner'); +INSERT INTO public.product_contents (id,name) values (1,'demo-product-contents'); +INSERT INTO public.page_builder_containers (id, created_at, updated_at, deleted_at, page_id, page_version, page_model_name, model_name, model_id, display_order, shared, hidden, display_name, locale_code, localize_from_model_id) VALUES (1, '2024-06-05 07:20:58.435363 +00:00', '2024-06-05 07:20:58.435363 +00:00', null, 1, '2024-05-20-v01', 'campaigns', 'MyContent', 1, 1, false, false, 'MyContent', '', 0); INSERT INTO page_builder_demo_containers (id, created_at, updated_at, deleted_at, model_name, model_id, locale_code) VALUES (1, '2024-06-25 02:21:41.014915 +00:00', '2024-06-25 02:21:41.014915 +00:00', null, 'ProductContent', 1, ''); `, []string{"campaigns", "campaign_products", "my_contents", "campaign_contents", "product_contents", "page_builder_containers", "page_builder_demo_containers"})) @@ -97,14 +108,14 @@ func TestPageBuilderCampaign(t *testing.T) { ExpectPageBodyContainsInOrder: []string{"publish_EventPublish", "iframe", "ProductDetail"}, }, { - Name: "Campaign editor", + Name: "Campaign editor NewContainerDialog", Debug: true, ReqFunc: func() *http.Request { pageBuilderData.TruncatePut(dbr) - return httptest.NewRequest("GET", "/page_builder/campaigns-editors/1_2024-05-20-v01", nil) + return httptest.NewRequest("GET", "/page_builder/campaigns-editors/1_2024-05-20-v01?__execute_event__=page_builder_NewContainerDialogEvent", nil) }, - ExpectPageBodyContainsInOrder: []string{"MyContent", "CampaignContent"}, - ExpectPageBodyNotContains: []string{"ProductContent"}, + ExpectPortalUpdate0ContainsInOrder: []string{"MyContent", "CampaignContent"}, + ExpectPortalUpdate0NotContains: []string{"ProductContent"}, }, { Name: "Campaign My Contents", @@ -362,7 +373,7 @@ func TestPageBuilderCampaign(t *testing.T) { Name: "CampaignProduct Add New Demo Container", Debug: true, ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) + pageBuilderDemoData.TruncatePut(dbr) req := NewMultipartBuilder(). PageURL("/page_builder/campaign-products-editors/1_2024-05-20-v01"). EventFunc(pagebuilder.AddContainerEvent). @@ -399,7 +410,7 @@ func TestPageBuilderCampaign(t *testing.T) { Name: "Edit Demo Container", Debug: true, ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) + pageBuilderDemoData.TruncatePut(dbr) return NewMultipartBuilder(). PageURL("/page_builder/product-contents?__execute_event__=presets_Update&id=1"). AddField("Name", "demo-product-contents2"). diff --git a/example/integration/pagebuilder_test.go b/example/integration/pagebuilder_test.go index f47acdd91..66ffa7bd3 100644 --- a/example/integration/pagebuilder_test.go +++ b/example/integration/pagebuilder_test.go @@ -125,7 +125,7 @@ func TestPageBuilder(t *testing.T) { var page pagebuilder.Page TestDB.First(&page, "slug = ?", "/hello4") if page.LocaleCode != "International" { - t.Errorf("wrong locale code, expected International, got %#+v", page) + t.Errorf("wrong locale code, expected International, got %#+v", page.LocaleCode) } }, }, diff --git a/pagebuilder/example/integration_test.go b/pagebuilder/example/integration_test.go deleted file mode 100644 index 2d0bbab9b..000000000 --- a/pagebuilder/example/integration_test.go +++ /dev/null @@ -1,264 +0,0 @@ -package example_test - -import ( - "fmt" - "net/http" - "net/http/httptest" - "strings" - "testing" - - "github.com/qor5/admin/v3/activity" - "github.com/qor5/admin/v3/media/oss" - "github.com/qor5/admin/v3/pagebuilder" - "github.com/qor5/admin/v3/pagebuilder/example" - "github.com/qor5/admin/v3/presets" - "github.com/qor5/admin/v3/presets/actions" - "github.com/qor5/admin/v3/presets/gorm2op" - "github.com/qor5/admin/v3/publish" - "github.com/qor5/admin/v3/seo" - "github.com/qor5/web/v3/multipartestutils" - "github.com/qor5/x/v3/login" - "github.com/qor5/x/v3/perm" - "github.com/theplant/gofixtures" - "github.com/theplant/testenv" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -var TestDB *gorm.DB - -func TestMain(m *testing.M) { - env, err := testenv.New().DBEnable(true).SetUp() - if err != nil { - panic(err) - } - defer env.TearDown() - TestDB = env.DB - TestDB.Logger = TestDB.Logger.LogMode(logger.Info) - m.Run() -} - -var pageBuilderData = gofixtures.Data( - gofixtures.Sql(` -INSERT INTO page_builder_pages (id, version, locale_code, title, slug) VALUES (1, 'v1','International', '123', '123'); -INSERT INTO container_headers (id, color) VALUES (1, 'black'); -INSERT INTO page_builder_containers (id, page_id, page_model_name, page_version, locale_code, model_name, model_id, -display_order) VALUES (1, 1, 'pages', 'v1','International', 'Header', 1, 1),(2, 1, 'pages', 'v1','International', -'Header', 1, -2); -`, []string{"page_builder_pages", "page_builder_containers", "container_headers"}), -) - -func initPageBuilder() (*gorm.DB, *pagebuilder.Builder, *presets.Builder) { - db := TestDB - b := presets.New().DataOperator(gorm2op.DataOperator(db)).URIPrefix("/admin") - b.Permission( - perm.New().Policies( - perm.PolicyFor(perm.Anybody).WhoAre(perm.Allowed).ToDo(perm.Anything).On(perm.Anything), - ), - ) - pb := example.ConfigPageBuilder(db, "/page_builder", "", b.GetI18n()) - ab := activity.New(db).CreatorContextKey(login.UserKey).TabHeading( - func(log activity.ActivityLogInterface) string { - return fmt.Sprintf("%s %s at %s", log.GetCreator(), strings.ToLower(log.GetAction()), log.GetCreatedAt().Format("2006-01-02 15:04:05")) - }) - publisher := publish.New(db, oss.Storage) - pb.Publisher(publisher).SEO(seo.New(db, seo.WithLocales("International"))).Activity(ab) - b.Use(pb) - - return db, pb, b -} - -func TestPages(t *testing.T) { - db, _, p := initPageBuilder() - dbr, _ := db.DB() - cases := []multipartestutils.TestCase{ - { - Name: "Update page", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/admin/pages"). - EventFunc(actions.Update). - Query(presets.ParamID, "1_v1_International"). - AddField("Title", "Hello Page"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{"success"}, - }, - } - - for _, c := range cases { - t.Run(c.Name, func(t *testing.T) { - multipartestutils.RunCase(t, c, p) - }) - } -} - -func TestPageBuilder(t *testing.T) { - db, pb, _ := initPageBuilder() - dbr, _ := db.DB() - - cases := []multipartestutils.TestCase{ - { - Name: "Show Editor", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return httptest.NewRequest("GET", "/page_builder/pages-editors/1_v1_International", nil) - }, - ExpectPageBodyContainsInOrder: []string{"Header"}, - }, - { - Name: "Add Container", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.AddContainerEvent). - AddField("containerName", "Header"). - AddField("modelName", "Header"). - AddField("id", "1"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{"page_builder_ReloadRenderPageOrTemplateEvent", "pageBuilderRightContentPortal", "overlay", "content"}, - }, - { - Name: "Delete Container Confirmation Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.DeleteContainerConfirmationEvent). - AddField("containerID", "1_International"). - BuildEventFuncRequest() - }, - ExpectPortalUpdate0ContainsInOrder: []string{presets.DeleteConfirmPortalName}, - }, - { - Name: "Editor Delete Container Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.DeleteContainerEvent). - AddField("containerID", "1_International"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{"pushState(true)", "clearMergeQuery"}, - }, - { - Name: "Editor Move Down Container Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.MoveUpDownContainerEvent). - AddField("containerID", "1_International"). - AddField("moveDirection", "down"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{pagebuilder.ReloadRenderPageOrTemplateEvent}, - }, - { - Name: "Editor Move Up Container Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.MoveUpDownContainerEvent). - AddField("containerID", "1_International"). - AddField("moveDirection", "up"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{pagebuilder.ReloadRenderPageOrTemplateEvent}, - }, - { - Name: "Editor Reload Render Page Or Template Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.ReloadRenderPageOrTemplateEvent). - BuildEventFuncRequest() - }, - ExpectPortalUpdate0ContainsInOrder: []string{"vx-scroll-iframe"}, - }, - { - Name: "Editor Rename Container Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.RenameContainerEvent). - AddField("containerID", "1_International"). - AddField("DisplayName", "Header0000001"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{pagebuilder.ShowSortedContainerDrawerEvent, pagebuilder.ReloadRenderPageOrTemplateEvent}, - EventResponseMatch: func(t *testing.T, er *multipartestutils.TestEventResponse) { - var pc pagebuilder.Container - db.Find(&pc, 1) - if pc.DisplayName != "Header0000001" { - t.Error("Expected Header0000001 got ", pc.DisplayName) - } - }, - }, - { - Name: "Editor Show Sorted Container Drawer Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.ShowSortedContainerDrawerEvent). - AddField("status", "draft"). - BuildEventFuncRequest() - }, - ExpectPortalUpdate0ContainsInOrder: []string{`"Header"`}, - }, - { - Name: "Editor Move Container Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.MoveContainerEvent). - AddField("moveResult", `[{"container_id":"2","locale":"International"},{"container_id":"1","locale":"International"}]`). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{"/page_builder/pages-editors/1_v1_International"}, - }, - { - Name: "Editor Toggle Container Visibility Event", - Debug: true, - ReqFunc: func() *http.Request { - pageBuilderData.TruncatePut(dbr) - return multipartestutils.NewMultipartBuilder(). - PageURL("/page_builder/pages-editors/1_v1_International"). - EventFunc(pagebuilder.ToggleContainerVisibilityEvent). - AddField("containerID", "1_International"). - BuildEventFuncRequest() - }, - ExpectRunScriptContainsInOrder: []string{ - pagebuilder.ReloadRenderPageOrTemplateEvent, - pagebuilder.ShowSortedContainerDrawerEvent, - }, - }, - } - - for _, c := range cases { - t.Run(c.Name, func(t *testing.T) { - multipartestutils.RunCase(t, c, pb) - }) - } -} diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 96049e56f..2ae2bd2e0 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -14,7 +14,6 @@ import ( "strconv" "strings" - "github.com/qor5/admin/v3/presets/gorm2op" "github.com/sunfmin/reflectutils" "github.com/qor5/admin/v3/utils" @@ -1185,6 +1184,16 @@ func (b *ModelBuilder) configDuplicate(mb *presets.ModelBuilder) { eb := mb.Editing() eb.WrapSaveFunc(func(in presets.SaveFunc) presets.SaveFunc { return func(obj interface{}, id string, ctx *web.EventContext) (err error) { + locale, _ := l10n.IsLocalizableFromContext(ctx.R.Context()) + var localeCode string + if p, ok := obj.(l10n.LocaleInterface); ok { + if p.EmbedLocale().LocaleCode == "" { + if err = reflectutils.Set(obj, "LocaleCode", locale); err != nil { + return + } + } + localeCode = p.EmbedLocale().LocaleCode + } if err = in(obj, id, ctx); err != nil { return } @@ -1200,29 +1209,23 @@ func (b *ModelBuilder) configDuplicate(mb *presets.ModelBuilder) { } } var ( - pageID int - version, localeCode, parentVersion string + pageID int + version, parentVersion string ) + if p, ok := obj.(PrimarySlugInterface); ok { + id = p.PrimarySlug() + } if id != "" { ctx.R.Form.Set(presets.ParamID, id) pageID, _, _ = b.getPrimaryColumnValuesBySlug(ctx) } - locale, _ := l10n.IsLocalizableFromContext(ctx.R.Context()) if p, ok := obj.(publish.VersionInterface); ok { parentVersion = p.EmbedVersion().ParentVersion version = p.EmbedVersion().Version } - if p, ok := obj.(l10n.LocaleInterface); ok { - if p.EmbedLocale().LocaleCode == "" { - reflectutils.Set(obj, "LocaleCode", locale) - } - localeCode = p.EmbedLocale().LocaleCode - } + err = b.db.Transaction(func(tx *gorm.DB) (inerr error) { - if inerr = gorm2op.DataOperator(tx).Save(obj, id, ctx); inerr != nil { - return - } if strings.Contains(ctx.R.RequestURI, publish.EventDuplicateVersion) { if inerr = b.copyContainersToNewPageVersion(tx, pageID, localeCode, parentVersion, version); inerr != nil { return From 946eb8c4b1498c5ec469e00279980fffd2d8643f Mon Sep 17 00:00:00 2001 From: wen Date: Mon, 1 Jul 2024 11:16:16 +0800 Subject: [PATCH 06/15] fix duplicate --- example/integration/pagebuilder_test.go | 37 ++++++++++++++++++++++++- pagebuilder/builder.go | 23 ++++++++++++++- pagebuilder/model.go | 13 ++++----- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/example/integration/pagebuilder_test.go b/example/integration/pagebuilder_test.go index 66ffa7bd3..8551979dc 100644 --- a/example/integration/pagebuilder_test.go +++ b/example/integration/pagebuilder_test.go @@ -129,10 +129,40 @@ func TestPageBuilder(t *testing.T) { } }, }, - { Name: "Page Builder Editor Duplicate A Page", Debug: true, + ReqFunc: func() *http.Request { + pageBuilderContainerTestData.TruncatePut(dbr) + req := NewMultipartBuilder(). + PageURL("/page_builder/pages-editors/10_2024-05-21-v01_International?__execute_event__=publish_EventDuplicateVersion"). + BuildEventFuncRequest() + + return req + }, + EventResponseMatch: func(t *testing.T, er *TestEventResponse) { + var pages []*pagebuilder.Page + TestDB.Order("id DESC, version DESC").Find(&pages) + if len(pages) != 2 { + t.Fatalf("Page not duplicated %v", pages) + return + } + if pages[0].Slug != pages[1].Slug { + t.Fatalf("Page not duplicated %v", pages) + return + } + var containers []*pagebuilder.Container + TestDB.Find(&containers, "page_id = ? AND page_version = ?", pages[0].ID, + pages[0].Version.Version) + if len(containers) == 0 { + t.Error("Container not duplicated", containers) + } + }, + }, + + { + Name: "Page Builder Detail Duplicate A Page", + Debug: true, ReqFunc: func() *http.Request { pageBuilderContainerTestData.TruncatePut(dbr) req := NewMultipartBuilder(). @@ -146,6 +176,11 @@ func TestPageBuilder(t *testing.T) { TestDB.Order("id DESC, version DESC").Find(&pages) if len(pages) != 2 { t.Fatal("Page not duplicated", pages) + return + } + if pages[0].Slug != pages[1].Slug { + t.Fatalf("Page not duplicated %v", pages) + return } var containers []*pagebuilder.Container TestDB.Find(&containers, "page_id = ? AND page_version = ?", pages[0].ID, diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index ad466b31f..77e81021d 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -327,12 +327,33 @@ func (b *Builder) installAsset(pb *presets.Builder) { pb.ExtraAsset("/redactor.css", "text/css", richeditor.CSSComponentsPack()) } +func (b *Builder) configPageSaver(pb *presets.Builder) (mb *presets.ModelBuilder) { + mb = pb.Model(&Page{}) + eb := mb.Editing() + eb.WrapSaveFunc(func(in presets.SaveFunc) presets.SaveFunc { + return func(obj interface{}, id string, ctx *web.EventContext) (err error) { + p := obj.(*Page) + if p.Slug != "" { + p.Slug = path.Clean(p.Slug) + } + funcName := ctx.R.FormValue(web.EventFuncIDName) + if funcName == publish.EventDuplicateVersion { + var fromPage Page + eb.Fetcher(&fromPage, ctx.Param(presets.ParamID), ctx) + p.SEO = fromPage.SEO + } + return in(obj, id, ctx) + } + }) + return +} + func (b *Builder) Install(pb *presets.Builder) (err error) { defer b.ps.Build() b.ps.I18n(pb.GetI18n()) if b.pageEnabled { var r *ModelBuilder - r = b.Model(pb.Model(&Page{})) + r = b.Model(b.configPageSaver(pb)) b.installAsset(pb) b.configEditor(r) b.configTemplateAndPage(pb, r) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 2ae2bd2e0..1007edaf7 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -1194,9 +1194,7 @@ func (b *ModelBuilder) configDuplicate(mb *presets.ModelBuilder) { } localeCode = p.EmbedLocale().LocaleCode } - if err = in(obj, id, ctx); err != nil { - return - } + if p, ok := obj.(*Page); ok { if p.Slug != "" { p.Slug = path.Clean(p.Slug) @@ -1208,23 +1206,22 @@ func (b *ModelBuilder) configDuplicate(mb *presets.ModelBuilder) { p.SEO = fromPage.SEO } } + if err = in(obj, id, ctx); err != nil { + return + } + var ( pageID int version, parentVersion string ) - if p, ok := obj.(PrimarySlugInterface); ok { - id = p.PrimarySlug() - } if id != "" { ctx.R.Form.Set(presets.ParamID, id) pageID, _, _ = b.getPrimaryColumnValuesBySlug(ctx) } - if p, ok := obj.(publish.VersionInterface); ok { parentVersion = p.EmbedVersion().ParentVersion version = p.EmbedVersion().Version } - err = b.db.Transaction(func(tx *gorm.DB) (inerr error) { if strings.Contains(ctx.R.RequestURI, publish.EventDuplicateVersion) { if inerr = b.copyContainersToNewPageVersion(tx, pageID, localeCode, parentVersion, version); inerr != nil { From 872e8450ecc7eed635bfd2ebe4ec600cff0ee117 Mon Sep 17 00:00:00 2001 From: wen Date: Mon, 1 Jul 2024 14:09:05 +0800 Subject: [PATCH 07/15] remove unused const Dialog to Overlay --- pagebuilder/editor.go | 3 --- pagebuilder/model.go | 32 ++++++++++++++++---------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index 18b860254..095dbd24f 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -60,9 +60,6 @@ const ( EventAdd = "add" EventEdit = "edit" iframeHeightName = "_iframeHeight" - - EditorTabAdd = "Add" - EditorTabLayers = "Layers" ) const ( diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 1007edaf7..aebca4c33 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -207,7 +207,7 @@ func (b *ModelBuilder) renderContainersSortedList(ctx *web.EventContext) (r h.HT VIcon("mdi-plus-circle-outline"), ).Name(VSlotPrepend), h.Span("New Element"), - ).BaseColor(ColorPrimary).Class(W100, "ml-4"). + ).BaseColor(ColorPrimary).Class(W100, "ml-4").Class("newContainer"). Attr("@click", web.Plaid().EventFunc(NewContainerDialogEvent).Go()), ), ).Class("pa-4 pt-2"), @@ -761,6 +761,15 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface } func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, obj interface{}, locale string, isEditor, isIframe, isReadonly bool) (r h.HTMLComponent) { + if !isReadonly && len(comps) == 0 { + r = h.Components( + h.Div( + h.RawHTML(defaultContainerEmptyIcon), + h.Div(h.Text("Please add your elements first")), + ).Style("display:flex;justify-content:center;align-items:center;flex-direction:column;height:80vh"), + ) + return + } r = h.Components(comps...) if b.builder.pageLayoutFunc != nil { var seoTags h.HTMLComponent @@ -775,6 +784,7 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, } if isEditor { + input.EditorCss = append(input.EditorCss, h.RawHTML(``)) input.EditorCss = append(input.EditorCss, h.Style(` .wrapper-shadow{ @@ -923,21 +933,10 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, "iframe-height", iframeValue, "iframe-height-name", iframeHeightName, "width", width, - ":container-data-id", fmt.Sprintf(`vars.containerTab=="%s"?"%s":""`, EditorTabAdd, ctx.Param(paramContainerDataID)), + ":container-data-id", ctx.Param(paramContainerDataID), "ref", "scrollIframe"). Attr(web.VAssign("vars", `{el:$}`)...) r = scrollIframe - if !isReadonly && len(comps) == 0 { - r = h.Components( - scrollIframe.Attr("v-show", fmt.Sprintf(`vars.containerTab=="%s"`, EditorTabAdd)), - h.Div( - h.RawHTML(defaultContainerEmptyIcon), - h.Div(h.Text("Please add your elements first")), - ).Style("display:flex;justify-content:center;align-items:center;flex-direction:column;height:80vh"). - Attr("v-show", fmt.Sprintf(`vars.containerTab!="%s"`, EditorTabAdd)), - ) - return - } } else { r = b.builder.pageLayoutFunc(h.Components(comps...), input, ctx) @@ -1296,7 +1295,7 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogPortal, Body: web.Scope( - VDialog( + VOverlay( VSheet( VCard( VCardTitle(h.Text("New Element")), @@ -1311,8 +1310,9 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes web.Portal().Name(addContainerDialogContentPortal), ).Class("px-6"), ).Variant(VariantTonal).Width("60%").Class(H100), - ).Class("d-inline-flex"), - ).Width(665).Height(460).Attr("v-model", "locals.dialog"), + ).Class("d-inline-flex").Width(665).Height(460), + ).Attr("v-model", "locals.dialog").Activator(".newContainer"). + LocationStrategy("connected").Location(LocationBottom), ).VSlot(`{locals}`).Init(`{dialog:true}`), }) return From b7d396ce08a9339ef672940e13ae49bfe5e65fe1 Mon Sep 17 00:00:00 2001 From: wen Date: Tue, 2 Jul 2024 11:14:14 +0800 Subject: [PATCH 08/15] fix Dialog --- pagebuilder/model.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index aebca4c33..2f2ad6c9a 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -14,6 +14,8 @@ import ( "strconv" "strings" + "github.com/qor5/web/v3" + "github.com/sunfmin/reflectutils" "github.com/qor5/admin/v3/utils" @@ -25,7 +27,6 @@ import ( "github.com/qor5/admin/v3/presets/actions" "github.com/qor5/admin/v3/publish" - "github.com/qor5/web/v3" "github.com/qor5/x/v3/i18n" . "github.com/qor5/x/v3/ui/vuetify" h "github.com/theplant/htmlgo" @@ -1295,7 +1296,7 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogPortal, Body: web.Scope( - VOverlay( + VDialog( VSheet( VCard( VCardTitle(h.Text("New Element")), @@ -1309,10 +1310,9 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes VCardText( web.Portal().Name(addContainerDialogContentPortal), ).Class("px-6"), - ).Variant(VariantTonal).Width("60%").Class(H100), - ).Class("d-inline-flex").Width(665).Height(460), - ).Attr("v-model", "locals.dialog").Activator(".newContainer"). - LocationStrategy("connected").Location(LocationBottom), + ).Width("60%").Class(H100), + ).Class("d-inline-flex"), + ).Attr("v-model", "locals.dialog").Width(665).Height(460), ).VSlot(`{locals}`).Init(`{dialog:true}`), }) return From 4caccefa9033059b6bf16351faadc030c5f2b4ac Mon Sep 17 00:00:00 2001 From: wen Date: Wed, 3 Jul 2024 11:30:19 +0800 Subject: [PATCH 09/15] preview iframe;virtual ele --- pagebuilder/builder.go | 2 +- pagebuilder/content.go | 35 ++++++++++++++++ pagebuilder/editor.go | 46 +++++++++++++++++---- pagebuilder/model.go | 91 +++++++++++++++++++++++++++--------------- 4 files changed, 132 insertions(+), 42 deletions(-) diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index 77e81021d..8e31eec3c 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -1611,7 +1611,7 @@ func (b *Builder) generateEditorBarJsFunction(_ *web.EventContext) string { Query(presets.ParamOverlay, actions.Content). Query(presets.ParamPortalName, pageBuilderRightContentPortal). Go() - addAction := web.Plaid().EventFunc(NewContainerDialogEvent).Query(paramContainerID, web.Var("container_id")).Go() + addAction := addVirtualELeToContainer(web.Var("container_data_id")) + web.Plaid().EventFunc(NewContainerDialogEvent).Query(paramContainerID, web.Var("container_id")).Go() deleteAction := web.POST(). EventFunc(DeleteContainerConfirmationEvent). Query(paramContainerID, web.Var("container_id")). diff --git a/pagebuilder/content.go b/pagebuilder/content.go index d2ccc7528..9e1901009 100644 --- a/pagebuilder/content.go +++ b/pagebuilder/content.go @@ -55,3 +55,38 @@ const defaultContainerEmptyIcon = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index 095dbd24f..3c6077fcf 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -54,12 +54,13 @@ const ( DeviceTablet = "tablet" DeviceComputer = "computer" - EventUp = "up" - EventDown = "down" - EventDelete = "delete" - EventAdd = "add" - EventEdit = "edit" - iframeHeightName = "_iframeHeight" + EventUp = "up" + EventDown = "down" + EventDelete = "delete" + EventAdd = "add" + EventEdit = "edit" + iframeHeightName = "_iframeHeight" + iframePreviewHeightName = "_iframePreviewHeight" ) const ( @@ -68,6 +69,23 @@ const ( addContainerDialogContentPortal = "addContainerDialogContentPortal" ) +func (b *Builder) emptyEdit(_ *web.EventContext) h.HTMLComponent { + return VLayout( + VAppBar( + VToolbarTitle("").Children(h.Text("Setting")), + ).Elevation(0), + VSpacer(), + VMain( + VSheet( + VCard( + VCardText( + h.Text("Select an element and change the setting here."), + ), + ).Variant(VariantFlat), + ).Class("pa-2")), + ) +} + func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { return func(ctx *web.EventContext) (r web.PageResponse, err error) { var ( @@ -81,7 +99,6 @@ func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { containerDataID = ctx.R.FormValue(paramContainerDataID) obj = m.mb.NewModel() ) - if containerDataID != "" { arr := strings.Split(containerDataID, "_") if len(arr) >= 2 { @@ -92,7 +109,8 @@ func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { Query(presets.ParamOverlay, actions.Content).Go() editContainerDrawer = web.RunScript(fmt.Sprintf(`function(){%s}`, editEvent)) } - + } else { + editContainerDrawer = b.emptyEdit(ctx) } deviceToggler = b.deviceToggle(ctx) if tabContent, err = m.pageContent(ctx, obj); err != nil { @@ -489,3 +507,15 @@ func (b *postMessageBody) postMessage(msgType string) string { b.MsgType = msgType return fmt.Sprintf(`window.parent.postMessage(%s, '*')`, h.JSONString(b)) } + +func addVirtualELeToContainer(containerDataID interface{}) string { + return fmt.Sprintf(`vars.el.refs.scrollIframe.addVirtualElement(%v);`, containerDataID) +} + +func removeVirtualElement() string { + return fmt.Sprintf(`vars.el.refs.scrollIframe.removeVirtualElement();`) +} + +func appendVirtualElement() string { + return fmt.Sprintf(`vars.el.refs.scrollIframe.appendVirtualElement();`) +} diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 2f2ad6c9a..be2d9add0 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -203,15 +203,16 @@ func (b *ModelBuilder) renderContainersSortedList(ctx *web.EventContext) (r h.HT ), ).Attr("#item", " { element } "), ), - VListItem( - web.Slot( - VIcon("mdi-plus-circle-outline"), - ).Name(VSlotPrepend), - h.Span("New Element"), - ).BaseColor(ColorPrimary).Class(W100, "ml-4").Class("newContainer"). - Attr("@click", web.Plaid().EventFunc(NewContainerDialogEvent).Go()), ), - ).Class("pa-4 pt-2"), + ).Class("px-4 overflow-y-auto").MaxHeight("86vh"), + VBtn("").Children( + web.Slot( + VIcon("mdi-plus-circle-outline"), + ).Name(VSlotPrepend), + h.Span("New Element").Class("ml-5"), + ).BaseColor(ColorPrimary).Variant(VariantText).Class(W100, "pl-14", "justify-start"). + Height(50). + Attr("@click", appendVirtualElement()+web.Plaid().ClearMergeQuery([]string{paramContainerID}).EventFunc(NewContainerDialogEvent).Go()), ).Init(h.JSONString(sorterData)).VSlot("{ locals:sortLocals,form }") return } @@ -446,14 +447,29 @@ func (b *ModelBuilder) renderContainersList(ctx *web.EventContext) (component h. var listItems []h.HTMLComponent for _, builder := range group { containerName := i18n.T(ctx.R, presets.ModelsI18nModuleKey, builder.name) + addContainerEvent := web.Plaid().EventFunc(AddContainerEvent). + Query(paramModelName, builder.name). + Query(paramContainerID, ctx.Param(paramContainerID)). + Go() listItems = append(listItems, - VListItem( - VListItemTitle(h.Text(containerName)), - ).Attr("@click", + VHover( + web.Slot( + VListItem( + VListItemTitle(h.Text(containerName)), + web.Slot(VBtn("Add").Color(ColorPrimary).Size(SizeSmall).Attr("v-if", "isHovering")).Name(VSlotAppend), + ).Attr("v-bind", "props", ":active", "isHovering"). + Class("cursor-pointer"). + Attr("@click", fmt.Sprintf(`isHovering?%s:null`, addContainerEvent)). + ActiveColor(ColorPrimary), + ).Name("default").Scope(`{isHovering, props }`), + ).Attr("@update:model-value", fmt.Sprintf(`(val)=>{if (val){%s} }`, web.Plaid().EventFunc(ContainerPreviewEvent). Query(paramModelName, builder.name). Go(), - )) + ), + ), + ) + } containers = append(containers, VListGroup( web.Slot( @@ -783,9 +799,10 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, IsPreview: !isEditor, SeoTags: seoTags, } + cookieHightName := iframePreviewHeightName if isEditor { - + cookieHightName = iframeHeightName input.EditorCss = append(input.EditorCss, h.RawHTML(``)) input.EditorCss = append(input.EditorCss, h.Style(` .wrapper-shadow{ @@ -901,9 +918,8 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, } if isIframe { - iframeHeightCookie, _ := ctx.R.Cookie(iframeHeightName) + iframeHeightCookie, _ := ctx.R.Cookie(cookieHightName) iframeValue := "1000px" - _ = iframeValue if iframeHeightCookie != nil { iframeValue = iframeHeightCookie.Value } @@ -932,11 +948,13 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, scrollIframe := h.Tag("vx-scroll-iframe").Attr( ":srcdoc", h.JSONString(h.MustString(r, ctx.R.Context())), "iframe-height", iframeValue, - "iframe-height-name", iframeHeightName, + "iframe-height-name", cookieHightName, "width", width, ":container-data-id", ctx.Param(paramContainerDataID), - "ref", "scrollIframe"). - Attr(web.VAssign("vars", `{el:$}`)...) + "ref", "scrollIframe") + if isEditor { + scrollIframe.Attr(web.VAssign("vars", `{el:$}`)...) + } r = scrollIframe } else { @@ -1292,7 +1310,14 @@ func (b *ModelBuilder) ExistedL10n() bool { } func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventResponse, err error) { - containers := b.renderContainersList(ctx) + var ( + containers = b.renderContainersList(ctx) + afterLeaveEvent = removeVirtualElement() + containerDataID = ctx.Param(paramContainerDataID) + ) + if containerDataID != "" { + afterLeaveEvent += scrollToContainer(fmt.Sprintf(`"%s"`, containerDataID)) + } r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogPortal, Body: web.Scope( @@ -1303,16 +1328,18 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes VCardText(containers), ).Width("40%").Class("pa-4", "overflow-y-auto"), VCard( - VToolbar( - VSpacer(), + VCardText( VBtn("").Icon("mdi-close").Variant(VariantText).Attr("@click", "locals.dialog=false"), - ).Class("v-card--variant-tonal"), + ).Class("d-flex justify-end"), VCardText( - web.Portal().Name(addContainerDialogContentPortal), - ).Class("px-6"), - ).Width("60%").Class(H100), + web.Portal(h.RawHTML(previewEmptySvg)).Name(addContainerDialogContentPortal), + ).Class("px-6", "mt-10"), + ).Width("60%"), ).Class("d-inline-flex"), - ).Attr("v-model", "locals.dialog").Width(665).Height(460), + ).Attr("v-model", "locals.dialog"). + ScrollStrategy("none"). + Attr("@after-leave", afterLeaveEvent). + Width(665).Height(460), ).VSlot(`{locals}`).Init(`{dialog:true}`), }) return @@ -1331,19 +1358,17 @@ func (b *ModelBuilder) containerPreview(ctx *web.EventContext) (r web.EventRespo if err != nil { return } - addContainerEvent := web.Plaid().EventFunc(AddContainerEvent). - MergeQuery(true). - Queries(ctx.R.Form). - Go() + iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogContentPortal, Body: VCard( VCardText( - h.Div(iframe).Style("pointer-events: none;"), + h.Div( + h.Div(iframe).Style("pointer-events: none;position: absolute;top: 0;left: 0;width: 100%;height: 100%;"), + ).Style(" position: relative;width: 100%;padding-top: 56.25%;overflow: hidden;"), ).Class("pa-0"), - ).Attr("@click", addContainerEvent). - Elevation(2).Width("100%").Height(326), + ).Elevation(2).Width(W100), }) return } From 90becf856c7d8d2c6605f78e3379f222a78125a9 Mon Sep 17 00:00:00 2001 From: wen Date: Wed, 3 Jul 2024 15:01:17 +0800 Subject: [PATCH 10/15] empty state --- pagebuilder/model.go | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index be2d9add0..23ee77f8d 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -209,7 +209,7 @@ func (b *ModelBuilder) renderContainersSortedList(ctx *web.EventContext) (r h.HT web.Slot( VIcon("mdi-plus-circle-outline"), ).Name(VSlotPrepend), - h.Span("New Element").Class("ml-5"), + h.Span("Add Component").Class("ml-5"), ).BaseColor(ColorPrimary).Variant(VariantText).Class(W100, "pl-14", "justify-start"). Height(50). Attr("@click", appendVirtualElement()+web.Plaid().ClearMergeQuery([]string{paramContainerID}).EventFunc(NewContainerDialogEvent).Go()), @@ -778,15 +778,6 @@ func (b *ModelBuilder) renderPageOrTemplate(ctx *web.EventContext, obj interface } func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, obj interface{}, locale string, isEditor, isIframe, isReadonly bool) (r h.HTMLComponent) { - if !isReadonly && len(comps) == 0 { - r = h.Components( - h.Div( - h.RawHTML(defaultContainerEmptyIcon), - h.Div(h.Text("Please add your elements first")), - ).Style("display:flex;justify-content:center;align-items:center;flex-direction:column;height:80vh"), - ) - return - } r = h.Components(comps...) if b.builder.pageLayoutFunc != nil { var seoTags h.HTMLComponent @@ -954,6 +945,26 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, "ref", "scrollIframe") if isEditor { scrollIframe.Attr(web.VAssign("vars", `{el:$}`)...) + + if !isReadonly && len(comps) == 0 { + r = h.Components( + h.Div( + VCard( + VCardText(h.RawHTML(previewEmptySvg)).Class("d-flex justify-center"), + VCardTitle(h.Text("Start building a page")).Class("d-flex justify-center"), + VCardSubtitle(h.Text("By Browsing and selecting components from the library")).Class("d-flex justify-center"), + VCardActions( + VBtn("Add Component").Color(ColorPrimary).Variant(VariantElevated). + Attr("@click", appendVirtualElement()+web.Plaid().ClearMergeQuery([]string{paramContainerID}).EventFunc(NewContainerDialogEvent).Go()), + ).Class("d-flex justify-center"), + ).Flat(true), + ).Attr("v-show", "vars.emptyIframe"). + Attr(web.VAssign("vars", `{emptyIframe:true}`)...). + Style("display:flex;justify-content:center;align-items:center;flex-direction:column;height:80vh"), + scrollIframe, + ) + return + } } r = scrollIframe @@ -1312,12 +1323,18 @@ func (b *ModelBuilder) ExistedL10n() bool { func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventResponse, err error) { var ( containers = b.renderContainersList(ctx) - afterLeaveEvent = removeVirtualElement() + afterLeaveEvent = removeVirtualElement() + "vars.emptyIframe = true;" containerDataID = ctx.Param(paramContainerDataID) ) if containerDataID != "" { afterLeaveEvent += scrollToContainer(fmt.Sprintf(`"%s"`, containerDataID)) } + emptyContent := VCard( + VCardText(h.RawHTML(previewEmptySvg)).Class("d-flex justify-center"), + VCardTitle(h.Text("Build your pages")).Class("d-flex justify-center"), + VCardSubtitle(h.Text("Place an element from QOR5 library.")).Class("d-flex justify-center"), + ).Flat(true) + r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogPortal, Body: web.Scope( @@ -1332,7 +1349,7 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes VBtn("").Icon("mdi-close").Variant(VariantText).Attr("@click", "locals.dialog=false"), ).Class("d-flex justify-end"), VCardText( - web.Portal(h.RawHTML(previewEmptySvg)).Name(addContainerDialogContentPortal), + web.Portal(emptyContent).Name(addContainerDialogContentPortal), ).Class("px-6", "mt-10"), ).Width("60%"), ).Class("d-inline-flex"), @@ -1342,6 +1359,7 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes Width(665).Height(460), ).VSlot(`{locals}`).Init(`{dialog:true}`), }) + r.RunScript = "vars.emptyIframe = false " return } From 5750e5abb46575a2bd33c79f8534b4fe74803fc0 Mon Sep 17 00:00:00 2001 From: wen Date: Thu, 4 Jul 2024 09:56:37 +0800 Subject: [PATCH 11/15] preview container --- pagebuilder/builder.go | 7 +++++ pagebuilder/model.go | 58 ++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index 8e31eec3c..5a9657a37 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -94,6 +94,7 @@ type Builder struct { templateEnabled bool expendContainers bool pageEnabled bool + previewContainer bool templateInstall presets.ModelInstallFunc pageInstall presets.ModelInstallFunc categoryInstall presets.ModelInstallFunc @@ -126,6 +127,7 @@ func newBuilder(prefix string, db *gorm.DB) *Builder { templateEnabled: true, expendContainers: true, pageEnabled: true, + previewContainer: true, } r.templateInstall = r.defaultTemplateInstall r.categoryInstall = r.defaultCategoryInstall @@ -282,6 +284,11 @@ func (b *Builder) PageEnabled(v bool) (r *Builder) { return b } +func (b *Builder) PreviewContainer(v bool) (r *Builder) { + b.previewContainer = v + return b +} + func (b *Builder) ExpendContainers(v bool) (r *Builder) { b.expendContainers = v return b diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 23ee77f8d..3487afefa 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -1340,18 +1340,25 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes Body: web.Scope( VDialog( VSheet( - VCard( - VCardTitle(h.Text("New Element")), - VCardText(containers), - ).Width("40%").Class("pa-4", "overflow-y-auto"), - VCard( - VCardText( + VSheet( + VCard( + VCardTitle(h.Text("New Element")), + VCardText(containers), + ).Elevation(0), + ).Class(W50).Class("pa-4", "overflow-y-auto"), + VSheet( + h.Div( + VSpacer(), VBtn("").Icon("mdi-close").Variant(VariantText).Attr("@click", "locals.dialog=false"), - ).Class("d-flex justify-end"), - VCardText( - web.Portal(emptyContent).Name(addContainerDialogContentPortal), - ).Class("px-6", "mt-10"), - ).Width("60%"), + ).Class("d-flex justify-end").Style("height:40px"), + VContainer( + VRow( + VCol( + VSheet(web.Portal(emptyContent).Name(addContainerDialogContentPortal)), + ), + ).Align(Center).Justify(Center).Attr("style", "height:420px"), + ).Class(W100), + ).Class(W50), ).Class("d-inline-flex"), ).Attr("v-model", "locals.dialog"). ScrollStrategy("none"). @@ -1372,21 +1379,28 @@ func (b *ModelBuilder) containerPreview(ctx *web.EventContext) (r web.EventRespo if err = b.db.First(&obj, ID).Error; err != nil { return } - previewContainer, err = b.renderPreviewContainer(ctx, locale, false, true) - if err != nil { - return + var body h.HTMLComponent + if !b.builder.previewContainer { + containerBuilder := b.builder.ContainerByName(ctx.Param(paramModelName)) + cover := containerBuilder.cover + if cover == "" { + cover = path.Join(b.builder.prefix, b.builder.imagesPrefix, strings.ReplaceAll(containerBuilder.name, " ", "")+".svg") + } + body = VImg().Src(cover) + } else { + previewContainer, err = b.renderPreviewContainer(ctx, locale, false, true) + if err != nil { + return + } + iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) + body = h.Div(h.Div(iframe). + Style("pointer-events: none;transform-origin: 0 0; transform:scale(0.25);width:400%")).Class(H100) + } - iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{ Name: addContainerDialogContentPortal, - Body: VCard( - VCardText( - h.Div( - h.Div(iframe).Style("pointer-events: none;position: absolute;top: 0;left: 0;width: 100%;height: 100%;"), - ).Style(" position: relative;width: 100%;padding-top: 56.25%;overflow: hidden;"), - ).Class("pa-0"), - ).Elevation(2).Width(W100), + Body: VCard(body).MaxHeight(200).Elevation(0), }) return } From 568d3ecf868a4026db26d8d7db62005356c7ba03 Mon Sep 17 00:00:00 2001 From: wen Date: Thu, 4 Jul 2024 18:06:03 +0800 Subject: [PATCH 12/15] fix message --- pagebuilder/editor.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index 3c6077fcf..d4860bd8a 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -439,6 +439,12 @@ func (b *Builder) pageEditorLayout(in web.PageFunc, config *presets.LayoutConfig web.Portal().Name(presets.ListingDialogPortalName), web.Portal().Name(dialogPortalName), web.Portal().Name(addContainerDialogPortal), + h.Template( + VSnackbar(h.Text("{{vars.presetsMessage.message}}")). + Attr("v-model", "vars.presetsMessage.show"). + Attr(":color", "vars.presetsMessage.color"). + Timeout(1000), + ).Attr("v-if", "vars.presetsMessage"), innerPr.Body.(h.HTMLComponent), ).Attr("id", "vt-app"). Attr(web.VAssign("vars", `{presetsRightDrawer: false, presetsDialog: false, dialogPortalName: false}`)...) From 6e480c0c9af2cd2274793bceeb023e73b0231ecd Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 5 Jul 2024 11:40:43 +0800 Subject: [PATCH 13/15] demo contianer support all localecode; publish support autoschedule --- pagebuilder/builder.go | 87 +++++++++++++++++++++++++++++++----------- publish/builder.go | 11 ++++++ 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index 5a9657a37..ed56ca9d2 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -7,6 +7,7 @@ import ( "net/url" "path" "reflect" + "slices" "sort" "strconv" "strings" @@ -1168,6 +1169,12 @@ func (b *Builder) configSharedContainer(pb *presets.Builder, r *ModelBuilder) { func (b *Builder) configDemoContainer(pb *presets.Builder) (pm *presets.ModelBuilder) { pm = pb.Model(&DemoContainer{}).URIName("demo_containers").Label("Demo Containers") listing := pm.Listing("ModelName").SearchColumns("model_name") + listing.WrapSearchFunc(func(in presets.SearchFunc) presets.SearchFunc { + return func(model interface{}, params *presets.SearchParams, ctx *web.EventContext) (r interface{}, totalCount int, err error) { + b.firstOrCreateDemoContainers(ctx) + return in(model, params, ctx) + } + }) listing.FilterDataFunc(func(ctx *web.EventContext) vx.FilterData { return []*vx.FilterItem{ { @@ -1210,7 +1217,6 @@ func (b *Builder) configDemoContainer(pb *presets.Builder) (pm *presets.ModelBui return nil }) listing.RowMenu().Empty() - b.firstOrCreateDemoContainers() listing.CellWrapperFunc(func(cell h.MutableAttrHTMLComponent, id string, obj interface{}, dataTableID string) h.HTMLComponent { tdbind := cell c := obj.(*DemoContainer) @@ -1233,14 +1239,15 @@ func (b *Builder) configDemoContainer(pb *presets.Builder) (pm *presets.ModelBui return } -func (b *Builder) firstOrCreateDemoContainers() { - var localeCode string +func (b *Builder) firstOrCreateDemoContainers(ctx *web.EventContext) { + locale, _ := l10n.IsLocalizableFromContext(ctx.R.Context()) + localeCodes := []string{locale} if b.l10n != nil { - localeCode = "International" + localeCodes = b.l10n.GetSupportLocaleCodes() } for _, con := range b.containerBuilders { - if err := con.firstOrCreate(localeCode); err != nil { - panic(err) + if err := con.firstOrCreate(slices.Concat(localeCodes)); err != nil { + continue } } } @@ -1542,28 +1549,62 @@ func (b *ContainerBuilder) getContainerDataID(id int) string { return fmt.Sprintf(inflection.Plural(strcase.ToKebab(b.name))+"_%v", id) } -func (b *ContainerBuilder) firstOrCreate(locale string) (err error) { +func (b *ContainerBuilder) firstOrCreate(localeCodes []string) (err error) { var ( - db = b.builder.db - obj = b.mb.NewModel() - m = DemoContainer{} + db = b.builder.db + obj = b.mb.NewModel() + cons []*DemoContainer + m = &DemoContainer{} ) - db.Where("model_name = ? and locale_code = ? ", b.name, locale).First(&m) - if m.ID > 0 { + if len(localeCodes) == 0 { return } - if err = db.Create(obj).Error; err != nil { + return db.Transaction(func(tx *gorm.DB) (vErr error) { + tx.Where("model_name = ? and locale_code in ? ", b.name, localeCodes).Find(&cons) + if len(cons) == 0 { + if vErr = tx.Create(obj).Error; vErr != nil { + return + } + modelID := reflectutils.MustGet(obj, "ID").(uint) + m = &DemoContainer{ + ModelName: b.name, + ModelID: modelID, + Filled: false, + Locale: l10n.Locale{LocaleCode: localeCodes[0]}, + } + if vErr = tx.Create(m).Error; vErr != nil { + return + } + slices.Delete(localeCodes, 0, 1) + + } else { + m = cons[0] + slices.DeleteFunc(localeCodes, func(s string) bool { + for _, con := range cons { + if con.LocaleCode == s { + return true + } + } + return false + }) + } + for _, localeCode := range localeCodes { + if localeCode == "" { + continue + } + if vErr = tx.Create(&DemoContainer{ + Model: gorm.Model{ID: m.ID}, + ModelName: b.name, + ModelID: m.ModelID, + Filled: false, + Locale: l10n.Locale{LocaleCode: localeCode}, + }).Error; vErr != nil { + return + } + } return - } - modelID := reflectutils.MustGet(obj, "ID") - m.Locale.LocaleCode = locale - m.ModelName = b.name - err = db.Model(DemoContainer{}).Create(map[string]interface{}{ - "locale_code": locale, - "model_name": b.name, - "model_id": modelID, - "filled": false, - }).Error + }) + return } diff --git a/publish/builder.go b/publish/builder.go index de3fd20be..8ec98a0ca 100644 --- a/publish/builder.go +++ b/publish/builder.go @@ -29,6 +29,7 @@ type Builder struct { ab *activity.Builder ctxValueProviders []ContextValueFunc afterInstallFuncs []func() + autoSchedule bool } type ContextValueFunc func(ctx context.Context) context.Context @@ -45,6 +46,11 @@ func (b *Builder) Activity(v *activity.Builder) (r *Builder) { return b } +func (b *Builder) AutoSchedule(v bool) (r *Builder) { + b.autoSchedule = v + return b +} + func (b *Builder) AfterInstall(f func()) *Builder { b.afterInstallFuncs = append(b.afterInstallFuncs, f) return b @@ -213,6 +219,11 @@ func makeSetVersionSetterFunc(db *gorm.DB) func(presets.SetterFunc) presets.Sett } func (b *Builder) Install(pb *presets.Builder) error { + if b.autoSchedule { + defer func() { + go RunPublisher(b.db, b.storage, b) + }() + } pb.FieldDefaults(presets.LIST). FieldType(Status{}). ComponentFunc(StatusListFunc()) From 71210e0107a2e052b045b712e3be968d262a6135 Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 5 Jul 2024 14:18:25 +0800 Subject: [PATCH 14/15] fix preview scroll;fix inumber error;save add show message --- pagebuilder/builder.go | 1 + pagebuilder/editor.go | 2 +- pagebuilder/model.go | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pagebuilder/builder.go b/pagebuilder/builder.go index ed56ca9d2..4e734d960 100644 --- a/pagebuilder/builder.go +++ b/pagebuilder/builder.go @@ -1732,6 +1732,7 @@ func (b *ContainerBuilder) autoSaveContainer(ctx *web.EventContext) (r web.Event return } r.RunScript = web.Plaid().EventFunc(ReloadRenderPageOrTemplateEvent).Go() + presets.ShowMessage(&r, "success", "") return } diff --git a/pagebuilder/editor.go b/pagebuilder/editor.go index d4860bd8a..69f53a6d8 100644 --- a/pagebuilder/editor.go +++ b/pagebuilder/editor.go @@ -96,7 +96,7 @@ func (b *Builder) Editor(m *ModelBuilder) web.PageFunc { exitHref string readonly bool - containerDataID = ctx.R.FormValue(paramContainerDataID) + containerDataID = ctx.Param(paramContainerDataID) obj = m.mb.NewModel() ) if containerDataID != "" { diff --git a/pagebuilder/model.go b/pagebuilder/model.go index 3487afefa..e3ae7f1b5 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -941,7 +941,7 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, "iframe-height", iframeValue, "iframe-height-name", cookieHightName, "width", width, - ":container-data-id", ctx.Param(paramContainerDataID), + "container-data-id", ctx.Param(paramContainerDataID), "ref", "scrollIframe") if isEditor { scrollIframe.Attr(web.VAssign("vars", `{el:$}`)...) @@ -1357,7 +1357,7 @@ func (b *ModelBuilder) newContainerDialog(ctx *web.EventContext) (r web.EventRes VSheet(web.Portal(emptyContent).Name(addContainerDialogContentPortal)), ), ).Align(Center).Justify(Center).Attr("style", "height:420px"), - ).Class(W100), + ).Class(W100, "py-0"), ).Class(W50), ).Class("d-inline-flex"), ).Attr("v-model", "locals.dialog"). @@ -1393,8 +1393,8 @@ func (b *ModelBuilder) containerPreview(ctx *web.EventContext) (r web.EventRespo return } iframe := b.rendering(h.Components(previewContainer), ctx, obj, locale, false, true, true) - body = h.Div(h.Div(iframe). - Style("pointer-events: none;transform-origin: 0 0; transform:scale(0.25);width:400%")).Class(H100) + body = h.Div(iframe). + Style("pointer-events: none;transform-origin: 0 0; transform:scale(0.25);width:400%") } From daedb346b7a4573969fec3b44baa3426f62ad52d Mon Sep 17 00:00:00 2001 From: wen Date: Fri, 5 Jul 2024 14:30:03 +0800 Subject: [PATCH 15/15] remove attr --- pagebuilder/model.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pagebuilder/model.go b/pagebuilder/model.go index e3ae7f1b5..045cfb8b1 100644 --- a/pagebuilder/model.go +++ b/pagebuilder/model.go @@ -941,7 +941,6 @@ func (b *ModelBuilder) rendering(comps []h.HTMLComponent, ctx *web.EventContext, "iframe-height", iframeValue, "iframe-height-name", cookieHightName, "width", width, - "container-data-id", ctx.Param(paramContainerDataID), "ref", "scrollIframe") if isEditor { scrollIframe.Attr(web.VAssign("vars", `{el:$}`)...)