github.com/kotovmak/go-admin@v1.1.1/template/types/form.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"html"
     8  	"html/template"
     9  	"net/http"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/kotovmak/go-admin/context"
    16  	"github.com/kotovmak/go-admin/modules/config"
    17  	"github.com/kotovmak/go-admin/modules/constant"
    18  	"github.com/kotovmak/go-admin/modules/db"
    19  	"github.com/kotovmak/go-admin/modules/errors"
    20  	"github.com/kotovmak/go-admin/modules/file"
    21  	"github.com/kotovmak/go-admin/modules/language"
    22  	"github.com/kotovmak/go-admin/modules/logger"
    23  	"github.com/kotovmak/go-admin/modules/utils"
    24  	"github.com/kotovmak/go-admin/plugins/admin/modules"
    25  	"github.com/kotovmak/go-admin/plugins/admin/modules/form"
    26  	form2 "github.com/kotovmak/go-admin/template/types/form"
    27  )
    28  
    29  type FieldOption struct {
    30  	Text          string            `json:"text"`
    31  	Value         string            `json:"value"`
    32  	TextHTML      template.HTML     `json:"-"`
    33  	Selected      bool              `json:"-"`
    34  	SelectedLabel template.HTML     `json:"-"`
    35  	Extra         map[string]string `json:"-"`
    36  }
    37  
    38  type FieldOptions []FieldOption
    39  
    40  func (fo FieldOptions) Copy() FieldOptions {
    41  	newOptions := make(FieldOptions, len(fo))
    42  	copy(newOptions, fo)
    43  	return newOptions
    44  }
    45  
    46  func (fo FieldOptions) SetSelected(val interface{}, labels []template.HTML) FieldOptions {
    47  
    48  	if valArr, ok := val.([]string); ok {
    49  		for k := range fo {
    50  			text := fo[k].Text
    51  			if text == "" {
    52  				text = string(fo[k].TextHTML)
    53  			}
    54  			fo[k].Selected = utils.InArray(valArr, fo[k].Value) || utils.InArray(valArr, text)
    55  			if fo[k].Selected {
    56  				fo[k].SelectedLabel = labels[0]
    57  			} else {
    58  				fo[k].SelectedLabel = labels[1]
    59  			}
    60  		}
    61  	} else {
    62  		for k := range fo {
    63  			text := fo[k].Text
    64  			if text == "" {
    65  				text = string(fo[k].TextHTML)
    66  			}
    67  			fo[k].Selected = fo[k].Value == val || text == val
    68  			if fo[k].Selected {
    69  				fo[k].SelectedLabel = labels[0]
    70  			} else {
    71  				fo[k].SelectedLabel = labels[1]
    72  			}
    73  		}
    74  	}
    75  
    76  	return fo
    77  }
    78  
    79  func (fo FieldOptions) SetSelectedLabel(labels []template.HTML) FieldOptions {
    80  	for k := range fo {
    81  		if fo[k].Selected {
    82  			fo[k].SelectedLabel = labels[0]
    83  		} else {
    84  			fo[k].SelectedLabel = labels[1]
    85  		}
    86  	}
    87  	return fo
    88  }
    89  
    90  func (fo FieldOptions) Marshal() string {
    91  	if len(fo) == 0 {
    92  		return ""
    93  	}
    94  	eo, err := json.Marshal(fo)
    95  
    96  	if err != nil {
    97  		return ""
    98  	}
    99  
   100  	return string(eo)
   101  }
   102  
   103  type (
   104  	OptionInitFn              func(val FieldModel) FieldOptions
   105  	OptionArrInitFn           func(val FieldModel) []FieldOptions
   106  	OptionTableQueryProcessFn func(sql *db.SQL) *db.SQL
   107  	OptionProcessFn           func(options FieldOptions) FieldOptions
   108  
   109  	OptionTable struct {
   110  		Table          string
   111  		TextField      string
   112  		ValueField     string
   113  		QueryProcessFn OptionTableQueryProcessFn
   114  		ProcessFn      OptionProcessFn
   115  	}
   116  )
   117  
   118  // FormField is the form field with different options.
   119  type FormField struct {
   120  	Field          string          `json:"field"`
   121  	FieldClass     string          `json:"field_class"`
   122  	TypeName       db.DatabaseType `json:"type_name"`
   123  	Head           string          `json:"head"`
   124  	Foot           template.HTML   `json:"foot"`
   125  	FormType       form2.Type      `json:"form_type"`
   126  	FatherFormType form2.Type      `json:"father_form_type"`
   127  	FatherField    string          `json:"father_field"`
   128  
   129  	RowWidth int
   130  	RowFlag  uint8
   131  
   132  	Default                template.HTML  `json:"default"`
   133  	DefaultArr             interface{}    `json:"default_arr"`
   134  	Value                  template.HTML  `json:"value"`
   135  	Value2                 string         `json:"value_2"`
   136  	ValueArr               []string       `json:"value_arr"`
   137  	Value2Arr              []string       `json:"value_2_arr"`
   138  	Options                FieldOptions   `json:"options"`
   139  	OptionsArr             []FieldOptions `json:"options_arr"`
   140  	DefaultOptionDelimiter string         `json:"default_option_delimiter"`
   141  	Label                  template.HTML  `json:"label"`
   142  	HideLabel              bool           `json:"hide_label"`
   143  
   144  	Placeholder string `json:"placeholder"`
   145  
   146  	CustomContent template.HTML `json:"custom_content"`
   147  	CustomJs      template.JS   `json:"custom_js"`
   148  	CustomCss     template.CSS  `json:"custom_css"`
   149  
   150  	Editable         bool `json:"editable"`
   151  	NotAllowEdit     bool `json:"not_allow_edit"`
   152  	NotAllowAdd      bool `json:"not_allow_add"`
   153  	DisplayButNotAdd bool `json:"display_but_not_add"`
   154  	Must             bool `json:"must"`
   155  	Hide             bool `json:"hide"`
   156  	CreateHide       bool `json:"create_hide"`
   157  	EditHide         bool `json:"edit_hide"`
   158  
   159  	Width int `json:"width"`
   160  
   161  	InputWidth int `json:"input_width"`
   162  	HeadWidth  int `json:"head_width"`
   163  
   164  	Joins Joins `json:"-"`
   165  
   166  	Divider      bool   `json:"divider"`
   167  	DividerTitle string `json:"divider_title"`
   168  
   169  	HelpMsg template.HTML `json:"help_msg"`
   170  
   171  	TableFields FormFields
   172  
   173  	Style  template.HTMLAttr `json:"style"`
   174  	NoIcon bool              `json:"no_icon"`
   175  
   176  	OptionExt       template.JS     `json:"option_ext"`
   177  	OptionExt2      template.JS     `json:"option_ext_2"`
   178  	OptionInitFn    OptionInitFn    `json:"-"`
   179  	OptionArrInitFn OptionArrInitFn `json:"-"`
   180  	OptionTable     OptionTable     `json:"-"`
   181  
   182  	FieldDisplay `json:"-"`
   183  	PostFilterFn PostFieldFilterFn `json:"-"`
   184  }
   185  
   186  func (f *FormField) GetRawValue(columns []string, v interface{}) string {
   187  	isJSON := len(columns) == 0
   188  	return modules.AorB(isJSON || modules.InArray(columns, f.Field),
   189  		db.GetValueFromDatabaseType(f.TypeName, v, isJSON).String(), "")
   190  }
   191  
   192  func (f *FormField) UpdateValue(id, val string, res map[string]interface{}, sql *db.SQL) *FormField {
   193  	return f.updateValue(id, val, res, PostTypeUpdate, sql)
   194  }
   195  
   196  func (f *FormField) UpdateDefaultValue(sql *db.SQL) *FormField {
   197  	f.Value = f.Default
   198  	return f.updateValue("", string(f.Value), make(map[string]interface{}), PostTypeCreate, sql)
   199  }
   200  
   201  func (f *FormField) setOptionsFromSQL(sql *db.SQL) {
   202  	if sql != nil && f.OptionTable.Table != "" && len(f.Options) == 0 {
   203  
   204  		sql.Table(f.OptionTable.Table).Select(f.OptionTable.ValueField, f.OptionTable.TextField)
   205  
   206  		if f.OptionTable.QueryProcessFn != nil {
   207  			f.OptionTable.QueryProcessFn(sql)
   208  		}
   209  
   210  		queryRes, err := sql.All()
   211  		if err == nil {
   212  			for _, item := range queryRes {
   213  				value := item[f.OptionTable.ValueField]
   214  				typeStr := reflect.TypeOf(value).String()
   215  				if typeStr == "[]uint8" {
   216  					f.Options = append(f.Options, FieldOption{
   217  						Value: fmt.Sprintf("%v", string(value.([]uint8))),
   218  						Text:  fmt.Sprintf("%v", item[f.OptionTable.TextField]),
   219  					})
   220  				} else {
   221  					f.Options = append(f.Options, FieldOption{
   222  						Value: fmt.Sprintf("%v", value),
   223  						Text:  fmt.Sprintf("%v", item[f.OptionTable.TextField]),
   224  					})
   225  				}
   226  			}
   227  		}
   228  
   229  		if f.OptionTable.ProcessFn != nil {
   230  			f.Options = f.OptionTable.ProcessFn(f.Options)
   231  		}
   232  	}
   233  }
   234  
   235  func (f *FormField) isBelongToATable() bool {
   236  	return f.FatherField != "" && f.FatherFormType.IsTable()
   237  }
   238  
   239  func (f *FormField) isNotBelongToATable() bool {
   240  	return f.FatherField == "" && !f.FatherFormType.IsTable()
   241  }
   242  
   243  func (f *FormField) allowAdd() bool {
   244  	return !f.NotAllowAdd
   245  }
   246  
   247  func (f *FormField) updateValue(id, val string, res map[string]interface{}, typ PostType, sql *db.SQL) *FormField {
   248  
   249  	m := FieldModel{
   250  		ID:       id,
   251  		Value:    val,
   252  		Row:      res,
   253  		PostType: typ,
   254  	}
   255  
   256  	if f.isBelongToATable() {
   257  		if f.FormType.IsSelect() {
   258  			if len(f.OptionsArr) == 0 && f.OptionArrInitFn != nil {
   259  				f.OptionsArr = f.OptionArrInitFn(m)
   260  				for i := 0; i < len(f.OptionsArr); i++ {
   261  					f.OptionsArr[i] = f.OptionsArr[i].SetSelectedLabel(f.FormType.SelectedLabel())
   262  				}
   263  			} else {
   264  
   265  				f.setOptionsFromSQL(sql)
   266  
   267  				if f.FormType.IsSingleSelect() {
   268  					values := f.ToDisplayStringArray(m)
   269  					f.OptionsArr = make([]FieldOptions, len(values))
   270  					for k, value := range values {
   271  						f.OptionsArr[k] = f.Options.Copy().SetSelected(value, f.FormType.SelectedLabel())
   272  					}
   273  				} else {
   274  					values := f.ToDisplayStringArrayArray(m)
   275  					f.OptionsArr = make([]FieldOptions, len(values))
   276  					for k, value := range values {
   277  						f.OptionsArr[k] = f.Options.Copy().SetSelected(value, f.FormType.SelectedLabel())
   278  					}
   279  				}
   280  			}
   281  		} else {
   282  			f.ValueArr = f.ToDisplayStringArray(m)
   283  		}
   284  	} else {
   285  		if f.FormType.IsSelect() {
   286  			if len(f.Options) == 0 && f.OptionInitFn != nil {
   287  				f.Options = f.OptionInitFn(m).SetSelectedLabel(f.FormType.SelectedLabel())
   288  			} else {
   289  				f.setOptionsFromSQL(sql)
   290  				f.Options.SetSelected(f.ToDisplay(m), f.FormType.SelectedLabel())
   291  			}
   292  		} else if f.FormType.IsArray() {
   293  			f.ValueArr = f.ToDisplayStringArray(m)
   294  		} else {
   295  			f.Value = f.ToDisplayHTML(m)
   296  			if f.FormType.IsFile() {
   297  				if f.Value != template.HTML("") {
   298  					f.Value2 = config.GetStore().URL(string(f.Value))
   299  				}
   300  			}
   301  		}
   302  	}
   303  
   304  	return f
   305  }
   306  
   307  func (f *FormField) FillCustomContent() *FormField {
   308  	// TODO: optimize
   309  	if f.CustomContent != "" {
   310  		f.CustomContent = template.HTML(f.fillCustom(string(f.CustomContent)))
   311  	}
   312  	if f.CustomJs != "" {
   313  		f.CustomJs = template.JS(f.fillCustom(string(f.CustomJs)))
   314  	}
   315  	if f.CustomCss != "" {
   316  		f.CustomCss = template.CSS(f.fillCustom(string(f.CustomCss)))
   317  	}
   318  	return f
   319  }
   320  
   321  func (f *FormField) fillCustom(src string) string {
   322  	t := template.New("custom")
   323  	t, err := t.Parse(src)
   324  	if err != nil {
   325  		logger.Error(err)
   326  		return ""
   327  	}
   328  	buf := new(bytes.Buffer)
   329  	err = t.Execute(buf, f)
   330  	if err != nil {
   331  		logger.Error(err)
   332  		return ""
   333  	}
   334  	return buf.String()
   335  }
   336  
   337  // FormPanel
   338  type FormPanel struct {
   339  	FieldList         FormFields `json:"field_list"`
   340  	curFieldListIndex int
   341  
   342  	// Warn: may be deprecated in the future. `json:""
   343  	TabGroups  TabGroups  `json:"tab_groups"`
   344  	TabHeaders TabHeaders `json:"tab_headers"`
   345  
   346  	Table       string `json:"table"`
   347  	Title       string `json:"title"`
   348  	Description string `json:"description"`
   349  
   350  	Validator    FormPostFn       `json:"validator"`
   351  	PostHook     FormPostFn       `json:"post_hook"`
   352  	PreProcessFn FormPreProcessFn `json:"pre_process_fn"`
   353  
   354  	Callbacks Callbacks `json:"callbacks"`
   355  
   356  	primaryKey primaryKey
   357  
   358  	UpdateFn FormPostFn `json:"update_fn"`
   359  	InsertFn FormPostFn `json:"insert_fn"`
   360  
   361  	IsHideContinueEditCheckBox bool `json:"is_hide_continue_edit_check_box"`
   362  	IsHideContinueNewCheckBox  bool `json:"is_hide_continue_new_check_box"`
   363  	IsHideResetButton          bool `json:"is_hide_reset_button"`
   364  	IsHideBackButton           bool `json:"is_hide_back_button"`
   365  
   366  	Layout form2.Layout `json:"layout"`
   367  
   368  	HTMLContent template.HTML `json:"html_content"`
   369  
   370  	Header template.HTML `json:"header"`
   371  
   372  	InputWidth int `json:"input_width"`
   373  	HeadWidth  int `json:"head_width"`
   374  
   375  	FormNewTitle    template.HTML `json:"form_new_title"`
   376  	FormNewBtnWord  template.HTML `json:"form_new_btn_word"`
   377  	FormEditTitle   template.HTML `json:"form_edit_title"`
   378  	FormEditBtnWord template.HTML `json:"form_edit_btn_word"`
   379  
   380  	Ajax          bool        `json:"ajax"`
   381  	AjaxSuccessJS template.JS `json:"ajax_success_js"`
   382  	AjaxErrorJS   template.JS `json:"ajax_error_js"`
   383  
   384  	Responder Responder `json:"responder"`
   385  
   386  	Wrapper ContentWrapper `json:"wrapper"`
   387  
   388  	HideSideBar bool `json:"hide_side_bar"`
   389  
   390  	processChains DisplayProcessFnChains
   391  
   392  	HeaderHtml template.HTML `json:"header_html"`
   393  	FooterHtml template.HTML `json:"footer_html"`
   394  
   395  	PageError     errors.PageError `json:"page_error"`
   396  	PageErrorHTML template.HTML    `json:"page_error_html"`
   397  
   398  	NoCompress bool `json:"no_compress"`
   399  }
   400  
   401  type Responder func(ctx *context.Context)
   402  
   403  func NewFormPanel() *FormPanel {
   404  	return &FormPanel{
   405  		curFieldListIndex: -1,
   406  		Callbacks:         make(Callbacks, 0),
   407  		Layout:            form2.LayoutDefault,
   408  		FormNewTitle:      "New",
   409  		FormEditTitle:     "Edit",
   410  		FormNewBtnWord:    language.GetFromHtml("Save"),
   411  		FormEditBtnWord:   language.GetFromHtml("Save"),
   412  	}
   413  }
   414  
   415  func (f *FormPanel) AddLimitFilter(limit int) *FormPanel {
   416  	f.processChains = addLimit(limit, f.processChains)
   417  	return f
   418  }
   419  
   420  func (f *FormPanel) AddTrimSpaceFilter() *FormPanel {
   421  	f.processChains = addTrimSpace(f.processChains)
   422  	return f
   423  }
   424  
   425  func (f *FormPanel) AddSubstrFilter(start int, end int) *FormPanel {
   426  	f.processChains = addSubstr(start, end, f.processChains)
   427  	return f
   428  }
   429  
   430  func (f *FormPanel) AddToTitleFilter() *FormPanel {
   431  	f.processChains = addToTitle(f.processChains)
   432  	return f
   433  }
   434  
   435  func (f *FormPanel) AddToUpperFilter() *FormPanel {
   436  	f.processChains = addToUpper(f.processChains)
   437  	return f
   438  }
   439  
   440  func (f *FormPanel) AddToLowerFilter() *FormPanel {
   441  	f.processChains = addToLower(f.processChains)
   442  	return f
   443  }
   444  
   445  func (f *FormPanel) AddXssFilter() *FormPanel {
   446  	f.processChains = addXssFilter(f.processChains)
   447  	return f
   448  }
   449  
   450  func (f *FormPanel) AddXssJsFilter() *FormPanel {
   451  	f.processChains = addXssJsFilter(f.processChains)
   452  	return f
   453  }
   454  
   455  func (f *FormPanel) SetPrimaryKey(name string, typ db.DatabaseType) *FormPanel {
   456  	f.primaryKey = primaryKey{Name: name, Type: typ}
   457  	return f
   458  }
   459  
   460  func (f *FormPanel) HideContinueEditCheckBox() *FormPanel {
   461  	f.IsHideContinueEditCheckBox = true
   462  	return f
   463  }
   464  
   465  func (f *FormPanel) HideContinueNewCheckBox() *FormPanel {
   466  	f.IsHideContinueNewCheckBox = true
   467  	return f
   468  }
   469  
   470  func (f *FormPanel) HideResetButton() *FormPanel {
   471  	f.IsHideResetButton = true
   472  	return f
   473  }
   474  
   475  func (f *FormPanel) HideBackButton() *FormPanel {
   476  	f.IsHideBackButton = true
   477  	return f
   478  }
   479  
   480  func (f *FormPanel) AddFieldTr(ctx *context.Context, head, field string, filedType db.DatabaseType, formType form2.Type) *FormPanel {
   481  	return f.AddFieldWithTranslation(ctx, head, field, filedType, formType)
   482  }
   483  
   484  func (f *FormPanel) AddFieldWithTranslation(ctx *context.Context, head, field string, filedType db.DatabaseType,
   485  	formType form2.Type) *FormPanel {
   486  	return f.AddField(language.GetWithLang(head, ctx.Lang()), field, filedType, formType)
   487  }
   488  
   489  func (f *FormPanel) AddField(head, field string, filedType db.DatabaseType, formType form2.Type) *FormPanel {
   490  
   491  	f.FieldList = append(f.FieldList, FormField{
   492  		Head:        head,
   493  		Field:       field,
   494  		FieldClass:  field,
   495  		TypeName:    filedType,
   496  		Editable:    true,
   497  		Hide:        false,
   498  		TableFields: make(FormFields, 0),
   499  		Placeholder: language.Get("input") + " " + head,
   500  		FormType:    formType,
   501  		FieldDisplay: FieldDisplay{
   502  			Display: func(value FieldModel) interface{} {
   503  				return value.Value
   504  			},
   505  			DisplayProcessChains: chooseDisplayProcessChains(f.processChains),
   506  		},
   507  	})
   508  	f.curFieldListIndex++
   509  
   510  	// Set default options of different form type
   511  	op1, op2, js := formType.GetDefaultOptions(field)
   512  	f.FieldOptionExt(op1)
   513  	f.FieldOptionExt2(op2)
   514  	f.FieldOptionExtJS(js)
   515  
   516  	// Set default Display Filter Function of different form type
   517  	setDefaultDisplayFnOfFormType(f, formType)
   518  
   519  	if formType.IsEditor() {
   520  		f.NoCompress = true
   521  	}
   522  
   523  	return f
   524  }
   525  
   526  type AddFormFieldFn func(panel *FormPanel)
   527  
   528  func (f *FormPanel) AddTable(head, field string, addFields AddFormFieldFn) *FormPanel {
   529  	index := f.curFieldListIndex
   530  	addFields(f)
   531  	for i := index + 1; i <= f.curFieldListIndex; i++ {
   532  		f.FieldList[i].FatherFormType = form2.Table
   533  		f.FieldList[i].FatherField = field
   534  	}
   535  	fields := make(FormFields, f.curFieldListIndex-index)
   536  	copy(fields, f.FieldList[index+1:f.curFieldListIndex+1])
   537  	f.FieldList = append(f.FieldList, FormField{
   538  		Head:        head,
   539  		Field:       field,
   540  		FieldClass:  field,
   541  		TypeName:    db.Varchar,
   542  		Editable:    true,
   543  		Hide:        false,
   544  		TableFields: fields,
   545  		FormType:    form2.Table,
   546  		FieldDisplay: FieldDisplay{
   547  			Display: func(value FieldModel) interface{} {
   548  				return value.Value
   549  			},
   550  			DisplayProcessChains: chooseDisplayProcessChains(f.processChains),
   551  		},
   552  	})
   553  	f.curFieldListIndex++
   554  	return f
   555  }
   556  
   557  func (f *FormPanel) AddRow(addFields AddFormFieldFn) *FormPanel {
   558  	index := f.curFieldListIndex
   559  	addFields(f)
   560  	if f.curFieldListIndex != index+1 {
   561  		for i := index + 1; i <= f.curFieldListIndex; i++ {
   562  			if i == index+1 {
   563  				f.FieldList[i].RowFlag = 1
   564  			} else if i == f.curFieldListIndex {
   565  				f.FieldList[i].RowFlag = 2
   566  			} else {
   567  				f.FieldList[i].RowFlag = 3
   568  			}
   569  		}
   570  	}
   571  	return f
   572  }
   573  
   574  // Field attribute setting functions
   575  // ====================================================
   576  
   577  func (f *FormPanel) FieldDisplay(filter FieldFilterFn) *FormPanel {
   578  	f.FieldList[f.curFieldListIndex].Display = filter
   579  	return f
   580  }
   581  
   582  func (f *FormPanel) SetTable(table string) *FormPanel {
   583  	f.Table = table
   584  	return f
   585  }
   586  
   587  func (f *FormPanel) FieldMust() *FormPanel {
   588  	f.FieldList[f.curFieldListIndex].Must = true
   589  	return f
   590  }
   591  
   592  func (f *FormPanel) FieldHide() *FormPanel {
   593  	f.FieldList[f.curFieldListIndex].Hide = true
   594  	return f
   595  }
   596  
   597  func (f *FormPanel) FieldPlaceholder(placeholder string) *FormPanel {
   598  	f.FieldList[f.curFieldListIndex].Placeholder = placeholder
   599  	return f
   600  }
   601  
   602  func (f *FormPanel) FieldWidth(width int) *FormPanel {
   603  	f.FieldList[f.curFieldListIndex].Width = width
   604  	return f
   605  }
   606  
   607  func (f *FormPanel) FieldInputWidth(width int) *FormPanel {
   608  	f.FieldList[f.curFieldListIndex].InputWidth = width
   609  	return f
   610  }
   611  
   612  func (f *FormPanel) FieldHeadWidth(width int) *FormPanel {
   613  	f.FieldList[f.curFieldListIndex].HeadWidth = width
   614  	return f
   615  }
   616  
   617  func (f *FormPanel) FieldRowWidth(width int) *FormPanel {
   618  	f.FieldList[f.curFieldListIndex].RowWidth = width
   619  	return f
   620  }
   621  
   622  func (f *FormPanel) FieldHideLabel() *FormPanel {
   623  	f.FieldList[f.curFieldListIndex].HideLabel = true
   624  	return f
   625  }
   626  
   627  func (f *FormPanel) FieldFoot(foot template.HTML) *FormPanel {
   628  	f.FieldList[f.curFieldListIndex].Foot = foot
   629  	return f
   630  }
   631  
   632  func (f *FormPanel) FieldDivider(title ...string) *FormPanel {
   633  	f.FieldList[f.curFieldListIndex].Divider = true
   634  	if len(title) > 0 {
   635  		f.FieldList[f.curFieldListIndex].DividerTitle = title[0]
   636  	}
   637  	return f
   638  }
   639  
   640  func (f *FormPanel) FieldHelpMsg(s template.HTML) *FormPanel {
   641  	f.FieldList[f.curFieldListIndex].HelpMsg = s
   642  	return f
   643  }
   644  
   645  func (f *FormPanel) FieldOptionInitFn(fn OptionInitFn) *FormPanel {
   646  	f.FieldList[f.curFieldListIndex].OptionInitFn = fn
   647  	return f
   648  }
   649  
   650  func (f *FormPanel) FieldOptionExt(m map[string]interface{}) *FormPanel {
   651  
   652  	if m == nil {
   653  		return f
   654  	}
   655  
   656  	if f.FieldList[f.curFieldListIndex].FormType.IsCode() {
   657  		f.FieldList[f.curFieldListIndex].OptionExt = template.JS(fmt.Sprintf(`
   658  	theme = "%s";
   659  	font_size = %s;
   660  	language = "%s";
   661  	options = %s;
   662  `, m["theme"], m["font_size"], m["language"], m["options"]))
   663  		return f
   664  	}
   665  
   666  	m = f.FieldList[f.curFieldListIndex].FormType.FixOptions(m)
   667  
   668  	s, _ := json.Marshal(m)
   669  
   670  	if f.FieldList[f.curFieldListIndex].OptionExt != template.JS("") {
   671  		ss := string(f.FieldList[f.curFieldListIndex].OptionExt)
   672  		ss = strings.Replace(ss, "}", "", strings.Count(ss, "}"))
   673  		ss = strings.TrimRight(ss, " ")
   674  		ss += ","
   675  		f.FieldList[f.curFieldListIndex].OptionExt = template.JS(ss) + template.JS(strings.Replace(string(s), "{", "", 1))
   676  	} else {
   677  		f.FieldList[f.curFieldListIndex].OptionExt = template.JS(string(s))
   678  	}
   679  
   680  	return f
   681  }
   682  
   683  func (f *FormPanel) FieldOptionExt2(m map[string]interface{}) *FormPanel {
   684  
   685  	if m == nil {
   686  		return f
   687  	}
   688  
   689  	m = f.FieldList[f.curFieldListIndex].FormType.FixOptions(m)
   690  
   691  	s, _ := json.Marshal(m)
   692  
   693  	if f.FieldList[f.curFieldListIndex].OptionExt2 != template.JS("") {
   694  		ss := string(f.FieldList[f.curFieldListIndex].OptionExt2)
   695  		ss = strings.Replace(ss, "}", "", strings.Count(ss, "}"))
   696  		ss = strings.TrimRight(ss, " ")
   697  		ss += ","
   698  		f.FieldList[f.curFieldListIndex].OptionExt2 = template.JS(ss) + template.JS(strings.Replace(string(s), "{", "", 1))
   699  	} else {
   700  		f.FieldList[f.curFieldListIndex].OptionExt2 = template.JS(string(s))
   701  	}
   702  
   703  	return f
   704  }
   705  
   706  func (f *FormPanel) FieldOptionExtJS(js template.JS) *FormPanel {
   707  	if js != template.JS("") {
   708  		f.FieldList[f.curFieldListIndex].OptionExt = js
   709  	}
   710  	return f
   711  }
   712  
   713  func (f *FormPanel) FieldOptionExtJS2(js template.JS) *FormPanel {
   714  	f.FieldList[f.curFieldListIndex].OptionExt2 = js
   715  	return f
   716  }
   717  
   718  func (f *FormPanel) FieldEnableFileUpload(data ...interface{}) *FormPanel {
   719  
   720  	url := f.OperationURL("/file/upload")
   721  
   722  	if len(data) > 0 {
   723  		url = data[0].(string)
   724  	}
   725  
   726  	field := f.FieldList[f.curFieldListIndex].Field
   727  
   728  	f.FieldList[f.curFieldListIndex].OptionExt = template.JS(fmt.Sprintf(`
   729  	%seditor.customConfig.uploadImgServer = '%s';
   730  	%seditor.customConfig.uploadImgMaxSize = 3 * 1024 * 1024;
   731  	%seditor.customConfig.uploadImgMaxLength = 5;
   732  	%seditor.customConfig.uploadFileName = 'file';
   733  `, field, url, field, field, field))
   734  
   735  	var fileUploadHandler context.Handler
   736  	if len(data) > 1 {
   737  		fileUploadHandler = data[1].(context.Handler)
   738  	} else {
   739  		fileUploadHandler = func(ctx *context.Context) {
   740  			if len(ctx.Request.MultipartForm.File) == 0 {
   741  				ctx.JSON(http.StatusOK, map[string]interface{}{
   742  					"errno": 400,
   743  				})
   744  				return
   745  			}
   746  
   747  			err := file.GetFileEngine(config.GetFileUploadEngine().Name).Upload(ctx.Request.MultipartForm)
   748  			if err != nil {
   749  				ctx.JSON(http.StatusOK, map[string]interface{}{
   750  					"errno": 500,
   751  				})
   752  				return
   753  			}
   754  
   755  			var imgPath = make([]string, len(ctx.Request.MultipartForm.Value["file"]))
   756  			for i, path := range ctx.Request.MultipartForm.Value["file"] {
   757  				imgPath[i] = config.GetStore().URL(path)
   758  			}
   759  
   760  			ctx.JSON(http.StatusOK, map[string]interface{}{
   761  				"errno": 0,
   762  				"data":  imgPath,
   763  			})
   764  		}
   765  	}
   766  
   767  	f.Callbacks = f.Callbacks.AddCallback(context.Node{
   768  		Path:     url,
   769  		Method:   "post",
   770  		Value:    map[string]interface{}{constant.ContextNodeNeedAuth: 1},
   771  		Handlers: []context.Handler{fileUploadHandler},
   772  	})
   773  
   774  	return f
   775  }
   776  
   777  func (f *FormPanel) FieldDefault(def string) *FormPanel {
   778  	f.FieldList[f.curFieldListIndex].Default = template.HTML(def)
   779  	return f
   780  }
   781  
   782  // FieldNotAllowEdit means when update record the field can not be edited but will still be displayed and submitted.
   783  // Deprecated: Use FieldDisplayButCanNotEditWhenUpdate instead.
   784  func (f *FormPanel) FieldNotAllowEdit() *FormPanel {
   785  	f.FieldList[f.curFieldListIndex].Editable = false
   786  	return f
   787  }
   788  
   789  // FieldDisplayButCanNotEditWhenUpdate means when update record the field can not be edited but will still be displayed and submitted.
   790  func (f *FormPanel) FieldDisplayButCanNotEditWhenUpdate() *FormPanel {
   791  	f.FieldList[f.curFieldListIndex].Editable = false
   792  	return f
   793  }
   794  
   795  // FieldDisableWhenUpdate means when update record the field can not be edited, displayed and submitted.
   796  func (f *FormPanel) FieldDisableWhenUpdate() *FormPanel {
   797  	f.FieldList[f.curFieldListIndex].NotAllowEdit = true
   798  	return f
   799  }
   800  
   801  // FieldNotAllowAdd means when create record the field can not be edited, displayed and submitted.
   802  // Deprecated: Use FieldDisableWhenCreate instead.
   803  func (f *FormPanel) FieldNotAllowAdd() *FormPanel {
   804  	f.FieldList[f.curFieldListIndex].NotAllowAdd = true
   805  	return f
   806  }
   807  
   808  // FieldDisableWhenCreate means when create record the field can not be edited, displayed and submitted.
   809  func (f *FormPanel) FieldDisableWhenCreate() *FormPanel {
   810  	f.FieldList[f.curFieldListIndex].NotAllowAdd = true
   811  	return f
   812  }
   813  
   814  // FieldDisplayButCanNotEditWhenCreate means when create record the field can not be edited but will still be displayed and submitted.
   815  func (f *FormPanel) FieldDisplayButCanNotEditWhenCreate() *FormPanel {
   816  	f.FieldList[f.curFieldListIndex].DisplayButNotAdd = true
   817  	return f
   818  }
   819  
   820  // FieldHideWhenCreate means when create record the field can not be edited and displayed, but will be submitted.
   821  func (f *FormPanel) FieldHideWhenCreate() *FormPanel {
   822  	f.FieldList[f.curFieldListIndex].CreateHide = true
   823  	return f
   824  }
   825  
   826  // FieldHideWhenUpdate means when update record the field can not be edited and displayed, but will be submitted.
   827  func (f *FormPanel) FieldHideWhenUpdate() *FormPanel {
   828  	f.FieldList[f.curFieldListIndex].EditHide = true
   829  	return f
   830  }
   831  
   832  func (f *FormPanel) FieldFormType(formType form2.Type) *FormPanel {
   833  	f.FieldList[f.curFieldListIndex].FormType = formType
   834  	return f
   835  }
   836  
   837  func (f *FormPanel) FieldValue(value string) *FormPanel {
   838  	f.FieldList[f.curFieldListIndex].Value = template.HTML(value)
   839  	return f
   840  }
   841  
   842  func (f *FormPanel) FieldOptionsFromTable(table, textFieldName, valueFieldName string, process ...OptionTableQueryProcessFn) *FormPanel {
   843  	var fn OptionTableQueryProcessFn
   844  	if len(process) > 0 {
   845  		fn = process[0]
   846  	}
   847  	f.FieldList[f.curFieldListIndex].OptionTable = OptionTable{
   848  		Table:          table,
   849  		TextField:      textFieldName,
   850  		ValueField:     valueFieldName,
   851  		QueryProcessFn: fn,
   852  	}
   853  	return f
   854  }
   855  
   856  func (f *FormPanel) FieldOptionsTableProcessFn(fn OptionProcessFn) *FormPanel {
   857  	f.FieldList[f.curFieldListIndex].OptionTable.ProcessFn = fn
   858  	return f
   859  }
   860  
   861  func (f *FormPanel) FieldOptions(options FieldOptions) *FormPanel {
   862  	f.FieldList[f.curFieldListIndex].Options = options
   863  	return f
   864  }
   865  
   866  func (f *FormPanel) FieldDefaultOptionDelimiter(delimiter string) *FormPanel {
   867  	f.FieldList[f.curFieldListIndex].DefaultOptionDelimiter = delimiter
   868  	return f
   869  }
   870  
   871  func (f *FormPanel) FieldPostFilterFn(post PostFieldFilterFn) *FormPanel {
   872  	f.FieldList[f.curFieldListIndex].PostFilterFn = post
   873  	return f
   874  }
   875  
   876  func (f *FormPanel) FieldNow() *FormPanel {
   877  	f.FieldList[f.curFieldListIndex].PostFilterFn = func(value PostFieldModel) interface{} {
   878  		return time.Now().Format("2006-01-02 15:04:05")
   879  	}
   880  	return f
   881  }
   882  
   883  func (f *FormPanel) FieldNowWhenUpdate() *FormPanel {
   884  	f.FieldList[f.curFieldListIndex].PostFilterFn = func(value PostFieldModel) interface{} {
   885  		if value.IsUpdate() {
   886  			return time.Now().Format("2006-01-02 15:04:05")
   887  		}
   888  		return value.Value.Value()
   889  	}
   890  	return f
   891  }
   892  
   893  func (f *FormPanel) FieldNowWhenInsert() *FormPanel {
   894  	f.FieldList[f.curFieldListIndex].PostFilterFn = func(value PostFieldModel) interface{} {
   895  		if value.IsCreate() {
   896  			return time.Now().Format("2006-01-02 15:04:05")
   897  		}
   898  		return value.Value.Value()
   899  	}
   900  	return f
   901  }
   902  
   903  func (f *FormPanel) FieldLimit(limit int) *FormPanel {
   904  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddLimit(limit)
   905  	return f
   906  }
   907  
   908  func (f *FormPanel) FieldTrimSpace() *FormPanel {
   909  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddTrimSpace()
   910  	return f
   911  }
   912  
   913  func (f *FormPanel) FieldSubstr(start int, end int) *FormPanel {
   914  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddSubstr(start, end)
   915  	return f
   916  }
   917  
   918  func (f *FormPanel) FieldToTitle() *FormPanel {
   919  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddToTitle()
   920  	return f
   921  }
   922  
   923  func (f *FormPanel) FieldToUpper() *FormPanel {
   924  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddToUpper()
   925  	return f
   926  }
   927  
   928  func (f *FormPanel) FieldToLower() *FormPanel {
   929  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].AddToLower()
   930  	return f
   931  }
   932  
   933  func (f *FormPanel) FieldXssFilter() *FormPanel {
   934  	f.FieldList[f.curFieldListIndex].DisplayProcessChains = f.FieldList[f.curFieldListIndex].DisplayProcessChains.
   935  		Add(func(value FieldModel) interface{} {
   936  			return html.EscapeString(value.Value)
   937  		})
   938  	return f
   939  }
   940  
   941  func (f *FormPanel) FieldCustomContent(content template.HTML) *FormPanel {
   942  	f.FieldList[f.curFieldListIndex].CustomContent = content
   943  	return f
   944  }
   945  
   946  func (f *FormPanel) FieldCustomJs(js template.JS) *FormPanel {
   947  	f.FieldList[f.curFieldListIndex].CustomJs = js
   948  	return f
   949  }
   950  
   951  func (f *FormPanel) FieldCustomCss(css template.CSS) *FormPanel {
   952  	f.FieldList[f.curFieldListIndex].CustomCss = css
   953  	return f
   954  }
   955  
   956  func (f *FormPanel) FieldOnSearch(url string, handler Handler, delay ...int) *FormPanel {
   957  	ext, callback := searchJS(f.FieldList[f.curFieldListIndex].OptionExt, f.OperationURL(url), handler, delay...)
   958  	f.FieldList[f.curFieldListIndex].OptionExt = ext
   959  	f.Callbacks = f.Callbacks.AddCallback(callback)
   960  	return f
   961  }
   962  
   963  func (f *FormPanel) FieldOnChooseCustom(js template.HTML) *FormPanel {
   964  	f.FooterHtml += chooseCustomJS(f.FieldList[f.curFieldListIndex].Field, js)
   965  	return f
   966  }
   967  
   968  type LinkField struct {
   969  	Field   string
   970  	Value   template.HTML
   971  	Hide    bool
   972  	Disable bool
   973  }
   974  
   975  func (f *FormPanel) FieldOnChooseMap(m map[string]LinkField) *FormPanel {
   976  	f.FooterHtml += chooseMapJS(f.FieldList[f.curFieldListIndex].Field, m)
   977  	return f
   978  }
   979  
   980  func (f *FormPanel) FieldOnChoose(val, field string, value template.HTML) *FormPanel {
   981  	f.FooterHtml += chooseJS(f.FieldList[f.curFieldListIndex].Field, field, val, value)
   982  	return f
   983  }
   984  
   985  func (f *FormPanel) OperationURL(id string) string {
   986  	return config.Url("/operation/" + utils.WrapURL(id))
   987  }
   988  
   989  func (f *FormPanel) FieldOnChooseAjax(field, url string, handler Handler, custom ...template.HTML) *FormPanel {
   990  	js, callback := chooseAjax(f.FieldList[f.curFieldListIndex].Field, field, f.OperationURL(url), handler, custom...)
   991  	f.FooterHtml += js
   992  	f.Callbacks = f.Callbacks.AddCallback(callback)
   993  	return f
   994  }
   995  
   996  func (f *FormPanel) FieldOnChooseHide(value string, field ...string) *FormPanel {
   997  	f.FooterHtml += chooseHideJS(f.FieldList[f.curFieldListIndex].Field, []string{value}, field...)
   998  	return f
   999  }
  1000  
  1001  func (f *FormPanel) FieldOnChooseOptionsHide(values []string, field ...string) *FormPanel {
  1002  	f.FooterHtml += chooseHideJS(f.FieldList[f.curFieldListIndex].Field, values, field...)
  1003  	return f
  1004  }
  1005  
  1006  func (f *FormPanel) FieldOnChooseShow(value string, field ...string) *FormPanel {
  1007  	f.FooterHtml += chooseShowJS(f.FieldList[f.curFieldListIndex].Field, []string{value}, field...)
  1008  	return f
  1009  }
  1010  
  1011  func (f *FormPanel) FieldOnChooseOptionsShow(values []string, field ...string) *FormPanel {
  1012  	f.FooterHtml += chooseShowJS(f.FieldList[f.curFieldListIndex].Field, values, field...)
  1013  	return f
  1014  }
  1015  
  1016  func (f *FormPanel) FieldOnChooseDisable(value string, field ...string) *FormPanel {
  1017  	f.FooterHtml += chooseDisableJS(f.FieldList[f.curFieldListIndex].Field, []string{value}, field...)
  1018  	return f
  1019  }
  1020  
  1021  func (f *FormPanel) addFooterHTML(footer template.HTML) *FormPanel {
  1022  	f.FooterHtml += template.HTML(ParseTableDataTmpl(footer))
  1023  	return f
  1024  }
  1025  
  1026  func (f *FormPanel) AddCSS(css template.CSS) *FormPanel {
  1027  	return f.addFooterHTML(template.HTML("<style>" + css + "</style>"))
  1028  }
  1029  
  1030  func (f *FormPanel) AddJS(js template.JS) *FormPanel {
  1031  	return f.addFooterHTML(template.HTML("<script>" + js + "</script>"))
  1032  }
  1033  
  1034  func searchJS(ext template.JS, url string, handler Handler, delay ...int) (template.JS, context.Node) {
  1035  	delayStr := "500"
  1036  	if len(delay) > 0 {
  1037  		delayStr = strconv.Itoa(delay[0])
  1038  	}
  1039  
  1040  	if ext != template.JS("") {
  1041  		s := string(ext)
  1042  		s = strings.Replace(s, "{", "", 1)
  1043  		s = utils.ReplaceNth(s, "}", "", strings.Count(s, "}"))
  1044  		s = strings.TrimRight(s, " ")
  1045  		s += ","
  1046  		ext = template.JS(s)
  1047  	}
  1048  
  1049  	return template.JS(`{
  1050  		`) + ext + template.JS(`
  1051  		ajax: {
  1052  		    url: "`+url+`",
  1053  		    dataType: 'json',
  1054  		    data: function (params) {
  1055  			      var query = {
  1056  			        	search: params.term,
  1057  						page: params.page || 1
  1058  			      }
  1059  			      return query;
  1060  		    },
  1061  		    delay: `+delayStr+`,
  1062  		    processResults: function (data, params) {
  1063  			      return data.data;
  1064  	    	}
  1065  	  	}
  1066  	}`), context.Node{
  1067  			Path:     url,
  1068  			Method:   "get",
  1069  			Handlers: context.Handlers{handler.Wrap()},
  1070  			Value:    map[string]interface{}{constant.ContextNodeNeedAuth: 1},
  1071  		}
  1072  }
  1073  
  1074  func chooseCustomJS(field string, js template.HTML) template.HTML {
  1075  	return utils.ParseHTML("choose_custom", tmpls["choose_custom"], struct {
  1076  		Field template.JS
  1077  		JS    template.JS
  1078  	}{Field: template.JS(field), JS: template.JS(js)})
  1079  }
  1080  
  1081  func chooseMapJS(field string, m map[string]LinkField) template.HTML {
  1082  	return utils.ParseHTML("choose_map", tmpls["choose_map"], struct {
  1083  		Field template.JS
  1084  		Data  map[string]LinkField
  1085  	}{
  1086  		Field: template.JS(field),
  1087  		Data:  m,
  1088  	})
  1089  }
  1090  
  1091  func chooseJS(field, chooseField, val string, value template.HTML) template.HTML {
  1092  	return utils.ParseHTML("choose", tmpls["choose"], struct {
  1093  		Field       template.JS
  1094  		ChooseField template.JS
  1095  		Val         template.JS
  1096  		Value       template.JS
  1097  	}{
  1098  		Field:       template.JS(field),
  1099  		ChooseField: template.JS(chooseField),
  1100  		Value:       decorateChooseValue([]string{string(value)}),
  1101  		Val:         decorateChooseValue([]string{string(val)}),
  1102  	})
  1103  }
  1104  
  1105  func chooseAjax(field, chooseField, url string, handler Handler, js ...template.HTML) (template.HTML, context.Node) {
  1106  
  1107  	actionJS := template.HTML("")
  1108  	passValue := template.JS("")
  1109  
  1110  	if len(js) > 0 {
  1111  		actionJS = js[0]
  1112  	}
  1113  
  1114  	if len(js) > 1 {
  1115  		passValue = template.JS(js[1])
  1116  	}
  1117  
  1118  	return utils.ParseHTML("choose_ajax", tmpls["choose_ajax"], struct {
  1119  			Field       template.JS
  1120  			ChooseField template.JS
  1121  			PassValue   template.JS
  1122  			ActionJS    template.JS
  1123  			Url         template.JS
  1124  		}{
  1125  			Url:         template.JS(url),
  1126  			Field:       template.JS(field),
  1127  			ChooseField: template.JS(chooseField),
  1128  			PassValue:   passValue,
  1129  			ActionJS:    template.JS(actionJS),
  1130  		}), context.Node{
  1131  			Path:     url,
  1132  			Method:   "post",
  1133  			Handlers: context.Handlers{handler.Wrap()},
  1134  			Value:    map[string]interface{}{constant.ContextNodeNeedAuth: 1},
  1135  		}
  1136  }
  1137  
  1138  func chooseHideJS(field string, value []string, chooseFields ...string) template.HTML {
  1139  	if len(chooseFields) == 0 {
  1140  		return ""
  1141  	}
  1142  
  1143  	return utils.ParseHTML("choose_hide", tmpls["choose_hide"], struct {
  1144  		Field        template.JS
  1145  		Value        template.JS
  1146  		ChooseFields []string
  1147  	}{
  1148  		Field:        template.JS(field),
  1149  		Value:        decorateChooseValue(value),
  1150  		ChooseFields: chooseFields,
  1151  	})
  1152  }
  1153  
  1154  func chooseShowJS(field string, value []string, chooseFields ...string) template.HTML {
  1155  	if len(chooseFields) == 0 {
  1156  		return ""
  1157  	}
  1158  
  1159  	return utils.ParseHTML("choose_show", tmpls["choose_show"], struct {
  1160  		Field        template.JS
  1161  		Value        template.JS
  1162  		ChooseFields []string
  1163  	}{
  1164  		Field:        template.JS(field),
  1165  		Value:        decorateChooseValue(value),
  1166  		ChooseFields: chooseFields,
  1167  	})
  1168  }
  1169  
  1170  func chooseDisableJS(field string, value []string, chooseFields ...string) template.HTML {
  1171  	if len(chooseFields) == 0 {
  1172  		return ""
  1173  	}
  1174  
  1175  	return utils.ParseHTML("choose_disable", tmpls["choose_disable"], struct {
  1176  		Field        template.JS
  1177  		Value        template.JS
  1178  		ChooseFields []string
  1179  	}{
  1180  		Field:        template.JS(field),
  1181  		Value:        decorateChooseValue(value),
  1182  		ChooseFields: chooseFields,
  1183  	})
  1184  }
  1185  
  1186  func decorateChooseValue(val []string) template.JS {
  1187  	if len(val) == 0 {
  1188  		return ""
  1189  	}
  1190  
  1191  	res := make([]string, len(val))
  1192  
  1193  	for k, v := range val {
  1194  
  1195  		if v == "" {
  1196  			v = `""`
  1197  		}
  1198  
  1199  		if v[0] != '"' {
  1200  			if strings.Contains(v, "$(this)") {
  1201  				res[k] = v
  1202  			}
  1203  			if v == "{{.vue}}" {
  1204  				res[k] = "$(this).v()"
  1205  			}
  1206  			if len(v) > 3 && v[:3] == "js:" {
  1207  				res[k] = v[3:]
  1208  			}
  1209  			res[k] = `"` + v + `"`
  1210  		} else {
  1211  			res[k] = v
  1212  		}
  1213  	}
  1214  
  1215  	return template.JS("[" + strings.Join(res, ",") + "]")
  1216  }
  1217  
  1218  // FormPanel attribute setting functions
  1219  // ====================================================
  1220  
  1221  func (f *FormPanel) SetTitle(title string) *FormPanel {
  1222  	f.Title = title
  1223  	return f
  1224  }
  1225  
  1226  func (f *FormPanel) SetTabGroups(groups TabGroups) *FormPanel {
  1227  	f.TabGroups = groups
  1228  	return f
  1229  }
  1230  
  1231  func (f *FormPanel) SetTabHeaders(headers ...string) *FormPanel {
  1232  	f.TabHeaders = headers
  1233  	return f
  1234  }
  1235  
  1236  func (f *FormPanel) SetDescription(desc string) *FormPanel {
  1237  	f.Description = desc
  1238  	return f
  1239  }
  1240  
  1241  func (f *FormPanel) SetHeaderHtml(header template.HTML) *FormPanel {
  1242  	f.HeaderHtml += header
  1243  	return f
  1244  }
  1245  
  1246  func (f *FormPanel) SetFooterHtml(footer template.HTML) *FormPanel {
  1247  	f.FooterHtml += footer
  1248  	return f
  1249  }
  1250  
  1251  func (f *FormPanel) HasError() bool {
  1252  	return f.PageError != nil
  1253  }
  1254  
  1255  func (f *FormPanel) SetError(err errors.PageError, content ...template.HTML) *FormPanel {
  1256  	f.PageError = err
  1257  	if len(content) > 0 {
  1258  		f.PageErrorHTML = content[0]
  1259  	}
  1260  	return f
  1261  }
  1262  
  1263  func (f *FormPanel) SetNoCompress() *FormPanel {
  1264  	f.NoCompress = true
  1265  	return f
  1266  }
  1267  
  1268  func (f *FormPanel) Set404Error(content ...template.HTML) *FormPanel {
  1269  	f.SetError(errors.PageError404, content...)
  1270  	return f
  1271  }
  1272  
  1273  func (f *FormPanel) Set403Error(content ...template.HTML) *FormPanel {
  1274  	f.SetError(errors.PageError403, content...)
  1275  	return f
  1276  }
  1277  
  1278  func (f *FormPanel) Set400Error(content ...template.HTML) *FormPanel {
  1279  	f.SetError(errors.PageError401, content...)
  1280  	return f
  1281  }
  1282  
  1283  func (f *FormPanel) Set500Error(content ...template.HTML) *FormPanel {
  1284  	f.SetError(errors.PageError500, content...)
  1285  	return f
  1286  }
  1287  
  1288  func (f *FormPanel) SetLayout(layout form2.Layout) *FormPanel {
  1289  	f.Layout = layout
  1290  	return f
  1291  }
  1292  
  1293  func (f *FormPanel) SetPostValidator(va FormPostFn) *FormPanel {
  1294  	f.Validator = va
  1295  	return f
  1296  }
  1297  
  1298  func (f *FormPanel) SetPreProcessFn(fn FormPreProcessFn) *FormPanel {
  1299  	f.PreProcessFn = fn
  1300  	return f
  1301  }
  1302  
  1303  func (f *FormPanel) SetHTMLContent(content template.HTML) *FormPanel {
  1304  	f.HTMLContent = content
  1305  	return f
  1306  }
  1307  
  1308  func (f *FormPanel) SetHeader(content template.HTML) *FormPanel {
  1309  	f.Header = content
  1310  	return f
  1311  }
  1312  
  1313  func (f *FormPanel) SetInputWidth(width int) *FormPanel {
  1314  	f.InputWidth = width
  1315  	return f
  1316  }
  1317  
  1318  func (f *FormPanel) SetHeadWidth(width int) *FormPanel {
  1319  	f.HeadWidth = width
  1320  	return f
  1321  }
  1322  
  1323  func (f *FormPanel) SetWrapper(wrapper ContentWrapper) *FormPanel {
  1324  	f.Wrapper = wrapper
  1325  	return f
  1326  }
  1327  
  1328  func (f *FormPanel) SetHideSideBar() *FormPanel {
  1329  	f.HideSideBar = true
  1330  	return f
  1331  }
  1332  
  1333  func (f *FormPanel) SetFormNewTitle(title template.HTML) *FormPanel {
  1334  	f.FormNewTitle = title
  1335  	return f
  1336  }
  1337  
  1338  func (f *FormPanel) SetFormNewBtnWord(word template.HTML) *FormPanel {
  1339  	f.FormNewBtnWord = word
  1340  	return f
  1341  }
  1342  
  1343  func (f *FormPanel) SetFormEditTitle(title template.HTML) *FormPanel {
  1344  	f.FormEditTitle = title
  1345  	return f
  1346  }
  1347  
  1348  func (f *FormPanel) SetFormEditBtnWord(word template.HTML) *FormPanel {
  1349  	f.FormEditBtnWord = word
  1350  	return f
  1351  }
  1352  
  1353  func (f *FormPanel) SetResponder(responder Responder) *FormPanel {
  1354  	f.Responder = responder
  1355  	return f
  1356  }
  1357  
  1358  type AjaxData struct {
  1359  	SuccessTitle   string
  1360  	SuccessText    string
  1361  	ErrorTitle     string
  1362  	ErrorText      string
  1363  	SuccessJumpURL string
  1364  	DisableJump    bool
  1365  	SuccessJS      string
  1366  	JumpInNewTab   string
  1367  }
  1368  
  1369  func (f *FormPanel) EnableAjaxData(data AjaxData) *FormPanel {
  1370  	f.Ajax = true
  1371  	if f.AjaxSuccessJS == template.JS("") {
  1372  		successMsg := modules.AorB(data.SuccessTitle != "", `"`+data.SuccessTitle+`"`, "data.msg")
  1373  		errorMsg := modules.AorB(data.ErrorTitle != "", `"`+data.ErrorTitle+`"`, "data.msg")
  1374  		jump := modules.AorB(data.SuccessJumpURL != "", `"`+data.SuccessJumpURL+`"`, "data.data.url")
  1375  		text := modules.AorB(data.SuccessText != "", `text:"`+data.SuccessText+`",`, "")
  1376  		wrongText := modules.AorB(data.ErrorText != "", `text:"`+data.ErrorText+`",`, "text:data.msg,")
  1377  		jumpURL := ""
  1378  		if !data.DisableJump {
  1379  			if data.JumpInNewTab != "" {
  1380  				jumpURL = `listenerForAddNavTab(` + jump + `, "` + data.JumpInNewTab + `");`
  1381  			}
  1382  			jumpURL += `$.pjax({url: ` + jump + `, container: '#pjax-container'});`
  1383  		} else {
  1384  			jumpURL = `
  1385  		if (data.data && data.data.token !== "") {
  1386  			$("input[name='__go_admin_t_']").val(data.data.token)
  1387  		}`
  1388  		}
  1389  		f.AjaxSuccessJS = template.JS(`
  1390  	if (typeof (data) === "string") {
  1391  	    data = JSON.parse(data);
  1392  	}
  1393  	if (data.code === 200) {
  1394  	    swal({
  1395  			type: "success",
  1396  			title: ` + successMsg + `,
  1397  			` + text + `
  1398  			showCancelButton: false,
  1399  			confirmButtonColor: "#3c8dbc",
  1400  			confirmButtonText: '` + language.Get("got it") + `',
  1401          }, function() {
  1402  			$(".modal-backdrop.fade.in").remove();
  1403  			` + jumpURL + `
  1404  			` + data.SuccessJS + `
  1405          });
  1406  	} else {
  1407  		if (data.data && data.data.token !== "") {
  1408  			$("input[name='__go_admin_t_']").val(data.data.token);
  1409  		}
  1410  		swal({
  1411  			type: "error",
  1412  			title: ` + errorMsg + `,
  1413  			` + wrongText + `
  1414  			showCancelButton: false,
  1415  			confirmButtonColor: "#3c8dbc",
  1416  			confirmButtonText: '` + language.Get("got it") + `',
  1417          })
  1418  	}
  1419  `)
  1420  	}
  1421  	if f.AjaxErrorJS == template.JS("") {
  1422  		errorMsg := modules.AorB(data.ErrorTitle != "", `"`+data.ErrorTitle+`"`, "data.responseJSON.msg")
  1423  		error2Msg := modules.AorB(data.ErrorTitle != "", `"`+data.ErrorTitle+`"`, "'"+language.Get("error")+"'")
  1424  		wrongText := modules.AorB(data.ErrorText != "", `text:"`+data.ErrorText+`",`, "text:data.msg,")
  1425  		f.AjaxErrorJS = template.JS(`
  1426  	if (data.responseText !== "") {
  1427  		if (data.responseJSON.data && data.responseJSON.data.token !== "") {
  1428  			$("input[name='__go_admin_t_']").val(data.responseJSON.data.token)
  1429  		}
  1430  		swal({
  1431  			type: "error",
  1432  			title: ` + errorMsg + `,
  1433  			` + wrongText + `
  1434  			showCancelButton: false,
  1435  			confirmButtonColor: "#3c8dbc",
  1436  			confirmButtonText: '` + language.Get("got it") + `',
  1437          })
  1438  	} else {
  1439  		swal({
  1440  			type: "error",
  1441  			title: ` + error2Msg + `,
  1442  			` + wrongText + `
  1443  			showCancelButton: false,
  1444  			confirmButtonColor: "#3c8dbc",
  1445  			confirmButtonText: '` + language.Get("got it") + `',
  1446          })
  1447  	}
  1448  `)
  1449  	}
  1450  	return f
  1451  }
  1452  
  1453  func (f *FormPanel) EnableAjax(msgs ...string) *FormPanel {
  1454  	var data AjaxData
  1455  	if len(msgs) > 0 && msgs[0] != "" {
  1456  		data.SuccessTitle = msgs[0]
  1457  	}
  1458  	if len(msgs) > 1 && msgs[1] != "" {
  1459  		data.ErrorTitle = msgs[1]
  1460  	}
  1461  	if len(msgs) > 2 && msgs[2] != "" {
  1462  		data.SuccessJumpURL = msgs[2]
  1463  	}
  1464  	if len(msgs) > 3 && msgs[3] != "" {
  1465  		data.SuccessText = msgs[3]
  1466  	}
  1467  	if len(msgs) > 4 && msgs[4] != "" {
  1468  		data.ErrorText = msgs[4]
  1469  	}
  1470  	return f.EnableAjaxData(data)
  1471  }
  1472  
  1473  func (f *FormPanel) SetAjaxSuccessJS(js template.JS) *FormPanel {
  1474  	f.AjaxSuccessJS = js
  1475  	return f
  1476  }
  1477  
  1478  func (f *FormPanel) SetAjaxErrorJS(js template.JS) *FormPanel {
  1479  	f.AjaxErrorJS = js
  1480  	return f
  1481  }
  1482  
  1483  func (f *FormPanel) SetPostHook(fn FormPostFn) *FormPanel {
  1484  	f.PostHook = fn
  1485  	return f
  1486  }
  1487  
  1488  func (f *FormPanel) SetUpdateFn(fn FormPostFn) *FormPanel {
  1489  	f.UpdateFn = fn
  1490  	return f
  1491  }
  1492  
  1493  func (f *FormPanel) SetInsertFn(fn FormPostFn) *FormPanel {
  1494  	f.InsertFn = fn
  1495  	return f
  1496  }
  1497  
  1498  func (f *FormPanel) GroupFieldWithValue(pk, id string, columns []string, res map[string]interface{}, sql func() *db.SQL) ([]FormFields, []string) {
  1499  	var (
  1500  		groupFormList = make([]FormFields, 0)
  1501  		groupHeaders  = make([]string, 0)
  1502  		hasPK         = false
  1503  		existField    = make([]string, 0)
  1504  	)
  1505  
  1506  	if len(f.TabGroups) > 0 {
  1507  		for index, group := range f.TabGroups {
  1508  			list := make(FormFields, 0)
  1509  			for index, fieldName := range group {
  1510  				label := "_ga_group_" + strconv.Itoa(index)
  1511  				field := f.FieldList.FindByFieldName(fieldName)
  1512  				if field != nil && field.isNotBelongToATable() && !field.NotAllowEdit {
  1513  					if !field.Hide {
  1514  						field.Hide = field.EditHide
  1515  					}
  1516  					if field.FormType.IsTable() {
  1517  						for z := 0; z < len(field.TableFields); z++ {
  1518  							rowValue := field.TableFields[z].GetRawValue(columns, res[field.TableFields[z].Field])
  1519  							if field.TableFields[z].Field == pk {
  1520  								hasPK = true
  1521  							}
  1522  							field.TableFields[z] = *(field.TableFields[z].UpdateValue(id, rowValue, res, sql()))
  1523  						}
  1524  						if utils.InArray(existField, field.Field) {
  1525  							field.Field = field.Field + label
  1526  						}
  1527  						list = append(list, *field)
  1528  						existField = append(existField, field.Field)
  1529  					} else {
  1530  						if field.Field == pk {
  1531  							hasPK = true
  1532  						}
  1533  						rowValue := field.GetRawValue(columns, res[field.Field])
  1534  						if utils.InArray(existField, field.Field) {
  1535  							field.Field = field.Field + label
  1536  						}
  1537  						list = append(list, *(field.UpdateValue(id, rowValue, res, sql())))
  1538  						existField = append(existField, field.Field)
  1539  					}
  1540  				}
  1541  			}
  1542  
  1543  			groupFormList = append(groupFormList, list.FillCustomContent())
  1544  			groupHeaders = append(groupHeaders, f.TabHeaders[index])
  1545  		}
  1546  
  1547  		if len(groupFormList) > 0 && !hasPK {
  1548  			groupFormList[len(groupFormList)-1] = groupFormList[len(groupFormList)-1].Add(&FormField{
  1549  				Head:       pk,
  1550  				FieldClass: pk,
  1551  				Field:      pk,
  1552  				Value:      template.HTML(id),
  1553  				Hide:       true,
  1554  			})
  1555  		}
  1556  	}
  1557  
  1558  	return groupFormList, groupHeaders
  1559  }
  1560  
  1561  func (f *FormPanel) GroupField(sql ...func() *db.SQL) ([]FormFields, []string) {
  1562  	var (
  1563  		groupFormList = make([]FormFields, 0)
  1564  		groupHeaders  = make([]string, 0)
  1565  		existField    = make([]string, 0)
  1566  	)
  1567  
  1568  	for index, group := range f.TabGroups {
  1569  		list := make(FormFields, 0)
  1570  		for index, fieldName := range group {
  1571  			field := f.FieldList.FindByFieldName(fieldName)
  1572  			label := "_ga_group_" + strconv.Itoa(index)
  1573  			if field != nil && field.isNotBelongToATable() && field.allowAdd() {
  1574  				field.Editable = !field.DisplayButNotAdd
  1575  				if !field.Hide {
  1576  					field.Hide = field.CreateHide
  1577  				}
  1578  				if field.FormType.IsTable() {
  1579  					for z := 0; z < len(field.TableFields); z++ {
  1580  						if len(sql) > 0 {
  1581  							field.TableFields[z] = *(field.TableFields[z].UpdateDefaultValue(sql[0]()))
  1582  						} else {
  1583  							field.TableFields[z] = *(field.TableFields[z].UpdateDefaultValue(nil))
  1584  						}
  1585  					}
  1586  					if utils.InArray(existField, field.Field) {
  1587  						field.Field = field.Field + label
  1588  					}
  1589  					list = append(list, *field)
  1590  					existField = append(existField, field.Field)
  1591  				} else {
  1592  					if utils.InArray(existField, field.Field) {
  1593  						field.Field = field.Field + label
  1594  					}
  1595  					if len(sql) > 0 {
  1596  						list = append(list, *(field.UpdateDefaultValue(sql[0]())))
  1597  					} else {
  1598  						list = append(list, *(field.UpdateDefaultValue(nil)))
  1599  					}
  1600  					existField = append(existField, field.Field)
  1601  				}
  1602  			}
  1603  		}
  1604  		groupFormList = append(groupFormList, list.FillCustomContent())
  1605  		groupHeaders = append(groupHeaders, f.TabHeaders[index])
  1606  	}
  1607  
  1608  	return groupFormList, groupHeaders
  1609  }
  1610  
  1611  func (f *FormPanel) FieldsWithValue(pk, id string, columns []string, res map[string]interface{}, sql func() *db.SQL) FormFields {
  1612  	var (
  1613  		list  = make(FormFields, 0)
  1614  		hasPK = false
  1615  	)
  1616  	for i := 0; i < len(f.FieldList); i++ {
  1617  		if !f.FieldList[i].NotAllowEdit {
  1618  			if !f.FieldList[i].Hide {
  1619  				f.FieldList[i].Hide = f.FieldList[i].EditHide
  1620  			}
  1621  			rowValue := f.FieldList[i].GetRawValue(columns, res[f.FieldList[i].Field])
  1622  			if f.FieldList[i].FatherField != "" {
  1623  				f.FieldList.FindTableField(f.FieldList[i].Field, f.FieldList[i].FatherField).UpdateValue(id, rowValue, res, sql())
  1624  			} else if f.FieldList[i].FormType.IsTable() {
  1625  				list = append(list, f.FieldList[i])
  1626  			} else {
  1627  				list = append(list, *(f.FieldList[i].UpdateValue(id, rowValue, res, sql())))
  1628  			}
  1629  
  1630  			if f.FieldList[i].Field == pk {
  1631  				hasPK = true
  1632  			}
  1633  		}
  1634  	}
  1635  	if !hasPK {
  1636  		list = list.Add(&FormField{
  1637  			Head:       pk,
  1638  			FieldClass: pk,
  1639  			Field:      pk,
  1640  			Value:      template.HTML(id),
  1641  			FormType:   form2.Default,
  1642  			Hide:       true,
  1643  		})
  1644  	}
  1645  	return list.FillCustomContent()
  1646  }
  1647  
  1648  func (f *FormPanel) FieldsWithDefaultValue(sql ...func() *db.SQL) FormFields {
  1649  	var list = make(FormFields, 0)
  1650  	for i := 0; i < len(f.FieldList); i++ {
  1651  		if f.FieldList[i].allowAdd() {
  1652  			f.FieldList[i].Editable = !f.FieldList[i].DisplayButNotAdd
  1653  			if !f.FieldList[i].Hide {
  1654  				f.FieldList[i].Hide = f.FieldList[i].CreateHide
  1655  			}
  1656  			if f.FieldList[i].FatherField != "" {
  1657  				if len(sql) > 0 {
  1658  					f.FieldList.FindTableField(f.FieldList[i].Field, f.FieldList[i].FatherField).UpdateDefaultValue(sql[0]())
  1659  				} else {
  1660  					f.FieldList.FindTableField(f.FieldList[i].Field, f.FieldList[i].FatherField).UpdateDefaultValue(nil)
  1661  				}
  1662  			} else if f.FieldList[i].FormType.IsTable() {
  1663  				list = append(list, f.FieldList[i])
  1664  			} else {
  1665  				if len(sql) > 0 {
  1666  					list = append(list, *(f.FieldList[i].UpdateDefaultValue(sql[0]())))
  1667  				} else {
  1668  					list = append(list, *(f.FieldList[i].UpdateDefaultValue(nil)))
  1669  				}
  1670  			}
  1671  		}
  1672  	}
  1673  	return list.FillCustomContent().RemoveNotShow()
  1674  }
  1675  
  1676  func (f *FormPanel) GetNewFormFields(sql ...func() *db.SQL) (FormFields, []FormFields, []string) {
  1677  	if len(f.TabGroups) > 0 {
  1678  		tabFields, tabHeaders := f.GroupField(sql...)
  1679  		return make(FormFields, 0), tabFields, tabHeaders
  1680  	}
  1681  	return f.FieldsWithDefaultValue(sql...), make([]FormFields, 0), make([]string, 0)
  1682  }
  1683  
  1684  type (
  1685  	FormPreProcessFn  func(values form.Values) form.Values
  1686  	FormPostFn        func(values form.Values) error
  1687  	FormFields        []FormField
  1688  	GroupFormFields   []FormFields
  1689  	GroupFieldHeaders []string
  1690  )
  1691  
  1692  func (f FormFields) Copy() FormFields {
  1693  	formList := make(FormFields, len(f))
  1694  	copy(formList, f)
  1695  	for i := 0; i < len(formList); i++ {
  1696  		formList[i].Options = make(FieldOptions, len(f[i].Options))
  1697  		for j := 0; j < len(f[i].Options); j++ {
  1698  			formList[i].Options[j] = FieldOption{
  1699  				Value:    f[i].Options[j].Value,
  1700  				Text:     f[i].Options[j].Text,
  1701  				TextHTML: f[i].Options[j].TextHTML,
  1702  				Selected: f[i].Options[j].Selected,
  1703  			}
  1704  		}
  1705  	}
  1706  	return formList
  1707  }
  1708  
  1709  func (f FormFields) FindByFieldName(field string) *FormField {
  1710  	for i := 0; i < len(f); i++ {
  1711  		if f[i].Field == field {
  1712  			return &f[i]
  1713  		}
  1714  	}
  1715  	return nil
  1716  }
  1717  
  1718  func (f FormFields) FindIndexByFieldName(field string) int {
  1719  	for i := 0; i < len(f); i++ {
  1720  		if f[i].Field == field {
  1721  			return i
  1722  		}
  1723  	}
  1724  	return -1
  1725  }
  1726  
  1727  func (f FormFields) FindTableField(field, father string) *FormField {
  1728  	ff := f.FindByFieldName(father)
  1729  	return ff.TableFields.FindByFieldName(field)
  1730  }
  1731  
  1732  func (f FormFields) FindTableChildren(father string) []*FormField {
  1733  	list := make([]*FormField, 0)
  1734  	for i := 0; i < len(f); i++ {
  1735  		if f[i].FatherField == father {
  1736  			list = append(list, &f[i])
  1737  		}
  1738  	}
  1739  	return list
  1740  }
  1741  
  1742  func (f FormFields) FillCustomContent() FormFields {
  1743  	for i := range f {
  1744  		if f[i].FormType.IsCustom() {
  1745  			f[i] = *(f[i]).FillCustomContent()
  1746  		}
  1747  	}
  1748  	return f
  1749  }
  1750  
  1751  func (f FormFields) Add(field *FormField) FormFields {
  1752  	return append(f, *field)
  1753  }
  1754  
  1755  func (f FormFields) RemoveNotShow() FormFields {
  1756  	ff := f
  1757  	for i := 0; i < len(ff); {
  1758  		if ff[i].FatherFormType == form2.Table {
  1759  			ff = append(ff[:i], ff[i+1:]...)
  1760  		} else {
  1761  			i++
  1762  		}
  1763  	}
  1764  	return ff
  1765  }