events.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package views
  2. import (
  3. "context"
  4. "reflect"
  5. "github.com/qor5/admin/activity"
  6. "github.com/qor5/admin/l10n"
  7. "github.com/qor5/admin/presets"
  8. "github.com/qor5/admin/utils"
  9. v "github.com/qor5/ui/vuetify"
  10. "github.com/qor5/web"
  11. "github.com/sunfmin/reflectutils"
  12. h "github.com/theplant/htmlgo"
  13. "gorm.io/gorm"
  14. )
  15. const (
  16. Localize = "l10n_LocalizeEvent"
  17. DoLocalize = "l10n_DoLocalizeEvent"
  18. FromID = "l10n_DoLocalize_FromID"
  19. FromVersion = "l10n_DoLocalize_FromVersion"
  20. FromLocale = "l10n_DoLocalize_FromLocale"
  21. LocalizeFrom = "Localize From"
  22. LocalizeTo = "Localize To"
  23. )
  24. func registerEventFuncs(db *gorm.DB, mb *presets.ModelBuilder, lb *l10n.Builder, ab *activity.ActivityBuilder) {
  25. mb.RegisterEventFunc(Localize, localizeToConfirmation(db, lb, mb))
  26. mb.RegisterEventFunc(DoLocalize, doLocalizeTo(db, mb, lb, ab))
  27. }
  28. type SelectLocale struct {
  29. Label string
  30. Code string
  31. }
  32. func localizeToConfirmation(db *gorm.DB, lb *l10n.Builder, mb *presets.ModelBuilder) web.EventFunc {
  33. return func(ctx *web.EventContext) (r web.EventResponse, err error) {
  34. presetsMsgr := presets.MustGetMessages(ctx.R)
  35. paramID := ctx.R.FormValue(presets.ParamID)
  36. cs := mb.NewModel().(presets.SlugDecoder).PrimaryColumnValuesBySlug(paramID)
  37. id := cs["id"]
  38. fromLocale := lb.GetCorrectLocaleCode(ctx.R)
  39. var obj = mb.NewModelSlice()
  40. err = db.Distinct("locale_code").Where("id = ? AND locale_code <> ?", id, fromLocale).Find(obj).Error
  41. if err != nil {
  42. return
  43. }
  44. vo := reflect.ValueOf(obj).Elem()
  45. var existLocales []string
  46. for i := 0; i < vo.Len(); i++ {
  47. existLocales = append(existLocales, vo.Index(i).Elem().FieldByName("LocaleCode").String())
  48. }
  49. toLocales := lb.GetSupportLocaleCodesFromRequest(ctx.R)
  50. var selectLocales []SelectLocale
  51. for _, locale := range toLocales {
  52. if locale == fromLocale {
  53. continue
  54. }
  55. if !utils.Contains(existLocales, locale) || vo.Len() == 0 {
  56. selectLocales = append(selectLocales, SelectLocale{Label: MustGetTranslation(ctx.R, lb.GetLocaleLabel(locale)), Code: locale})
  57. }
  58. }
  59. r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
  60. Name: presets.DialogPortalName,
  61. Body: v.VDialog(
  62. v.VCard(
  63. v.VCardTitle(h.Text(MustGetTranslation(ctx.R, "Localize"))),
  64. v.VCardText(
  65. h.Div(
  66. h.Div(
  67. h.Div(
  68. h.Label(MustGetTranslation(ctx.R, "LocalizeFrom")).Class("v-label v-label--active theme--light").Style("left: 0px; right: auto; position: absolute;"),
  69. //h.Br(),
  70. h.Text(MustGetTranslation(ctx.R, lb.GetLocaleLabel(fromLocale))),
  71. ).Class("v-text-field__slot"),
  72. ).Class("v-input__slot"),
  73. ).Class("v-input v-input--is-label-active v-input--is-dirty theme--light v-text-field v-text-field--is-booted"),
  74. v.VSelect().FieldName("localize_to").
  75. Label(MustGetTranslation(ctx.R, "LocalizeTo")).
  76. Multiple(true).Chips(true).
  77. Items(selectLocales).
  78. ItemText("Label").
  79. ItemValue("Code"),
  80. ).Attr("style", "height: 200px;"),
  81. v.VCardActions(
  82. v.VSpacer(),
  83. v.VBtn(presetsMsgr.Cancel).
  84. Depressed(true).
  85. Class("ml-2").
  86. On("click", "vars.localizeConfirmation = false"),
  87. v.VBtn(presetsMsgr.OK).
  88. Color("primary").
  89. Depressed(true).
  90. Dark(true).
  91. Attr("@click", web.Plaid().
  92. EventFunc(DoLocalize).
  93. Query(presets.ParamID, paramID).
  94. Query("localize_from", fromLocale).
  95. URL(ctx.R.URL.Path).
  96. Go()),
  97. ),
  98. ),
  99. ).MaxWidth("600px").
  100. Attr("v-model", "vars.localizeConfirmation").
  101. Attr(web.InitContextVars, `{localizeConfirmation: false}`),
  102. })
  103. r.VarsScript = "setTimeout(function(){ vars.localizeConfirmation = true }, 100)"
  104. return
  105. }
  106. }
  107. func doLocalizeTo(db *gorm.DB, mb *presets.ModelBuilder, lb *l10n.Builder, ab *activity.ActivityBuilder) web.EventFunc {
  108. return func(ctx *web.EventContext) (r web.EventResponse, err error) {
  109. fromParamID := ctx.R.FormValue(presets.ParamID)
  110. cs := mb.NewModel().(presets.SlugDecoder).PrimaryColumnValuesBySlug(fromParamID)
  111. fromID := cs["id"]
  112. fromVersion := cs["version"]
  113. fromLocale := cs["locale_code"]
  114. to := make(map[string]struct{})
  115. for _, v := range ctx.R.Form["localize_to"] {
  116. for _, lc := range lb.GetSupportLocaleCodes() {
  117. if v == lc {
  118. to[v] = struct{}{}
  119. break
  120. }
  121. }
  122. }
  123. if len(to) == 0 {
  124. web.AppendVarsScripts(&r, "vars.localizeConfirmation = false")
  125. return
  126. }
  127. var fromObj = mb.NewModel()
  128. if err = utils.PrimarySluggerWhere(db, mb.NewModel(), fromParamID).First(fromObj).Error; err != nil {
  129. return
  130. }
  131. var toObjs []interface{}
  132. defer func(fromObj interface{}) {
  133. if ab == nil {
  134. return
  135. }
  136. if _, ok := ab.GetModelBuilder(fromObj); !ok {
  137. return
  138. }
  139. if len(toObjs) > 0 {
  140. if err = ab.AddCustomizedRecord(LocalizeFrom, false, ctx.R.Context(), fromObj); err != nil {
  141. return
  142. }
  143. for _, toObj := range toObjs {
  144. if err = ab.AddCustomizedRecord(LocalizeTo, false, ctx.R.Context(), toObj); err != nil {
  145. return
  146. }
  147. }
  148. }
  149. }(reflect.Indirect(reflect.ValueOf(fromObj)).Interface())
  150. me := mb.Editing()
  151. for toLocale, _ := range to {
  152. var toObj = mb.NewModel()
  153. var fakeToObj = fromObj
  154. if err = reflectutils.Set(fakeToObj, "LocaleCode", toLocale); err != nil {
  155. return
  156. }
  157. toParamID := fakeToObj.(presets.SlugEncoder).PrimarySlug()
  158. if err = utils.SetPrimaryKeys(fromObj, toObj, db, toParamID); err != nil {
  159. return
  160. }
  161. me.SetObjectFields(fromObj, toObj, &presets.FieldContext{
  162. ModelInfo: mb.Info(),
  163. }, false, presets.ContextModifiedIndexesBuilder(ctx).FromHidden(ctx.R), ctx)
  164. if me.Validator != nil {
  165. if vErr := me.Validator(toObj, ctx); vErr.HaveErrors() {
  166. me.UpdateOverlayContent(ctx, &r, toObj, "", &vErr)
  167. return
  168. }
  169. }
  170. newContext := context.WithValue(ctx.R.Context(), FromID, fromID)
  171. newContext = context.WithValue(newContext, FromVersion, fromVersion)
  172. newContext = context.WithValue(newContext, FromLocale, fromLocale)
  173. ctx.R = ctx.R.WithContext(newContext)
  174. if err = me.Saver(toObj, toParamID, ctx); err != nil {
  175. return
  176. }
  177. toObjs = append(toObjs, toObj)
  178. }
  179. presets.ShowMessage(&r, MustGetTranslation(ctx.R, "SuccessfullyLocalized"), "")
  180. // refresh current page
  181. r.Reload = true
  182. return
  183. }
  184. }