12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997 |
- package pagebuilder
- import (
- "errors"
- "fmt"
- "html/template"
- "net/http"
- "net/url"
- "path"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "github.com/qor5/admin/activity"
- "github.com/qor5/admin/l10n"
- l10n_view "github.com/qor5/admin/l10n/views"
- mediav "github.com/qor5/admin/media/views"
- "github.com/qor5/admin/note"
- "github.com/qor5/admin/presets"
- "github.com/qor5/admin/presets/actions"
- "github.com/qor5/admin/presets/gorm2op"
- "github.com/qor5/admin/publish"
- "github.com/qor5/admin/publish/views"
- pv "github.com/qor5/admin/publish/views"
- "github.com/qor5/admin/seo"
- "github.com/qor5/admin/utils"
- . "github.com/qor5/ui/vuetify"
- vx "github.com/qor5/ui/vuetifyx"
- "github.com/qor5/web"
- "github.com/qor5/x/i18n"
- "github.com/qor5/x/perm"
- "github.com/sunfmin/reflectutils"
- h "github.com/theplant/htmlgo"
- "goji.io/pat"
- "golang.org/x/text/language"
- "gorm.io/gorm"
- )
- type RenderInput struct {
- IsEditor bool
- IsReadonly bool
- Device string
- }
- type RenderFunc func(obj interface{}, input *RenderInput, ctx *web.EventContext) h.HTMLComponent
- type PageLayoutFunc func(body h.HTMLComponent, input *PageLayoutInput, ctx *web.EventContext) h.HTMLComponent
- type PageLayoutInput struct {
- Page *Page
- SeoTags template.HTML
- CanonicalLink template.HTML
- StructuredData template.HTML
- FreeStyleCss []string
- FreeStyleTopJs []string
- FreeStyleBottomJs []string
- Header h.HTMLComponent
- Footer h.HTMLComponent
- IsEditor bool
- EditorCss []h.HTMLComponent
- IsPreview bool
- }
- type Builder struct {
- prefix string
- wb *web.Builder
- db *gorm.DB
- containerBuilders []*ContainerBuilder
- ps *presets.Builder
- mb *presets.ModelBuilder
- pageStyle h.HTMLComponent
- pageLayoutFunc PageLayoutFunc
- preview http.Handler
- images http.Handler
- imagesPrefix string
- defaultDevice string
- publishBtnColor string
- duplicateBtnColor string
- templateEnabled bool
- }
- const (
- openTemplateDialogEvent = "openTemplateDialogEvent"
- selectTemplateEvent = "selectTemplateEvent"
- // clearTemplateEvent = "clearTemplateEvent"
- republishRelatedOnlinePagesEvent = "republish_related_online_pages"
- schedulePublishDialogEvent = "schedulePublishDialogEvent"
- schedulePublishEvent = "schedulePublishEvent"
- createNoteDialogEvent = "createNoteDialogEvent"
- createNoteEvent = "createNoteEvent"
- editSEODialogEvent = "editSEODialogEvent"
- updateSEOEvent = "updateSEOEvent"
- selectVersionEvent = "selectVersionEvent"
- renameVersionDialogEvent = "renameVersionDialogEvent"
- renameVersionEvent = "renameVersionEvent"
- deleteVersionDialogEvent = "deleteVersionDialogEvent"
- paramOpenFromSharedContainer = "open_from_shared_container"
- )
- func New(prefix string, db *gorm.DB, i18nB *i18n.Builder) *Builder {
- err := db.AutoMigrate(
- &Page{},
- &Template{},
- &Container{},
- &DemoContainer{},
- &Category{},
- )
- if err != nil {
- panic(err)
- }
- // https://github.com/go-gorm/sqlite/blob/64917553e84d5482e252c7a0c8f798fb672d7668/ddlmod.go#L16
- // fxxk: newline is not allowed
- err = db.Exec(`
- create unique index if not exists uidx_page_builder_demo_containers_model_name_locale_code on page_builder_demo_containers (model_name, locale_code) where deleted_at is null;
- `).Error
- if err != nil {
- panic(err)
- }
- r := &Builder{
- db: db,
- wb: web.New(),
- prefix: prefix,
- defaultDevice: DeviceComputer,
- publishBtnColor: "primary",
- duplicateBtnColor: "primary",
- templateEnabled: true,
- }
- r.ps = presets.New().
- BrandTitle("Page Builder").
- DataOperator(gorm2op.DataOperator(db)).
- URIPrefix(prefix).
- LayoutFunc(r.pageEditorLayout).
- SetI18n(i18nB)
- type Editor struct {
- }
- r.ps.Model(&Editor{}).
- Detailing().
- PageFunc(r.Editor)
- r.ps.GetWebBuilder().RegisterEventFunc(AddContainerDialogEvent, r.AddContainerDialog)
- r.ps.GetWebBuilder().RegisterEventFunc(AddContainerEvent, r.AddContainer)
- r.ps.GetWebBuilder().RegisterEventFunc(DeleteContainerConfirmationEvent, r.DeleteContainerConfirmation)
- r.ps.GetWebBuilder().RegisterEventFunc(DeleteContainerEvent, r.DeleteContainer)
- r.ps.GetWebBuilder().RegisterEventFunc(MoveContainerEvent, r.MoveContainer)
- r.ps.GetWebBuilder().RegisterEventFunc(ToggleContainerVisibilityEvent, r.ToggleContainerVisibility)
- r.ps.GetWebBuilder().RegisterEventFunc(MarkAsSharedContainerEvent, r.MarkAsSharedContainer)
- r.ps.GetWebBuilder().RegisterEventFunc(RenameContainerDialogEvent, r.RenameContainerDialog)
- r.ps.GetWebBuilder().RegisterEventFunc(RenameContainerEvent, r.RenameContainer)
- r.preview = r.ps.GetWebBuilder().Page(r.Preview)
- return r
- }
- func (b *Builder) Prefix(v string) (r *Builder) {
- b.ps.URIPrefix(v)
- b.prefix = v
- return b
- }
- func (b *Builder) PageStyle(v h.HTMLComponent) (r *Builder) {
- b.pageStyle = v
- return b
- }
- func (b *Builder) PageLayout(v PageLayoutFunc) (r *Builder) {
- b.pageLayoutFunc = v
- return b
- }
- func (b *Builder) Images(v http.Handler, imagesPrefix string) (r *Builder) {
- b.images = v
- b.imagesPrefix = imagesPrefix
- return b
- }
- func (b *Builder) DefaultDevice(v string) (r *Builder) {
- b.defaultDevice = v
- return b
- }
- func (b *Builder) GetPresetsBuilder() (r *presets.Builder) {
- return b.ps
- }
- func (b *Builder) PublishBtnColor(v string) (r *Builder) {
- b.publishBtnColor = v
- return b
- }
- func (b *Builder) DuplicateBtnColor(v string) (r *Builder) {
- b.duplicateBtnColor = v
- return b
- }
- func (b *Builder) TemplateEnabled(v bool) (r *Builder) {
- b.templateEnabled = v
- return b
- }
- func (b *Builder) Configure(pb *presets.Builder, db *gorm.DB, l10nB *l10n.Builder, activityB *activity.ActivityBuilder, publisher *publish.Builder, seoCollection *seo.Collection) (pm *presets.ModelBuilder) {
- pb.I18n().
- RegisterForModule(language.English, I18nPageBuilderKey, Messages_en_US).
- RegisterForModule(language.SimplifiedChinese, I18nPageBuilderKey, Messages_zh_CN).
- RegisterForModule(language.Japanese, I18nPageBuilderKey, Messages_ja_JP)
- pm = pb.Model(&Page{})
- templateM := presets.NewModelBuilder(pb, &Template{})
- if b.templateEnabled {
- templateM = b.ConfigTemplate(pb, db)
- }
- b.mb = pm
- pm.Listing("ID", "Online", "Title", "Slug")
- dp := pm.Detailing("Overview")
- dp.Field("Overview").ComponentFunc(settings(db, pm))
- oldDetailLayout := pb.GetDetailLayoutFunc()
- pb.DetailLayoutFunc(func(in web.PageFunc, cfg *presets.LayoutConfig) (out web.PageFunc) {
- return func(ctx *web.EventContext) (pr web.PageResponse, err error) {
- if !strings.Contains(ctx.R.RequestURI, "/"+pm.Info().URIName()+"/") && !strings.Contains(ctx.R.RequestURI, "/"+templateM.Info().URIName()+"/") {
- pr, err = oldDetailLayout(in, cfg)(ctx)
- return
- }
- pb.InjectAssets(ctx)
- // call createMenus before in(ctx) to fill the menuGroupName for modelBuilders first
- menu := pb.CreateMenus(ctx)
- var profile h.HTMLComponent
- if pb.GetProfileFunc() != nil {
- profile = pb.GetProfileFunc()(ctx)
- }
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- utilsMsgr := i18n.MustGetModuleMessages(ctx.R, utils.I18nUtilsKey, utils.Messages_en_US).(*utils.Messages)
- pvMsgr := i18n.MustGetModuleMessages(ctx.R, pv.I18nPublishKey, utils.Messages_en_US).(*pv.Messages)
- id := pat.Param(ctx.R, "id")
- if id == "" {
- return pb.DefaultNotFoundPageFunc(ctx)
- }
- isPage := strings.Contains(ctx.R.RequestURI, "/"+pm.Info().URIName()+"/")
- isTemplate := strings.Contains(ctx.R.RequestURI, "/"+templateM.Info().URIName()+"/")
- var obj interface{}
- var dmb *presets.ModelBuilder
- if isPage {
- dmb = pm
- } else {
- dmb = templateM
- }
- obj = dmb.NewModel()
- if sd, ok := obj.(presets.SlugDecoder); ok {
- vs, err := presets.RecoverPrimaryColumnValuesBySlug(sd, id)
- if err != nil {
- return pb.DefaultNotFoundPageFunc(ctx)
- }
- if _, err := strconv.Atoi(vs["id"]); err != nil {
- return pb.DefaultNotFoundPageFunc(ctx)
- }
- } else {
- if _, err := strconv.Atoi(id); err != nil {
- return pb.DefaultNotFoundPageFunc(ctx)
- }
- }
- obj, err = dmb.Detailing().GetFetchFunc()(obj, id, ctx)
- if err != nil {
- if errors.Is(err, presets.ErrRecordNotFound) {
- return pb.DefaultNotFoundPageFunc(ctx)
- }
- return
- }
- if l, ok := obj.(l10n.L10nInterface); ok {
- locale := ctx.R.FormValue("locale")
- if ctx.R.FormValue(web.EventFuncIDName) == "__reload__" && locale != "" && locale != l.GetLocale() {
- // redirect to list page when change locale
- http.Redirect(ctx.W, ctx.R, dmb.Info().ListingHref(), http.StatusSeeOther)
- return
- }
- }
- var tabContent web.PageResponse
- tab := ctx.R.FormValue("tab")
- isContent := tab == "content"
- activeTabIndex := 0
- isVersion := false
- if _, ok := obj.(publish.VersionInterface); ok {
- isVersion = true
- }
- if isContent {
- activeTabIndex = 1
- if v, ok := obj.(interface {
- GetID() uint
- }); ok {
- ctx.R.Form.Set("id", strconv.Itoa(int(v.GetID())))
- }
- if v, ok := obj.(publish.VersionInterface); ok {
- ctx.R.Form.Set("version", v.GetVersion())
- }
- if l, ok := obj.(l10n.L10nInterface); ok {
- ctx.R.Form.Set("locale", l.GetLocale())
- }
- if isTemplate {
- ctx.R.Form.Set("tpl", "1")
- }
- tabContent, err = b.PageContent(ctx)
- } else {
- tabContent, err = in(ctx)
- }
- if errors.Is(err, perm.PermissionDenied) {
- pr.Body = h.Text(perm.PermissionDenied.Error())
- return pr, nil
- }
- if err != nil {
- panic(err)
- }
- device := ctx.R.FormValue("device")
- editAction := web.POST().
- EventFunc(actions.Edit).
- URL(web.Var("\""+b.prefix+"/\"+arr[0]")).
- Query(presets.ParamOverlay, actions.Dialog).
- Query(presets.ParamID, web.Var("arr[1]")).
- Go()
- var publishBtn h.HTMLComponent
- var duplicateBtn h.HTMLComponent
- var versionSwitch h.HTMLComponent
- primarySlug := ""
- if v, ok := obj.(presets.SlugEncoder); ok {
- primarySlug = v.PrimarySlug()
- }
- if isVersion {
- p := obj.(*Page)
- versionCount := versionCount(db, p)
- switch p.GetStatus() {
- case publish.StatusDraft, publish.StatusOffline:
- publishBtn = VBtn(pvMsgr.Publish).Small(true).Color(b.publishBtnColor).Height(40).Attr("@click", fmt.Sprintf(`locals.action="%s";locals.commonConfirmDialog = true`, pv.PublishEvent))
- case publish.StatusOnline:
- publishBtn = VBtn(pvMsgr.Republish).Small(true).Color(b.publishBtnColor).Height(40).Attr("@click", fmt.Sprintf(`locals.action="%s";locals.commonConfirmDialog = true`, pv.RepublishEvent))
- }
- duplicateBtn = VBtn(msgr.Duplicate).
- Small(true).Color(b.duplicateBtnColor).Height(40).Class("rounded-l-0 mr-3").
- Attr("@click", web.Plaid().
- EventFunc(pv.DuplicateVersionEvent).
- URL(pm.Info().ListingHref()).
- Query(presets.ParamID, primarySlug).
- Query("tab", tab).
- QueryIf("device", device, device != "").
- FieldValue("Title", p.Title).FieldValue("Slug", p.Slug).FieldValue("CategoryID", p.CategoryID).
- Go(),
- )
- versionSwitch = VChip(
- VChip(h.Text(fmt.Sprintf("%d", versionCount))).Label(true).Color("#E0E0E0").Small(true).Class("px-1 mx-1").TextColor("black").Attr("style", "height:20px"),
- h.Text(p.GetVersionName()+" | "),
- VChip(h.Text(pv.GetStatusText(p.GetStatus(), pvMsgr))).Label(true).Color(pv.GetStatusColor(p.GetStatus())).Small(true).Class("px-1 mx-1").TextColor("black").Attr("style", "height:20px"),
- VIcon("chevron_right"),
- ).Label(true).Outlined(true).Class("px-1 ml-8 rounded-r-0").Attr("style", "height:40px;background-color:#FFFFFF!important;").TextColor("black").
- Attr("@click", web.Plaid().EventFunc(actions.OpenListingDialog).
- URL(b.ps.GetURIPrefix()+"/version-list-dialog").
- Query("select_id", primarySlug).
- Go())
- }
- pr.Body = VApp(
- VNavigationDrawer(
- pb.RunBrandProfileSwitchLanguageDisplayFunc(pb.RunBrandFunc(ctx), profile, pb.RunSwitchLanguageFunc(ctx), ctx),
- VDivider(),
- menu,
- ).App(true).
- Fixed(true).
- Value(true).
- Attr("v-model", "vars.navDrawer").
- Attr(web.InitContextVars, `{navDrawer: null}`),
- VAppBar(
- VAppBarNavIcon().On("click.stop", "vars.navDrawer = !vars.navDrawer"),
- VTabs(
- VTab(h.Text("{{item.label}}")).Attr("@click", web.Plaid().Query("tab", web.Var("item.query")).PushState(true).Go()).
- Attr("v-for", "(item, index) in locals.tabs", ":key", "index"),
- ).Centered(true).FixedTabs(true).Attr("v-model", `locals.activeTab`).Attr("style", "width:400px"),
- // h.If(isContent, VAppBarNavIcon().On("click.stop", "vars.pbEditorDrawer = !vars.pbEditorDrawer")),
- h.If(isVersion, versionSwitch, duplicateBtn, publishBtn),
- ).Dark(true).
- Color(presets.ColorPrimary).
- App(true).
- ClippedRight(true).
- Fixed(true),
- web.Portal().Name(presets.RightDrawerPortalName),
- web.Portal().Name(presets.DialogPortalName),
- web.Portal().Name(presets.DeleteConfirmPortalName),
- web.Portal().Name(presets.DefaultConfirmDialogPortalName),
- web.Portal().Name(presets.ListingDialogPortalName),
- web.Portal().Name(dialogPortalName),
- utils.ConfirmDialog(pvMsgr.Areyousure, web.Plaid().EventFunc(web.Var("locals.action")).
- Query(presets.ParamID, primarySlug).Go(),
- utilsMsgr),
- h.If(isContent, h.Script(`
- (function(){
- let scrollLeft = 0;
- let scrollTop = 0;
-
- function pause(duration) {
- return new Promise(res => setTimeout(res, duration));
- }
- function backoff(retries, fn, delay = 100) {
- fn().catch(err => retries > 1
- ? pause(delay).then(() => backoff(retries - 1, fn, delay * 2))
- : Promise.reject(err));
- }
- function restoreScroll() {
- window.scroll({left: scrollLeft, top: scrollTop, behavior: "auto"});
- if (window.scrollX == scrollLeft && window.scrollY == scrollTop) {
- return Promise.resolve();
- }
- return Promise.reject();
- }
- window.addEventListener('fetchStart', (event) => {
- scrollLeft = window.scrollX;
- scrollTop = window.scrollY;
- });
-
- window.addEventListener('fetchEnd', (event) => {
- backoff(5, restoreScroll, 100);
- });
- })()
- `),
- vx.VXMessageListener().ListenFunc(fmt.Sprintf(`
- function(e){
- if (!e.data.split) {
- return
- }
- let arr = e.data.split("_");
- if (arr.length != 2) {
- console.log(arr);
- return
- }
- %s
- }`, editAction))),
- VProgressLinear().
- Attr(":active", "isFetching").
- Attr("style", "position: fixed; z-index: 99").
- Indeterminate(true).
- Height(2).
- Color(pb.GetProgressBarColor()),
- h.Template(
- VSnackbar(h.Text("{{vars.presetsMessage.message}}")).
- Attr("v-model", "vars.presetsMessage.show").
- Attr(":color", "vars.presetsMessage.color").
- Timeout(1000).
- Top(true),
- ).Attr("v-if", "vars.presetsMessage"),
- VMain(
- tabContent.Body.(h.HTMLComponent),
- ),
- ).Id("vt-app").
- Attr(web.InitContextVars, `{presetsRightDrawer: false, presetsDialog: false, dialogPortalName: false, presetsListingDialog: false, presetsMessage: {show: false, color: "success", message: ""}}`).
- Attr(web.InitContextLocals, fmt.Sprintf(`{action: "", commonConfirmDialog: false, activeTab:%d, tabs: [{label:"SETTINGS",query:"settings"},{label:"CONTENT",query:"content"}]}`, activeTabIndex))
- return
- }
- })
- configureVersionListDialog(db, b.ps, pm)
- if b.templateEnabled {
- pm.RegisterEventFunc(openTemplateDialogEvent, openTemplateDialog(db, b.prefix))
- pm.RegisterEventFunc(selectTemplateEvent, selectTemplate(db))
- // pm.RegisterEventFunc(clearTemplateEvent, clearTemplate(db))
- }
- pm.RegisterEventFunc(schedulePublishDialogEvent, schedulePublishDialog(db, pm))
- pm.RegisterEventFunc(schedulePublishEvent, schedulePublish(db, pm))
- pm.RegisterEventFunc(createNoteDialogEvent, createNoteDialog(db, pm))
- pm.RegisterEventFunc(createNoteEvent, createNote(db, pm))
- pm.RegisterEventFunc(editSEODialogEvent, editSEODialog(db, pm, seoCollection))
- pm.RegisterEventFunc(updateSEOEvent, updateSEO(db, pm))
- eb := pm.Editing("TemplateSelection", "Title", "CategoryID", "Slug")
- eb.ValidateFunc(func(obj interface{}, ctx *web.EventContext) (err web.ValidationErrors) {
- c := obj.(*Page)
- err = pageValidator(c, db, l10nB)
- return
- })
- eb.Field("Slug").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- var vErr web.ValidationErrors
- if ve, ok := ctx.Flash.(*web.ValidationErrors); ok {
- vErr = *ve
- }
- return VTextField().
- FieldName(field.Name).
- Prefix("/").
- Label(field.Label).Value(strings.TrimPrefix(field.Value(obj).(string), "/")).
- ErrorMessages(vErr.GetFieldErrors("Page.Slug")...)
- }).SetterFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) (err error) {
- m := obj.(*Page)
- m.Slug = path.Join("/", m.Slug)
- return nil
- })
- eb.Field("CategoryID").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- p := obj.(*Page)
- categories := []*Category{}
- locale, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- if err := db.Model(&Category{}).Where("locale_code = ?", locale).Find(&categories).Error; err != nil {
- panic(err)
- }
- var vErr web.ValidationErrors
- if ve, ok := ctx.Flash.(*web.ValidationErrors); ok {
- vErr = *ve
- }
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- return vx.VXAutocomplete().Label(msgr.Category).FieldName(field.Name).
- Multiple(false).Chips(false).
- Items(categories).Value(p.CategoryID).ItemText("Path").ItemValue("ID").
- ErrorMessages(vErr.GetFieldErrors("Page.Category")...)
- })
- eb.Field("TemplateSelection").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- if !b.templateEnabled {
- return nil
- }
- p := obj.(*Page)
- selectedID := ctx.R.FormValue(templateSelectedID)
- body, err := getTplPortalComp(ctx, db, selectedID)
- if err != nil {
- panic(err)
- }
- // Display template selection only when creating a new page
- if p.ID == 0 {
- return h.Div(
- web.Portal().Name(templateSelectPortal),
- web.Portal(
- body,
- ).Name(selectedTemplatePortal),
- ).Class("my-2").Attr(web.InitContextVars, `{showTemplateDialog: false}`)
- }
- return nil
- })
- eb.Field("EditContainer").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- p := obj.(*Page)
- if p.ID == 0 {
- return nil
- }
- if p.GetStatus() == publish.StatusDraft {
- var href = fmt.Sprintf("%s/editors/%d?version=%s", b.prefix, p.ID, p.GetVersion())
- if locale, isLocalizable := l10n.IsLocalizableFromCtx(ctx.R.Context()); isLocalizable && l10nON {
- href = fmt.Sprintf("%s/editors/%d?version=%s&locale=%s", b.prefix, p.ID, p.GetVersion(), locale)
- }
- return h.Div(
- VBtn(msgr.EditPageContent).
- Target("_blank").
- Href(href).
- Color("secondary"),
- )
- } else {
- var href = fmt.Sprintf("%s/preview?id=%d&version=%s", b.prefix, p.ID, p.GetVersion())
- if locale, isLocalizable := l10n.IsLocalizableFromCtx(ctx.R.Context()); isLocalizable && l10nON {
- href = fmt.Sprintf("%s/preview?id=%d&version=%s&locale=%s", b.prefix, p.ID, p.GetVersion(), locale)
- }
- return h.Div(
- VBtn(msgr.Preview).
- Target("_blank").
- Href(href).
- Color("secondary"),
- )
- }
- return nil
- })
- eb.SaveFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) {
- localeCode, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- p := obj.(*Page)
- if p.Slug != "" {
- p.Slug = path.Clean(p.Slug)
- }
- funcName := ctx.R.FormValue(web.EventFuncIDName)
- if funcName == pv.DuplicateVersionEvent {
- id := ctx.R.FormValue(presets.ParamID)
- var fromPage Page
- eb.Fetcher(&fromPage, id, ctx)
- p.SEO = fromPage.SEO
- }
- err = 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, pv.SaveNewVersionEvent) || strings.Contains(ctx.R.RequestURI, pv.DuplicateVersionEvent) {
- if inerr = b.copyContainersToNewPageVersion(tx, int(p.ID), p.GetLocale(), p.ParentVersion, p.GetVersion()); inerr != nil {
- return
- }
- return
- }
- if v := ctx.R.FormValue(templateSelectedID); v != "" {
- var tplID int
- tplID, inerr = strconv.Atoi(v)
- if inerr != nil {
- return
- }
- if !l10nON {
- localeCode = ""
- }
- if inerr = b.copyContainersToAnotherPage(tx, tplID, templateVersion, localeCode, int(p.ID), p.GetVersion(), localeCode); inerr != nil {
- panic(inerr)
- return
- }
- }
- if l10nON && strings.Contains(ctx.R.RequestURI, l10n_view.DoLocalize) {
- fromID := ctx.R.Context().Value(l10n_view.FromID).(string)
- fromVersion := ctx.R.Context().Value(l10n_view.FromVersion).(string)
- fromLocale := ctx.R.Context().Value(l10n_view.FromLocale).(string)
- var fromIDInt int
- fromIDInt, err = strconv.Atoi(fromID)
- if err != nil {
- return
- }
- if inerr = b.localizeContainersToAnotherPage(tx, fromIDInt, fromVersion, fromLocale, int(p.ID), p.GetVersion(), p.GetLocale()); inerr != nil {
- panic(inerr)
- return
- }
- return
- }
- return
- })
- return
- })
- sharedContainerM := b.ConfigSharedContainer(pb, db)
- demoContainerM := b.ConfigDemoContainer(pb, db)
- categoryM := b.ConfigCategory(pb, db, l10nB)
- if activityB != nil {
- activityB.RegisterModels(pm, sharedContainerM, demoContainerM, templateM, categoryM)
- }
- if l10nB != nil {
- l10n_view.Configure(pb, db, l10nB, activityB, pm, demoContainerM, templateM, categoryM)
- }
- if publisher != nil {
- publisher.WithPageBuilder(b)
- pv.Configure(pb, db, activityB, publisher, pm)
- pm.Editing().SidePanelFunc(nil).ActionsFunc(nil)
- }
- if seoCollection != nil {
- seoCollection.RegisterSEO(&Page{}).RegisterContextVariables(
- "Title",
- func(object interface{}, _ *seo.Setting, _ *http.Request) string {
- if p, ok := object.(Page); ok {
- return p.Title
- }
- return ""
- },
- )
- }
- note.Configure(db, pb, pm)
- eb.CleanTabsPanels()
- dp.CleanTabsPanels()
- mediav.Configure(b.GetPresetsBuilder(), db)
- return
- }
- func versionCount(db *gorm.DB, p *Page) (count int64) {
- db.Model(&Page{}).Where("id = ? and locale_code = ?", p.ID, p.LocaleCode).Count(&count)
- return
- }
- func configureVersionListDialog(db *gorm.DB, pb *presets.Builder, pm *presets.ModelBuilder) {
- mb := pb.Model(&Page{}).
- URIName("version-list-dialog").
- InMenu(false)
- searcher := mb.Listing().Searcher
- lb := mb.Listing("Version", "State", "Notes", "Option").
- SearchColumns("version", "version_name").
- PerPage(10).
- SearchFunc(func(model interface{}, params *presets.SearchParams, ctx *web.EventContext) (r interface{}, totalCount int, err error) {
- id := ctx.R.FormValue("select_id")
- if id == "" {
- id = ctx.R.FormValue("f_select_id")
- }
- if id != "" {
- cs := mb.NewModel().(presets.SlugDecoder).PrimaryColumnValuesBySlug(id)
- con := presets.SQLCondition{
- Query: "id = ? and locale_code = ?",
- Args: []interface{}{cs["id"], cs["locale_code"]},
- }
- params.SQLConditions = append(params.SQLConditions, &con)
- }
- params.OrderBy = "created_at DESC"
- return searcher(model, params, ctx)
- })
- lb.Field("Version").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- versionName := obj.(publish.VersionInterface).GetVersionName()
- return h.Td(
- h.Text(versionName),
- VBtn("").Icon(true).Children(VIcon("edit")).Attr("@click", web.Plaid().
- URL(pb.GetURIPrefix()+"/version-list-dialog").
- EventFunc(renameVersionDialogEvent).
- Queries(ctx.Queries()).
- Query(presets.ParamOverlay, actions.Dialog).
- Query("rename_id", obj.(presets.SlugEncoder).PrimarySlug()).
- Query("version_name", versionName).
- Go()),
- )
- })
- lb.Field("State").ComponentFunc(pv.StatusListFunc())
- lb.Field("Notes").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- p := obj.(*Page)
- rt := pm.Info().Label()
- ri := p.PrimarySlug()
- userID, _ := note.GetUserData(ctx)
- count := note.GetUnreadNotesCount(db, userID, rt, ri)
- return h.Td(
- h.If(count > 0,
- VBadge().Content(count).Color("red"),
- ).Else(
- h.Text(""),
- ),
- )
- }).Label("Unread Notes")
- lb.Field("Option").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- p := obj.(*Page)
- id := ctx.R.FormValue("select_id")
- if id == "" {
- id = ctx.R.FormValue("f_select_id")
- }
- versionName := p.GetVersionName()
- if p.PrimarySlug() == id {
- return h.Td(h.Text("current"))
- }
- if p.GetStatus() != publish.StatusDraft {
- return h.Td()
- }
- return h.Td(VBtn("").Icon(true).Children(VIcon("delete")).Attr("@click", web.Plaid().
- URL(pb.GetURIPrefix()+"/version-list-dialog").
- EventFunc(deleteVersionDialogEvent).
- Queries(ctx.Queries()).
- Query(presets.ParamOverlay, actions.Dialog).
- Query("delete_id", obj.(presets.SlugEncoder).PrimarySlug()).
- Query("version_name", versionName).
- Go()))
- })
- lb.NewButtonFunc(func(ctx *web.EventContext) h.HTMLComponent { return nil })
- lb.RowMenu().Empty()
- mb.RegisterEventFunc(selectVersionEvent, func(ctx *web.EventContext) (r web.EventResponse, err error) {
- id := ctx.R.FormValue("select_id")
- refer, _ := url.Parse(ctx.R.Referer())
- newQueries := refer.Query()
- r.PushState = web.Location(newQueries).URL(pm.Info().DetailingHref(id))
- return
- })
- mb.RegisterEventFunc(renameVersionDialogEvent, renameVersionDialog(mb))
- mb.RegisterEventFunc(renameVersionEvent, renameVersion(mb))
- mb.RegisterEventFunc(deleteVersionDialogEvent, deleteVersionDialog(mb))
- lb.CellWrapperFunc(func(cell h.MutableAttrHTMLComponent, id string, obj interface{}, dataTableID string) h.HTMLComponent {
- cell.SetAttr("@click.self", web.Plaid().
- Query("select_id", obj.(*Page).PrimarySlug()).
- URL(pb.GetURIPrefix()+"/version-list-dialog").
- EventFunc(selectVersionEvent).
- Go(),
- )
- return cell
- })
- lb.FilterDataFunc(func(ctx *web.EventContext) vx.FilterData {
- return []*vx.FilterItem{
- {
- Key: "all",
- Invisible: true,
- SQLCondition: ``,
- },
- {
- Key: "online_version",
- Invisible: true,
- SQLCondition: `status = 'online'`,
- },
- {
- Key: "named_versions",
- Invisible: true,
- SQLCondition: `version <> version_name`,
- },
- }
- })
- lb.FilterTabsFunc(func(ctx *web.EventContext) []*presets.FilterTab {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- id := ctx.R.FormValue("select_id")
- if id == "" {
- id = ctx.R.FormValue("f_select_id")
- }
- return []*presets.FilterTab{
- {
- Label: msgr.FilterTabAllVersions,
- ID: "all",
- Query: url.Values{"all": []string{"1"}, "select_id": []string{id}},
- },
- {
- Label: msgr.FilterTabOnlineVersion,
- ID: "online_version",
- Query: url.Values{"online_version": []string{"1"}, "select_id": []string{id}},
- },
- {
- Label: msgr.FilterTabNamedVersions,
- ID: "named_versions",
- Query: url.Values{"named_versions": []string{"1"}, "select_id": []string{id}},
- },
- }
- })
- }
- // cats should be ordered by path
- func fillCategoryIndentLevels(cats []*Category) {
- for i, cat := range cats {
- if cat.Path == "/" {
- continue
- }
- for j := i - 1; j >= 0; j-- {
- if strings.HasPrefix(cat.Path, cats[j].Path+"/") {
- cat.IndentLevel = cats[j].IndentLevel + 1
- break
- }
- }
- }
- }
- func (b *Builder) ConfigCategory(pb *presets.Builder, db *gorm.DB, l10nB *l10n.Builder) (pm *presets.ModelBuilder) {
- pm = pb.Model(&Category{}).URIName("page_categories").Label("Categories")
- lb := pm.Listing("Name", "Path", "Description")
- oldSearcher := lb.Searcher
- lb.SearchFunc(func(model interface{}, params *presets.SearchParams, ctx *web.EventContext) (r interface{}, totalCount int, err error) {
- r, totalCount, err = oldSearcher(model, params, ctx)
- cats := r.([]*Category)
- sort.Slice(cats, func(i, j int) bool {
- return cats[i].Path < cats[j].Path
- })
- fillCategoryIndentLevels(cats)
- return
- })
- lb.Field("Name").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- cat := obj.(*Category)
- icon := "folder"
- if cat.IndentLevel != 0 {
- icon = "insert_drive_file"
- }
- return h.Td(
- h.Div(
- VIcon(icon).Small(true).Class("mb-1"),
- h.Text(cat.Name),
- ).Style(fmt.Sprintf("padding-left: %dpx;", cat.IndentLevel*32)),
- )
- })
- eb := pm.Editing("Name", "Path", "Description")
- eb.Field("Path").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- var vErr web.ValidationErrors
- if ve, ok := ctx.Flash.(*web.ValidationErrors); ok {
- vErr = *ve
- }
- return VTextField().Label("Path").
- Value(strings.TrimPrefix(field.Value(obj).(string), "/")).
- FieldName("Path").
- Prefix("/").
- ErrorMessages(vErr.GetFieldErrors("Category.Category")...)
- }).SetterFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) (err error) {
- m := obj.(*Category)
- p := ctx.R.FormValue(field.Name)
- p = path.Join("/", p)
- m.Path = p
- return nil
- })
- eb.DeleteFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) {
- cs := obj.(presets.SlugDecoder).PrimaryColumnValuesBySlug(id)
- ID := cs["id"]
- Locale := cs["locale_code"]
- var count int64
- if err = db.Model(&Page{}).Where("category_id = ? AND locale_code = ?", ID, Locale).Count(&count).Error; err != nil {
- return
- }
- if count > 0 {
- err = errors.New(unableDeleteCategoryMsg)
- return
- }
- if err = db.Model(&Category{}).Where("id = ? AND locale_code = ?", ID, Locale).Delete(&Category{}).Error; err != nil {
- return
- }
- return
- })
- eb.ValidateFunc(func(obj interface{}, ctx *web.EventContext) (err web.ValidationErrors) {
- c := obj.(*Category)
- err = categoryValidator(c, db, l10nB)
- return
- })
- eb.SaveFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) {
- c := obj.(*Category)
- c.Path = path.Clean(c.Path)
- err = db.Save(c).Error
- return
- })
- return
- }
- const (
- templateSelectPortal = "templateSelectPortal"
- selectedTemplatePortal = "selectedTemplatePortal"
- templateSelectedID = "TemplateSelectedID"
- templateID = "TemplateID"
- templateBlankVal = "blank"
- )
- func selectTemplate(db *gorm.DB) web.EventFunc {
- return func(ctx *web.EventContext) (er web.EventResponse, err error) {
- defer func() {
- web.AppendVarsScripts(&er, "vars.showTemplateDialog=false")
- }()
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- id := ctx.R.FormValue(templateID)
- if id == templateBlankVal {
- er.UpdatePortals = append(er.UpdatePortals, &web.PortalUpdate{
- Name: selectedTemplatePortal,
- Body: VRow(
- VCol(
- h.Input("").Type("hidden").Value("").Attr(web.VFieldName(templateSelectedID)...),
- VTextField().Readonly(true).Label(msgr.SelectedTemplateLabel).Value(msgr.Blank).Dense(true).Outlined(true),
- ).Cols(5),
- VCol(
- VBtn(msgr.ChangeTemplate).Color("primary").
- Attr("@click", web.Plaid().Query(templateSelectedID, "").EventFunc(openTemplateDialogEvent).Go()),
- ).Cols(5),
- ),
- })
- return
- }
- var body h.HTMLComponent
- if body, err = getTplPortalComp(ctx, db, id); err != nil {
- return
- }
- er.UpdatePortals = append(er.UpdatePortals, &web.PortalUpdate{
- Name: selectedTemplatePortal,
- Body: body,
- })
- return
- }
- }
- func getTplPortalComp(ctx *web.EventContext, db *gorm.DB, selectedID string) (h.HTMLComponent, error) {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- locale, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- name := msgr.Blank
- if selectedID != "" {
- if err := db.Model(&Template{}).Where("id = ? AND locale_code = ?", selectedID, locale).Pluck("name", &name).Error; err != nil {
- return nil, err
- }
- }
- return VRow(
- VCol(
- h.Input("").Type("hidden").Value(selectedID).Attr(web.VFieldName(templateSelectedID)...),
- VTextField().Readonly(true).Label(msgr.SelectedTemplateLabel).Value(name).Dense(true).Outlined(true),
- ).Cols(5),
- VCol(
- VBtn(msgr.ChangeTemplate).Color("primary").
- Attr("@click", web.Plaid().Query(templateSelectedID, selectedID).EventFunc(openTemplateDialogEvent).Go()),
- ).Cols(5),
- ), nil
- }
- // Unused
- func clearTemplate(db *gorm.DB) web.EventFunc {
- return func(ctx *web.EventContext) (er web.EventResponse, err error) {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- er.UpdatePortals = append(er.UpdatePortals, &web.PortalUpdate{
- Name: selectedTemplatePortal,
- Body: VRow(
- VCol(
- h.Input("").Type("hidden").Value("").Attr(web.VFieldName(templateSelectedID)...),
- VTextField().Readonly(true).Label(msgr.SelectedTemplateLabel).Value(msgr.Blank).Dense(true).Outlined(true),
- ).Cols(5),
- VCol(
- VBtn(msgr.ChangeTemplate).Color("primary").
- Attr("@click", web.Plaid().Query(templateSelectedID, "").EventFunc(openTemplateDialogEvent).Go()),
- ).Cols(5),
- ),
- })
- return
- }
- }
- func openTemplateDialog(db *gorm.DB, prefix string) web.EventFunc {
- return func(ctx *web.EventContext) (er web.EventResponse, err error) {
- gmsgr := presets.MustGetMessages(ctx.R)
- locale, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- selectedID := ctx.R.FormValue(templateSelectedID)
- tpls := []*Template{}
- if err := db.Model(&Template{}).Where("locale_code = ?", locale).Find(&tpls).Error; err != nil {
- panic(err)
- }
- msgrPb := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- var tplHTMLComponents []h.HTMLComponent
- tplHTMLComponents = append(tplHTMLComponents,
- VCol(
- VCard(
- h.Div(
- h.Iframe().
- Attr("width", "100%", "height", "150", "frameborder", "no").
- Style("transform-origin: left top; transform: scale(1, 1); pointer-events: none;"),
- ),
- VCardTitle(h.Text(msgrPb.Blank)),
- VCardSubtitle(h.Text("")),
- h.Div(
- h.Input(templateID).Type("radio").
- Value(templateBlankVal).
- Attr(web.VFieldName(templateID)...).
- AttrIf("checked", "checked", selectedID == "").
- Style("width: 18px; height: 18px"),
- ).Class("mr-4 float-right"),
- ).Height(280).Class("text-truncate").Outlined(true),
- ).Cols(3),
- )
- for _, tpl := range tpls {
- tplHTMLComponents = append(tplHTMLComponents,
- getTplColComponent(ctx, prefix, tpl, selectedID),
- )
- }
- if len(tpls) == 0 {
- tplHTMLComponents = append(tplHTMLComponents,
- h.Div(h.Text(gmsgr.ListingNoRecordToShow)).Class("pl-4 text-center grey--text text--darken-2"),
- )
- }
- er.UpdatePortals = append(er.UpdatePortals, &web.PortalUpdate{
- Name: templateSelectPortal,
- Body: VDialog(
- VCard(
- VCardTitle(
- h.Text(msgrPb.CreateFromTemplate),
- VSpacer(),
- VBtn("").Icon(true).
- Children(VIcon("close")).
- Large(true).
- On("click", fmt.Sprintf("vars.showTemplateDialog=false")),
- ),
- VCardActions(
- VRow(tplHTMLComponents...),
- ),
- VCardActions(
- VSpacer(),
- VBtn(gmsgr.Cancel).Attr("@click", "vars.showTemplateDialog=false"),
- VBtn(gmsgr.OK).Color("primary").
- Attr("@click", web.Plaid().EventFunc(selectTemplateEvent).
- Go(),
- ),
- ).Class("pb-4"),
- ).Tile(true),
- ).MaxWidth("80%").
- Attr("v-model", fmt.Sprintf("vars.showTemplateDialog")).
- Attr(web.InitContextVars, fmt.Sprintf(`{showTemplateDialog: false}`)),
- })
- er.VarsScript = `setTimeout(function(){ vars.showTemplateDialog = true }, 100)`
- return
- }
- }
- func getTplColComponent(ctx *web.EventContext, prefix string, tpl *Template, selectedID string) h.HTMLComponent {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- // Avoid layout errors
- var name string
- var desc string
- if tpl.Name == "" {
- name = msgr.Unnamed
- } else {
- name = tpl.Name
- }
- if tpl.Description == "" {
- desc = msgr.NotDescribed
- } else {
- desc = tpl.Description
- }
- id := fmt.Sprintf("%d", tpl.ID)
- src := fmt.Sprintf("./%s/preview?id=%d&tpl=1&locale=%s", prefix, tpl.ID, tpl.LocaleCode)
- return VCol(
- VCard(
- h.Div(
- h.Iframe().Src(src).
- Attr("width", "100%", "height", "150", "frameborder", "no").
- Style("transform-origin: left top; transform: scale(1, 1); pointer-events: none;"),
- ),
- VCardTitle(h.Text(name)),
- VCardSubtitle(h.Text(desc)),
- VBtn(msgr.Preview).Text(true).XSmall(true).Class("ml-2 mb-4").
- Href(src).
- Target("_blank").Color("primary"),
- h.Div(
- h.Input(templateID).Type("radio").
- Value(id).
- Attr(web.VFieldName(templateID)...).
- AttrIf("checked", "checked", selectedID == id).
- Style("width: 18px; height: 18px"),
- ).Class("mr-4 float-right"),
- ).Height(280).Class("text-truncate").Outlined(true),
- ).Cols(3)
- }
- func schedulePublishDialog(db *gorm.DB, mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue(presets.ParamID)
- obj := mb.NewModel()
- obj, err = mb.Editing().Fetcher(obj, paramID, ctx)
- if err != nil {
- return
- }
- s, ok := obj.(publish.ScheduleInterface)
- if !ok {
- return
- }
- var start, end string
- if s.GetScheduledStartAt() != nil {
- start = s.GetScheduledStartAt().Format("2006-01-02 15:04")
- }
- if s.GetScheduledEndAt() != nil {
- end = s.GetScheduledEndAt().Format("2006-01-02 15:04")
- }
- msgr := i18n.MustGetModuleMessages(ctx.R, pv.I18nPublishKey, Messages_en_US).(*pv.Messages)
- cmsgr := i18n.MustGetModuleMessages(ctx.R, presets.CoreI18nModuleKey, Messages_en_US).(*presets.Messages)
- updateBtn := VBtn(cmsgr.Update).
- Color("primary").
- Attr(":disabled", "isFetching").
- Attr(":loading", "isFetching").
- Attr("@click", web.Plaid().
- EventFunc(schedulePublishEvent).
- // Queries(queries).
- Query(presets.ParamID, paramID).
- Query(presets.ParamOverlay, actions.Dialog).
- URL(mb.Info().ListingHref()).
- Go())
- r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
- Name: dialogPortalName,
- Body: web.Scope(
- VDialog(
- VCard(
- VCardTitle(h.Text("Schedule Publish Time")),
- VCardText(
- VRow(
- VCol(
- vx.VXDateTimePicker().FieldName("ScheduledStartAt").Label(msgr.ScheduledStartAt).Value(start).
- TimePickerProps(vx.TimePickerProps{Format: "24hr", Scrollable: true}).
- ClearText(msgr.DateTimePickerClearText).OkText(msgr.DateTimePickerOkText),
- // h.RawHTML(fmt.Sprintf(`<vx-datetimepicker label="ScheduledStartAt" value="%s" v-field-name='"ScheduledStartAt"'> </vx-datetimepicker>`, start)),
- ).Cols(6),
- VCol(
- vx.VXDateTimePicker().FieldName("ScheduledEndAt").Label(msgr.ScheduledEndAt).Value(end).
- TimePickerProps(vx.TimePickerProps{Format: "24hr", Scrollable: true}).
- ClearText(msgr.DateTimePickerClearText).OkText(msgr.DateTimePickerOkText),
- // h.RawHTML(fmt.Sprintf(`<vx-datetimepicker label="ScheduledEndAt" value="%s" v-field-name='"ScheduledEndAt"'> </vx-datetimepicker>`, end)),
- ).Cols(6),
- ),
- ),
- VCardActions(
- VSpacer(),
- updateBtn,
- ),
- ),
- ).MaxWidth("480px").
- Attr("v-model", "locals.schedulePublishDialog"),
- ).Init("{schedulePublishDialog:true}").VSlot("{locals}"),
- })
- return
- }
- }
- func schedulePublish(db *gorm.DB, mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue(presets.ParamID)
- obj := mb.NewModel()
- obj, err = mb.Editing().Fetcher(obj, paramID, ctx)
- if err != nil {
- return
- }
- err = pv.ScheduleEditSetterFunc(obj, nil, ctx)
- if err != nil {
- mb.Editing().UpdateOverlayContent(ctx, &r, obj, "", err)
- return
- }
- err = mb.Editing().Saver(obj, paramID, ctx)
- if err != nil {
- mb.Editing().UpdateOverlayContent(ctx, &r, obj, "", err)
- return
- }
- r.PushState = web.Location(nil)
- return
- }
- }
- func createNoteDialog(db *gorm.DB, mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue(presets.ParamID)
- okAction := web.Plaid().
- URL(mb.Info().ListingHref()).
- EventFunc(createNoteEvent).
- Query("resource_id", paramID).
- Query("resource_type", mb.Info().Label()).
- Query(presets.ParamOverlay, actions.Dialog).Go()
- r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
- Name: dialogPortalName,
- Body: web.Scope(
- VDialog(
- VCard(
- VCardTitle(h.Text("Note")),
- VCardText(
- VTextField().FieldName("Content").Value(""),
- ),
- VCardActions(
- VSpacer(),
- VBtn("Cancel").
- Depressed(true).
- Class("ml-2").
- On("click", "locals.createNoteDialog = false"),
- VBtn("OK").
- Color("primary").
- Depressed(true).
- Dark(true).
- Attr("@click", okAction),
- ),
- ),
- ).MaxWidth("420px").Attr("v-model", "locals.createNoteDialog"),
- ).Init("{createNoteDialog:true}").VSlot("{locals}"),
- })
- return
- }
- }
- func createNote(db *gorm.DB, mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- ri := ctx.R.FormValue("resource_id")
- rt := ctx.R.FormValue("resource_type")
- content := ctx.R.FormValue("Content")
- userID, creator := note.GetUserData(ctx)
- nt := note.QorNote{
- UserID: userID,
- Creator: creator,
- ResourceID: ri,
- ResourceType: rt,
- Content: content,
- }
- if err = db.Save(&nt).Error; err != nil {
- presets.ShowMessage(&r, err.Error(), "error")
- err = nil
- return
- }
- userNote := note.UserNote{UserID: userID, ResourceType: rt, ResourceID: ri}
- db.Where(userNote).FirstOrCreate(&userNote)
- var total int64
- db.Model(¬e.QorNote{}).Where("resource_type = ? AND resource_id = ?", rt, ri).Count(&total)
- db.Model(&userNote).UpdateColumn("Number", total)
- r.PushState = web.Location(nil)
- return
- }
- }
- func editSEODialog(db *gorm.DB, mb *presets.ModelBuilder, seoCollection *seo.Collection) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue(presets.ParamID)
- obj := mb.NewModel()
- obj, err = mb.Editing().Fetcher(obj, paramID, ctx)
- if err != nil {
- return
- }
- // msgr := i18n.MustGetModuleMessages(ctx.R, pv.I18nPublishKey, Messages_en_US).(*pv.Messages)
- cmsgr := i18n.MustGetModuleMessages(ctx.R, presets.CoreI18nModuleKey, Messages_en_US).(*presets.Messages)
- updateBtn := VBtn(cmsgr.Update).
- Color("primary").
- Attr(":disabled", "isFetching").
- Attr(":loading", "isFetching").
- Attr("@click", web.Plaid().
- EventFunc(updateSEOEvent).
- // Queries(queries).
- Query(presets.ParamID, paramID).
- // Query(presets.ParamOverlay, actions.Dialog).
- URL(mb.Info().ListingHref()).
- Go())
- ctx.R.Form.Set("openCustomizePanel", "0")
- seoForm := seoCollection.EditingComponentFunc(obj, nil, ctx)
- r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
- Name: dialogPortalName,
- Body: web.Scope(
- VDialog(
- VCard(
- VCardTitle(h.Text("")),
- VCardText(
- seoForm,
- ),
- VCardActions(
- VSpacer(),
- updateBtn,
- ),
- ),
- ).MaxWidth("650px").
- Attr("v-model", "locals.editSEODialog"),
- ).Init("{editSEODialog:true}").VSlot("{locals}"),
- })
- return
- }
- }
- func updateSEO(db *gorm.DB, mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue(presets.ParamID)
- obj := mb.NewModel()
- obj, err = mb.Editing().Fetcher(obj, paramID, ctx)
- if err != nil {
- return
- }
- err = seo.EditSetterFunc(obj, &presets.FieldContext{Name: "SEO"}, ctx)
- if err != nil {
- mb.Editing().UpdateOverlayContent(ctx, &r, obj, "", err)
- return
- }
- err = mb.Editing().Saver(obj, paramID, ctx)
- if err != nil {
- mb.Editing().UpdateOverlayContent(ctx, &r, obj, "", err)
- return
- }
- r.PushState = web.Location(nil)
- return
- }
- }
- func renameVersionDialog(mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- id := ctx.R.FormValue("rename_id")
- versionName := ctx.R.FormValue("version_name")
- okAction := web.Plaid().
- URL(mb.Info().ListingHref()).
- EventFunc(renameVersionEvent).
- Queries(ctx.Queries()).
- Query("rename_id", id).Go()
- r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
- Name: dialogPortalName,
- Body: web.Scope(
- VDialog(
- VCard(
- VCardTitle(h.Text("Version")),
- VCardText(
- VTextField().FieldName("VersionName").Value(versionName),
- ),
- VCardActions(
- VSpacer(),
- VBtn("Cancel").
- Depressed(true).
- Class("ml-2").
- On("click", "locals.renameVersionDialog = false"),
- VBtn("OK").
- Color("primary").
- Depressed(true).
- Dark(true).
- Attr("@click", "locals.renameVersionDialog = false; "+okAction),
- ),
- ),
- ).MaxWidth("420px").Attr("v-model", "locals.renameVersionDialog"),
- ).Init("{renameVersionDialog:true}").VSlot("{locals}"),
- })
- return
- }
- }
- func renameVersion(mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- paramID := ctx.R.FormValue("rename_id")
- obj := mb.NewModel()
- obj, err = mb.Editing().Fetcher(obj, paramID, ctx)
- if err != nil {
- return
- }
- name := ctx.R.FormValue("VersionName")
- if err = reflectutils.Set(obj, "Version.VersionName", name); err != nil {
- return
- }
- if err = mb.Editing().Saver(obj, paramID, ctx); err != nil {
- return
- }
- qs := ctx.Queries()
- delete(qs, "version_name")
- delete(qs, "rename_id")
- r.VarsScript = web.Plaid().URL(ctx.R.RequestURI).Queries(qs).EventFunc(actions.UpdateListingDialog).Go()
- return
- }
- }
- func deleteVersionDialog(mb *presets.ModelBuilder) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- id := ctx.R.FormValue("delete_id")
- versionName := ctx.R.FormValue("version_name")
- r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
- Name: presets.DeleteConfirmPortalName,
- Body: VDialog(
- VCard(
- VCardTitle(h.Text(fmt.Sprintf("Are you sure you want to delete %s?", versionName))),
- VCardActions(
- VSpacer(),
- VBtn("Cancel").
- Depressed(true).
- Class("ml-2").
- On("click", "vars.deleteConfirmation = false"),
- VBtn("Delete").
- Color("primary").
- Depressed(true).
- Dark(true).
- Attr("@click", web.Plaid().
- URL(mb.Info().ListingHref()).
- EventFunc(actions.DoDelete).
- Queries(ctx.Queries()).
- Query(presets.ParamInDialog, true).
- Query(presets.ParamID, id).Go()),
- ),
- ),
- ).MaxWidth("580px").
- Attr("v-model", "vars.deleteConfirmation").
- Attr(web.InitContextVars, `{deleteConfirmation: false}`),
- })
- r.VarsScript = "setTimeout(function(){ vars.deleteConfirmation = true }, 100)"
- return
- }
- }
- func (b *Builder) ConfigSharedContainer(pb *presets.Builder, db *gorm.DB) (pm *presets.ModelBuilder) {
- pm = pb.Model(&Container{}).URIName("shared_containers").Label("Shared Containers")
- pm.RegisterEventFunc(republishRelatedOnlinePagesEvent, republishRelatedOnlinePages(b.mb.Info().ListingHref()))
- listing := pm.Listing("DisplayName").SearchColumns("display_name")
- listing.RowMenu("").Empty()
- // ed := pm.Editing("SelectContainer")
- // ed.Field("SelectContainer").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- // var containers []h.HTMLComponent
- // for _, builder := range b.containerBuilders {
- // cover := builder.cover
- // if cover == "" {
- // cover = path.Join(b.prefix, b.imagesPrefix, strings.ReplaceAll(builder.name, " ", "")+".png")
- // }
- // containers = append(containers,
- // VCol(
- // VCard(
- // VImg().Src(cover).Height(200),
- // VCardActions(
- // VCardTitle(h.Text(builder.name)),
- // VSpacer(),
- // VBtn("Select").
- // Text(true).
- // Color("primary").Attr("@click",
- // web.Plaid().
- // EventFunc(actions.New).
- // URL(builder.GetModelBuilder().Info().ListingHref()).
- // Go()),
- // ),
- // ),
- // ).Cols(6),
- // )
- // }
- // return VSheet(
- // VContainer(
- // VRow(
- // containers...,
- // ),
- // ),
- // )
- // })
- if permB := pb.GetPermission(); permB != nil {
- permB.CreatePolicies(
- perm.PolicyFor(perm.Anybody).WhoAre(perm.Denied).ToDo(presets.PermCreate).On("*:shared_containers:*"),
- )
- }
- listing.Field("DisplayName").Label("Name")
- listing.SearchFunc(sharedContainerSearcher(db, pm))
- listing.CellWrapperFunc(func(cell h.MutableAttrHTMLComponent, id string, obj interface{}, dataTableID string) h.HTMLComponent {
- tdbind := cell
- c := obj.(*Container)
- tdbind.SetAttr("@click.self",
- web.Plaid().
- EventFunc(actions.Edit).
- URL(b.ContainerByName(c.ModelName).GetModelBuilder().Info().ListingHref()).
- Query(presets.ParamID, c.ModelID).
- Query(paramOpenFromSharedContainer, 1).
- Go()+fmt.Sprintf(`; vars.currEditingListItemID="%s-%d"`, dataTableID, c.ModelID))
- return tdbind
- })
- return
- }
- func (b *Builder) ConfigDemoContainer(pb *presets.Builder, db *gorm.DB) (pm *presets.ModelBuilder) {
- pm = pb.Model(&DemoContainer{}).URIName("demo_containers").Label("Demo Containers")
- pm.RegisterEventFunc("addDemoContainer", func(ctx *web.EventContext) (r web.EventResponse, err error) {
- modelID := ctx.QueryAsInt(presets.ParamOverlayUpdateID)
- modelName := ctx.R.FormValue("ModelName")
- locale, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- var existID uint
- {
- m := DemoContainer{}
- db.Where("model_name = ?", modelName).First(&m)
- existID = m.ID
- }
- db.Assign(DemoContainer{
- Model: gorm.Model{
- ID: existID,
- },
- ModelID: uint(modelID),
- }).FirstOrCreate(&DemoContainer{}, map[string]interface{}{
- "model_name": modelName,
- "locale_code": locale,
- })
- r.Reload = true
- return
- })
- listing := pm.Listing("ModelName").SearchColumns("ModelName")
- listing.Field("ModelName").Label("Name")
- ed := pm.Editing("SelectContainer").ActionsFunc(func(obj interface{}, ctx *web.EventContext) h.HTMLComponent { return nil })
- ed.Field("ModelName")
- ed.Field("ModelID")
- ed.Field("SelectContainer").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- locale, localizable := l10n.IsLocalizableFromCtx(ctx.R.Context())
- var demoContainers []DemoContainer
- db.Find(&demoContainers)
- var containers []h.HTMLComponent
- for _, builder := range b.containerBuilders {
- cover := builder.cover
- if cover == "" {
- cover = path.Join(b.prefix, b.imagesPrefix, strings.ReplaceAll(builder.name, " ", "")+".png")
- }
- c := VCol(
- VCard(
- VImg().Src(cover).Height(200),
- VCardActions(
- VCardTitle(h.Text(builder.name)),
- VSpacer(),
- VBtn("Select").
- Text(true).
- Color("primary").Attr("@click",
- web.Plaid().
- EventFunc(actions.New).
- URL(builder.GetModelBuilder().Info().ListingHref()).
- Query(presets.ParamOverlayAfterUpdateScript, web.POST().Query("ModelName", builder.name).EventFunc("addDemoContainer").Go()).
- Go()),
- ),
- ),
- ).Cols(6)
- var isExists bool
- var modelID uint
- for _, dc := range demoContainers {
- if dc.ModelName == builder.name {
- if localizable && dc.GetLocale() != locale {
- continue
- }
- isExists = true
- modelID = dc.ModelID
- break
- }
- }
- if isExists {
- c = VCol(
- VCard(
- VImg().Src(cover).Height(200),
- VCardActions(
- VCardTitle(h.Text(builder.name)),
- VSpacer(),
- VBtn("Edit").
- Text(true).
- Color("primary").Attr("@click",
- web.Plaid().
- EventFunc(actions.Edit).
- URL(builder.GetModelBuilder().Info().ListingHref()).
- Query(presets.ParamID, fmt.Sprint(modelID)).
- Go()),
- ),
- ),
- ).Cols(6)
- }
- containers = append(containers, c)
- }
- return VSheet(
- VContainer(
- VRow(
- containers...,
- ),
- ),
- )
- })
- listing.CellWrapperFunc(func(cell h.MutableAttrHTMLComponent, id string, obj interface{}, dataTableID string) h.HTMLComponent {
- tdbind := cell
- c := obj.(*DemoContainer)
- tdbind.SetAttr("@click.self",
- web.Plaid().
- EventFunc(actions.Edit).
- URL(b.ContainerByName(c.ModelName).GetModelBuilder().Info().ListingHref()).
- Query(presets.ParamID, c.ModelID).
- Go()+fmt.Sprintf(`; vars.currEditingListItemID="%s-%d"`, dataTableID, c.ModelID))
- return tdbind
- })
- ed.SaveFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) {
- this := obj.(*DemoContainer)
- err = db.Transaction(func(tx *gorm.DB) (inerr error) {
- if l10nON && strings.Contains(ctx.R.RequestURI, l10n_view.DoLocalize) {
- if inerr = b.createModelAfterLocalizeDemoContainer(tx, this); inerr != nil {
- panic(inerr)
- return
- }
- }
- if inerr = gorm2op.DataOperator(tx).Save(this, id, ctx); inerr != nil {
- return
- }
- return
- })
- return
- })
- return
- }
- func (b *Builder) ConfigTemplate(pb *presets.Builder, db *gorm.DB) (pm *presets.ModelBuilder) {
- pm = pb.Model(&Template{}).URIName("page_templates").Label("Templates")
- pm.Listing("ID", "Name", "Description")
- dp := pm.Detailing("Overview")
- dp.Field("Overview").ComponentFunc(templateSettings(db, pm))
- eb := pm.Editing("Name", "Description")
- eb.Field("EditContainer").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- m := obj.(*Template)
- if m.ID == 0 {
- return nil
- }
- var href = fmt.Sprintf("%s/editors/%d?tpl=1", b.prefix, m.ID)
- if locale, isLocalizable := l10n.IsLocalizableFromCtx(ctx.R.Context()); isLocalizable && l10nON {
- href = fmt.Sprintf("%s/editors/%d?tpl=1&locale=%s", b.prefix, m.ID, locale)
- }
- return h.Div(
- VBtn(msgr.EditPageContent).
- Target("_blank").
- Href(href).
- Color("secondary"),
- )
- })
- eb.SaveFunc(func(obj interface{}, id string, ctx *web.EventContext) (err error) {
- this := obj.(*Template)
- err = db.Transaction(func(tx *gorm.DB) (inerr error) {
- if inerr = gorm2op.DataOperator(tx).Save(obj, id, ctx); inerr != nil {
- return
- }
- if l10nON && strings.Contains(ctx.R.RequestURI, l10n_view.DoLocalize) {
- fromID := ctx.R.Context().Value(l10n_view.FromID).(string)
- fromLocale := ctx.R.Context().Value(l10n_view.FromLocale).(string)
- var fromIDInt int
- fromIDInt, err = strconv.Atoi(fromID)
- if err != nil {
- return
- }
- if inerr = b.localizeContainersToAnotherPage(tx, fromIDInt, "tpl", fromLocale, int(this.ID), "tpl", this.GetLocale()); inerr != nil {
- panic(inerr)
- return
- }
- return
- }
- return
- })
- return
- })
- return
- }
- func sharedContainerSearcher(db *gorm.DB, mb *presets.ModelBuilder) presets.SearchFunc {
- return func(obj interface{}, params *presets.SearchParams, ctx *web.EventContext) (r interface{}, totalCount int, err error) {
- ilike := "ILIKE"
- if db.Dialector.Name() == "sqlite" {
- ilike = "LIKE"
- }
- wh := db.Model(obj)
- if len(params.KeywordColumns) > 0 && len(params.Keyword) > 0 {
- var segs []string
- var args []interface{}
- for _, c := range params.KeywordColumns {
- segs = append(segs, fmt.Sprintf("%s %s ?", c, ilike))
- args = append(args, fmt.Sprintf("%%%s%%", params.Keyword))
- }
- wh = wh.Where(strings.Join(segs, " OR "), args...)
- }
- for _, cond := range params.SQLConditions {
- wh = wh.Where(strings.Replace(cond.Query, " ILIKE ", " "+ilike+" ", -1), cond.Args...)
- }
- locale, _ := l10n.IsLocalizableFromCtx(ctx.R.Context())
- var c int64
- if err = wh.Select("count(display_name)").Where("shared = true AND locale_code = ?", locale).Group("display_name,model_name,model_id").Count(&c).Error; err != nil {
- return
- }
- totalCount = int(c)
- if params.PerPage > 0 {
- wh = wh.Limit(int(params.PerPage))
- page := params.Page
- if page == 0 {
- page = 1
- }
- offset := (page - 1) * params.PerPage
- wh = wh.Offset(int(offset))
- }
- if err = wh.Select("display_name,model_name,model_id").Find(obj).Error; err != nil {
- return
- }
- r = reflect.ValueOf(obj).Elem().Interface()
- return
- }
- }
- func (b *Builder) ContainerByName(name string) (r *ContainerBuilder) {
- for _, cb := range b.containerBuilders {
- if cb.name == name {
- return cb
- }
- }
- panic(fmt.Sprintf("No container: %s", name))
- }
- type ContainerBuilder struct {
- builder *Builder
- name string
- mb *presets.ModelBuilder
- model interface{}
- modelType reflect.Type
- renderFunc RenderFunc
- cover string
- }
- func (b *Builder) RegisterContainer(name string) (r *ContainerBuilder) {
- r = &ContainerBuilder{
- name: name,
- builder: b,
- }
- b.containerBuilders = append(b.containerBuilders, r)
- return
- }
- func (b *ContainerBuilder) Model(m interface{}) *ContainerBuilder {
- b.model = m
- b.mb = b.builder.ps.Model(m)
- val := reflect.ValueOf(m)
- if val.Kind() != reflect.Ptr {
- panic("model pointer type required")
- }
- b.modelType = val.Elem().Type()
- b.configureRelatedOnlinePagesTab()
- return b
- }
- func (b *ContainerBuilder) URIName(uri string) *ContainerBuilder {
- if b.mb == nil {
- return b
- }
- b.mb.URIName(uri)
- return b
- }
- func (b *ContainerBuilder) GetModelBuilder() *presets.ModelBuilder {
- return b.mb
- }
- func (b *ContainerBuilder) RenderFunc(v RenderFunc) *ContainerBuilder {
- b.renderFunc = v
- return b
- }
- func (b *ContainerBuilder) Cover(v string) *ContainerBuilder {
- b.cover = v
- return b
- }
- func (b *ContainerBuilder) NewModel() interface{} {
- return reflect.New(b.modelType).Interface()
- }
- func (b *ContainerBuilder) ModelTypeName() string {
- return b.modelType.String()
- }
- func (b *ContainerBuilder) Editing(vs ...interface{}) *presets.EditingBuilder {
- return b.mb.Editing(vs...)
- }
- func (b *ContainerBuilder) configureRelatedOnlinePagesTab() {
- eb := b.mb.Editing()
- eb.AppendTabsPanelFunc(func(obj interface{}, ctx *web.EventContext) h.HTMLComponent {
- if ctx.R.FormValue(paramOpenFromSharedContainer) != "1" {
- return nil
- }
- pmsgr := i18n.MustGetModuleMessages(ctx.R, presets.CoreI18nModuleKey, Messages_en_US).(*presets.Messages)
- msgr := i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
- id, err := reflectutils.Get(obj, "id")
- if err != nil {
- panic(err)
- }
- pages := []*Page{}
- pageTable := (&Page{}).TableName()
- containerTable := (&Container{}).TableName()
- err = b.builder.db.Model(&Page{}).
- Joins(fmt.Sprintf(`inner join %s on
- %s.id = %s.page_id
- and %s.version = %s.page_version
- and %s.locale_code = %s.locale_code`,
- containerTable,
- pageTable, containerTable,
- pageTable, containerTable,
- pageTable, containerTable,
- )).
- // FIXME: add container locale condition after container supports l10n
- Where(fmt.Sprintf(`%s.status = ? and %s.model_id = ? and %s.model_name = ?`,
- pageTable,
- containerTable,
- containerTable,
- ), publish.StatusOnline, id, b.name).
- Group(fmt.Sprintf(`%s.id,%s.version,%s.locale_code`, pageTable, pageTable, pageTable)).
- Find(&pages).
- Error
- if err != nil {
- panic(err)
- }
- var pageIDs []string
- var pageListComps h.HTMLComponents
- for _, p := range pages {
- pid := p.PrimarySlug()
- pageIDs = append(pageIDs, pid)
- statusVar := fmt.Sprintf(`republish_status_%s`, strings.Replace(pid, "-", "_", -1))
- pageListComps = append(pageListComps, VListItem(
- h.Text(fmt.Sprintf("%s (%s)", p.Title, pid)),
- VSpacer(),
- VIcon(fmt.Sprintf(`{{vars.%s}}`, statusVar)),
- ).
- Dense(true).
- Attr(web.InitContextVars, fmt.Sprintf(`{%s: ""}`, statusVar)))
- }
- return h.Components(
- VTab(h.Text(msgr.RelatedOnlinePages)),
- VTabItem(
- h.If(len(pages) > 0,
- VList(pageListComps),
- h.Div(
- VSpacer(),
- VBtn(msgr.RepublishAllRelatedOnlinePages).
- Color("primary").
- Attr("@click",
- web.Plaid().
- EventFunc(presets.OpenConfirmDialog).
- Query(presets.ConfirmDialogConfirmEvent,
- web.Plaid().
- EventFunc(republishRelatedOnlinePagesEvent).
- Query("ids", strings.Join(pageIDs, ",")).
- Go(),
- ).
- Go(),
- ),
- ).Class("d-flex"),
- ).Else(
- h.Div(h.Text(pmsgr.ListingNoRecordToShow)).Class("text-center grey--text text--darken-2 mt-8"),
- ),
- ),
- )
- })
- }
- func republishRelatedOnlinePages(pageURL string) web.EventFunc {
- return func(ctx *web.EventContext) (r web.EventResponse, err error) {
- ids := strings.Split(ctx.R.FormValue("ids"), ",")
- for _, id := range ids {
- statusVar := fmt.Sprintf(`republish_status_%s`, strings.Replace(id, "-", "_", -1))
- web.AppendVarsScripts(&r,
- web.Plaid().
- URL(pageURL).
- EventFunc(views.RepublishEvent).
- Query("id", id).
- Query(views.ParamScriptAfterPublish, fmt.Sprintf(`vars.%s = "done"`, statusVar)).
- Query("status_var", statusVar).
- Go(),
- fmt.Sprintf(`vars.%s = "pending"`, statusVar),
- )
- }
- return r, nil
- }
- }
- func (b *Builder) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if strings.Index(r.RequestURI, b.prefix+"/preview") >= 0 {
- b.preview.ServeHTTP(w, r)
- return
- }
- if strings.Index(r.RequestURI, path.Join(b.prefix, b.imagesPrefix)) >= 0 {
- b.images.ServeHTTP(w, r)
- return
- }
- b.ps.ServeHTTP(w, r)
- }
|