github.com/kotovmak/go-admin@v1.1.1/template/types/info.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "html" 7 "html/template" 8 "net/http" 9 "strconv" 10 "strings" 11 12 "github.com/kotovmak/go-admin/modules/config" 13 14 "github.com/kotovmak/go-admin/context" 15 "github.com/kotovmak/go-admin/modules/db" 16 "github.com/kotovmak/go-admin/modules/errors" 17 "github.com/kotovmak/go-admin/modules/language" 18 "github.com/kotovmak/go-admin/modules/logger" 19 "github.com/kotovmak/go-admin/modules/utils" 20 "github.com/kotovmak/go-admin/plugins/admin/modules" 21 "github.com/kotovmak/go-admin/plugins/admin/modules/parameter" 22 "github.com/kotovmak/go-admin/template/types/form" 23 "github.com/kotovmak/go-admin/template/types/table" 24 ) 25 26 // FieldModel is the single query result. 27 type FieldModel struct { 28 // The primaryKey of the table. 29 ID string 30 31 // The value of the single query result. 32 Value string 33 34 // The current row data. 35 Row map[string]interface{} 36 37 // Post type 38 PostType PostType 39 } 40 41 type PostType uint8 42 43 const ( 44 PostTypeCreate = iota 45 PostTypeUpdate 46 ) 47 48 func (m FieldModel) IsCreate() bool { 49 return m.PostType == PostTypeCreate 50 } 51 52 func (m FieldModel) IsUpdate() bool { 53 return m.PostType == PostTypeUpdate 54 } 55 56 // PostFieldModel contains ID and value of the single query result and the current row data. 57 type PostFieldModel struct { 58 ID string 59 Value FieldModelValue 60 Row map[string]string 61 // Post type 62 PostType PostType 63 } 64 65 func (m PostFieldModel) IsCreate() bool { 66 return m.PostType == PostTypeCreate 67 } 68 69 func (m PostFieldModel) IsUpdate() bool { 70 return m.PostType == PostTypeUpdate 71 } 72 73 type InfoList []map[string]InfoItem 74 75 type InfoItem struct { 76 Content template.HTML `json:"content"` 77 Value string `json:"value"` 78 } 79 80 func (i InfoList) GroupBy(groups TabGroups) []InfoList { 81 82 var res = make([]InfoList, len(groups)) 83 84 for key, value := range groups { 85 var newInfoList = make(InfoList, len(i)) 86 87 for index, info := range i { 88 var newRow = make(map[string]InfoItem) 89 for mk, m := range info { 90 if modules.InArray(value, mk) { 91 newRow[mk] = m 92 } 93 } 94 newInfoList[index] = newRow 95 } 96 97 res[key] = newInfoList 98 } 99 100 return res 101 } 102 103 type Callbacks []context.Node 104 105 func (c Callbacks) AddCallback(node context.Node) Callbacks { 106 if node.Path != "" && node.Method != "" && len(node.Handlers) > 0 { 107 for _, item := range c { 108 if strings.EqualFold(item.Path, node.Path) && 109 strings.EqualFold(item.Method, node.Method) { 110 return c 111 } 112 } 113 parr := strings.Split(node.Path, "?") 114 if len(parr) > 1 { 115 node.Path = parr[0] 116 return append(c, node) 117 } 118 return append(c, node) 119 } 120 return c 121 } 122 123 type FieldModelValue []string 124 125 func (r FieldModelValue) Value() string { 126 return r.First() 127 } 128 129 func (r FieldModelValue) First() string { 130 if len(r) > 0 { 131 return r[0] 132 } 133 return "" 134 } 135 136 // FieldDisplay is filter function of data. 137 type FieldFilterFn func(value FieldModel) interface{} 138 139 // PostFieldFilterFn is filter function of data. 140 type PostFieldFilterFn func(value PostFieldModel) interface{} 141 142 // Field is the table field. 143 type Field struct { 144 Head string 145 Field string 146 TypeName db.DatabaseType 147 148 Joins Joins 149 150 Width int 151 Sortable bool 152 EditAble bool 153 Fixed bool 154 Filterable bool 155 Hide bool 156 HideForList bool 157 158 EditType table.Type 159 EditOptions FieldOptions 160 161 FilterFormFields []FilterFormField 162 163 IsEditParam bool 164 IsDeleteParam bool 165 IsDetailParam bool 166 167 FieldDisplay 168 } 169 170 type QueryFilterFn func(param parameter.Parameters, conn db.Connection) (ids []string, stopQuery bool) 171 type UpdateParametersFn func(param *parameter.Parameters) 172 173 type FilterFormField struct { 174 Type form.Type 175 Options FieldOptions 176 OptionTable OptionTable 177 Width int 178 HeadWidth int 179 InputWidth int 180 Style template.HTMLAttr 181 Operator FilterOperator 182 OptionExt template.JS 183 Head string 184 Placeholder string 185 HelpMsg template.HTML 186 NoIcon bool 187 ProcessFn func(string) string 188 } 189 190 func (f Field) GetFilterFormFields(params parameter.Parameters, headField string, sql ...*db.SQL) []FormField { 191 192 var ( 193 filterForm = make([]FormField, 0) 194 value, value2, keySuffix string 195 ) 196 197 for index, filter := range f.FilterFormFields { 198 199 if index > 0 { 200 keySuffix = parameter.FilterParamCountInfix + strconv.Itoa(index) 201 } 202 203 if filter.Type.IsRange() { 204 value = params.GetFilterFieldValueStart(headField) 205 value2 = params.GetFilterFieldValueEnd(headField) 206 } else if filter.Type.IsMultiSelect() { 207 value = params.GetFieldValuesStr(headField) 208 } else { 209 if filter.Operator == FilterOperatorFree { 210 value2 = GetOperatorFromValue(params.GetFieldOperator(headField, keySuffix)).String() 211 } 212 value = params.GetFieldValue(headField + keySuffix) 213 } 214 215 var ( 216 optionExt1 = filter.OptionExt 217 optionExt2 template.JS 218 ) 219 220 if filter.OptionExt == template.JS("") { 221 op1, op2, js := filter.Type.GetDefaultOptions(headField + keySuffix) 222 if op1 != nil { 223 s, _ := json.Marshal(op1) 224 optionExt1 = template.JS(string(s)) 225 } 226 if op2 != nil { 227 s, _ := json.Marshal(op2) 228 optionExt2 = template.JS(string(s)) 229 } 230 if js != template.JS("") { 231 optionExt1 = js 232 } 233 } 234 235 field := &FormField{ 236 Field: headField + keySuffix, 237 FieldClass: headField + keySuffix, 238 Head: filter.Head, 239 TypeName: f.TypeName, 240 HelpMsg: filter.HelpMsg, 241 NoIcon: filter.NoIcon, 242 FormType: filter.Type, 243 Editable: true, 244 Width: filter.Width, 245 HeadWidth: filter.HeadWidth, 246 InputWidth: filter.InputWidth, 247 Style: filter.Style, 248 Placeholder: filter.Placeholder, 249 Value: template.HTML(value), 250 Value2: value2, 251 Options: filter.Options, 252 OptionExt: optionExt1, 253 OptionExt2: optionExt2, 254 OptionTable: filter.OptionTable, 255 Label: filter.Operator.Label(), 256 } 257 258 field.setOptionsFromSQL(sql[0]) 259 260 if filter.Type.IsSingleSelect() { 261 field.Options = field.Options.SetSelected(params.GetFieldValue(f.Field), filter.Type.SelectedLabel()) 262 } 263 264 if filter.Type.IsMultiSelect() { 265 field.Options = field.Options.SetSelected(params.GetFieldValues(f.Field), filter.Type.SelectedLabel()) 266 } 267 268 filterForm = append(filterForm, *field) 269 270 if filter.Operator.AddOrNot() { 271 ff := headField + parameter.FilterParamOperatorSuffix + keySuffix 272 filterForm = append(filterForm, FormField{ 273 Field: ff, 274 FieldClass: ff, 275 Head: f.Head, 276 TypeName: f.TypeName, 277 Value: template.HTML(filter.Operator.Value()), 278 FormType: filter.Type, 279 Hide: true, 280 }) 281 } 282 } 283 284 return filterForm 285 } 286 287 func (f Field) Exist() bool { 288 return f.Field != "" 289 } 290 291 type FieldList []Field 292 293 type TableInfo struct { 294 Table string 295 PrimaryKey string 296 Delimiter string 297 Delimiter2 string 298 Driver string 299 } 300 301 func (f FieldList) GetTheadAndFilterForm(info TableInfo, params parameter.Parameters, columns []string, 302 sql ...func() *db.SQL) (Thead, string, string, string, []string, []FormField) { 303 var ( 304 thead = make(Thead, 0) 305 fields = "" 306 joinFields = "" 307 joins = "" 308 joinTables = make([]string, 0) 309 filterForm = make([]FormField, 0) 310 tableName = info.Delimiter + info.Table + info.Delimiter2 311 ) 312 for _, field := range f { 313 if field.Field != info.PrimaryKey && modules.InArray(columns, field.Field) && 314 !field.Joins.Valid() { 315 fields += tableName + "." + modules.FilterField(field.Field, info.Delimiter, info.Delimiter2) + "," 316 } 317 318 headField := field.Field 319 320 if field.Joins.Valid() { 321 headField = field.Joins.Last().GetTableName() + parameter.FilterParamJoinInfix + field.Field 322 joinFields += db.GetAggregationExpression(info.Driver, field.Joins.Last().GetTableName(info.Delimiter, info.Delimiter2)+"."+ 323 modules.FilterField(field.Field, info.Delimiter, info.Delimiter2), headField, JoinFieldValueDelimiter) + "," 324 for _, join := range field.Joins { 325 if !modules.InArray(joinTables, join.GetTableName(info.Delimiter, info.Delimiter2)) { 326 joinTables = append(joinTables, join.GetTableName(info.Delimiter, info.Delimiter2)) 327 if join.BaseTable == "" { 328 join.BaseTable = info.Table 329 } 330 joins += " left join " + modules.FilterField(join.Table, info.Delimiter, info.Delimiter2) + " " + join.TableAlias + " on " + 331 join.GetTableName(info.Delimiter, info.Delimiter2) + "." + modules.FilterField(join.JoinField, info.Delimiter, info.Delimiter2) + " = " + 332 modules.Delimiter(info.Delimiter, info.Delimiter2, join.BaseTable) + "." + modules.FilterField(join.Field, info.Delimiter, info.Delimiter2) 333 } 334 } 335 } 336 337 if field.Filterable { 338 if len(sql) > 0 { 339 filterForm = append(filterForm, field.GetFilterFormFields(params, headField, sql[0]())...) 340 } else { 341 filterForm = append(filterForm, field.GetFilterFormFields(params, headField)...) 342 } 343 } 344 345 if field.Hide { 346 continue 347 } 348 if field.HideForList { 349 continue 350 } 351 thead = append(thead, TheadItem{ 352 Head: field.Head, 353 Sortable: field.Sortable, 354 Field: headField, 355 Hide: !modules.InArrayWithoutEmpty(params.Columns, headField), 356 Editable: field.EditAble, 357 EditType: field.EditType.String(), 358 EditOption: field.EditOptions, 359 Width: strconv.Itoa(field.Width) + "px", 360 }) 361 } 362 363 return thead, fields, joinFields, joins, joinTables, filterForm 364 } 365 366 func (f FieldList) GetThead(info TableInfo, params parameter.Parameters, columns []string) (Thead, string, string) { 367 var ( 368 thead = make(Thead, 0) 369 fields = "" 370 joins = "" 371 joinTables = make([]string, 0) 372 ) 373 for _, field := range f { 374 if field.Field != info.PrimaryKey && modules.InArray(columns, field.Field) && 375 !field.Joins.Valid() { 376 fields += info.Table + "." + modules.FilterField(field.Field, info.Delimiter, info.Delimiter2) + "," 377 } 378 379 headField := field.Field 380 381 if field.Joins.Valid() { 382 headField = field.Joins.Last().GetTableName(info.Delimiter, info.Delimiter2) + parameter.FilterParamJoinInfix + field.Field 383 for _, join := range field.Joins { 384 if !modules.InArray(joinTables, join.GetTableName(info.Delimiter, info.Delimiter2)) { 385 joinTables = append(joinTables, join.GetTableName(info.Delimiter, info.Delimiter2)) 386 if join.BaseTable == "" { 387 join.BaseTable = info.Table 388 } 389 joins += " left join " + modules.FilterField(join.Table, info.Delimiter, info.Delimiter2) + " " + join.TableAlias + " on " + 390 join.GetTableName(info.Delimiter, info.Delimiter2) + "." + modules.FilterField(join.JoinField, info.Delimiter, info.Delimiter2) + " = " + 391 modules.Delimiter(info.Delimiter, info.Delimiter2, join.BaseTable) + "." + modules.FilterField(join.Field, info.Delimiter, info.Delimiter2) 392 } 393 } 394 } 395 396 if field.Hide { 397 continue 398 } 399 thead = append(thead, TheadItem{ 400 Head: field.Head, 401 Sortable: field.Sortable, 402 Field: headField, 403 Hide: !modules.InArrayWithoutEmpty(params.Columns, headField), 404 Editable: field.EditAble, 405 EditType: field.EditType.String(), 406 EditOption: field.EditOptions, 407 Width: strconv.Itoa(field.Width) + "px", 408 }) 409 } 410 411 return thead, fields, joins 412 } 413 414 func (f FieldList) GetFieldFilterProcessValue(key, value, keyIndex string) string { 415 field := f.GetFieldByFieldName(key) 416 index := 0 417 if keyIndex != "" { 418 index, _ = strconv.Atoi(keyIndex) 419 } 420 if field.FilterFormFields != nil && len(field.FilterFormFields) > index { 421 if field.FilterFormFields[index].ProcessFn != nil { 422 value = field.FilterFormFields[index].ProcessFn(value) 423 } 424 } 425 return value 426 } 427 428 func (f FieldList) GetFieldJoinTable(key string) string { 429 field := f.GetFieldByFieldName(key) 430 if field.Exist() { 431 return field.Joins.Last().Table 432 } 433 return "" 434 } 435 436 func (f FieldList) GetFieldByFieldName(name string) Field { 437 for _, field := range f { 438 if field.Field == name { 439 return field 440 } 441 if JoinField(field.Joins.Last().GetTableName(), field.Field) == name { 442 return field 443 } 444 } 445 return Field{} 446 } 447 448 // Join store join table info. For example: 449 // 450 // Join { 451 // BaseTable: "users", 452 // Field: "role_id", 453 // Table: "roles", 454 // JoinField: "id", 455 // } 456 // 457 // It will generate the join table sql like: 458 // 459 // ... left join roles on roles.id = users.role_id ... 460 type Join struct { 461 Table string 462 TableAlias string 463 Field string 464 JoinField string 465 BaseTable string 466 } 467 468 type Joins []Join 469 470 func JoinField(table, field string) string { 471 return table + parameter.FilterParamJoinInfix + field 472 } 473 474 func GetJoinField(field string) string { 475 return strings.Split(field, parameter.FilterParamJoinInfix)[1] 476 } 477 478 func (j Joins) Valid() bool { 479 for i := 0; i < len(j); i++ { 480 if j[i].Valid() { 481 return true 482 } 483 } 484 return false 485 } 486 487 func (j Joins) Last() Join { 488 if len(j) > 0 { 489 return j[len(j)-1] 490 } 491 return Join{} 492 } 493 494 func (j Join) Valid() bool { 495 return j.Table != "" && j.Field != "" && j.JoinField != "" 496 } 497 498 func (j Join) GetTableName(delimiter ...string) string { 499 if j.TableAlias != "" { 500 return j.TableAlias 501 } 502 if len(delimiter) > 0 { 503 return delimiter[0] + j.Table + delimiter[1] 504 } 505 return j.Table 506 } 507 508 var JoinFieldValueDelimiter = utils.Uuid(8) 509 510 type TabGroups [][]string 511 512 func (t TabGroups) Valid() bool { 513 return len(t) > 0 514 } 515 516 func NewTabGroups(items ...string) TabGroups { 517 var t = make(TabGroups, 0) 518 return append(t, items) 519 } 520 521 func (t TabGroups) AddGroup(items ...string) TabGroups { 522 return append(t, items) 523 } 524 525 type TabHeaders []string 526 527 func (t TabHeaders) Add(header string) TabHeaders { 528 return append(t, header) 529 } 530 531 type GetDataFn func(param parameter.Parameters) ([]map[string]interface{}, int) 532 533 type DeleteFn func(ids []string) error 534 type DeleteFnWithRes func(ids []string, res error) error 535 536 type Sort uint8 537 538 const ( 539 SortDesc Sort = iota 540 SortAsc 541 ) 542 543 type primaryKey struct { 544 Type db.DatabaseType 545 Name string 546 } 547 548 type ExportProcessFn func(param parameter.Parameters) (PanelInfo, error) 549 550 // InfoPanel 551 type InfoPanel struct { 552 FieldList FieldList 553 curFieldListIndex int 554 555 Table string 556 Title string 557 Description string 558 559 // Warn: may be deprecated future. 560 TabGroups TabGroups 561 TabHeaders TabHeaders 562 563 Sort Sort 564 SortField string 565 566 PageSizeList []int 567 DefaultPageSize int 568 569 ExportType int 570 ExportProcessFn ExportProcessFn 571 572 primaryKey primaryKey 573 574 IsHideNewButton bool 575 IsHideExportButton bool 576 IsHideEditButton bool 577 IsHideDeleteButton bool 578 IsHideDetailButton bool 579 IsHideFilterButton bool 580 IsHideRowSelector bool 581 IsHidePagination bool 582 IsHideFilterArea bool 583 IsHideQueryInfo bool 584 FilterFormLayout form.Layout 585 586 FilterFormHeadWidth int 587 FilterFormInputWidth int 588 589 Wheres Wheres 590 WhereRaws WhereRaw 591 592 Callbacks Callbacks 593 594 Buttons Buttons 595 596 TableLayout string 597 598 DeleteHook DeleteFn 599 PreDeleteFn DeleteFn 600 DeleteFn DeleteFn 601 602 DeleteHookWithRes DeleteFnWithRes 603 604 GetDataFn GetDataFn 605 606 processChains DisplayProcessFnChains 607 608 ActionButtons Buttons 609 ActionButtonFold bool 610 611 DisplayGeneratorRecords map[string]struct{} 612 613 QueryFilterFn QueryFilterFn 614 UpdateParametersFns []UpdateParametersFn 615 616 Wrapper ContentWrapper 617 618 // column operation buttons 619 Action template.HTML 620 HeaderHtml template.HTML 621 FooterHtml template.HTML 622 623 PageError errors.PageError 624 PageErrorHTML template.HTML 625 626 NoCompress bool 627 HideSideBar bool 628 629 AutoRefresh uint 630 } 631 632 type Where struct { 633 Join string 634 Field string 635 Operator string 636 Arg interface{} 637 } 638 639 type Wheres []Where 640 641 func (whs Wheres) Statement(wheres, delimiter, delimiter2 string, whereArgs []interface{}, existKeys, columns []string) (string, []interface{}) { 642 pwheres := "" 643 for k, wh := range whs { 644 645 whFieldArr := strings.Split(wh.Field, ".") 646 whField := "" 647 whTable := "" 648 if len(whFieldArr) > 1 { 649 whField = whFieldArr[1] 650 whTable = whFieldArr[0] 651 } else { 652 whField = whFieldArr[0] 653 } 654 655 if modules.InArray(existKeys, whField) { 656 continue 657 } 658 659 // TODO: support like operation and join table 660 if modules.InArray(columns, whField) { 661 662 joinMark := "" 663 if k != len(whs)-1 { 664 joinMark = whs[k+1].Join 665 } 666 667 if whTable != "" { 668 pwheres += whTable + "." + modules.FilterField(whField, delimiter, delimiter2) + " " + wh.Operator + " ? " + joinMark + " " 669 } else { 670 pwheres += modules.FilterField(whField, delimiter, delimiter2) + " " + wh.Operator + " ? " + joinMark + " " 671 } 672 whereArgs = append(whereArgs, wh.Arg) 673 } 674 } 675 if wheres != "" && pwheres != "" { 676 wheres += " and " 677 } 678 return wheres + pwheres, whereArgs 679 } 680 681 type WhereRaw struct { 682 Raw string 683 Args []interface{} 684 } 685 686 func (wh WhereRaw) check() int { 687 index := 0 688 for i := 0; i < len(wh.Raw); i++ { 689 if wh.Raw[i] == ' ' { 690 continue 691 } 692 if wh.Raw[i] == 'a' { 693 if len(wh.Raw) < i+3 { 694 break 695 } else if wh.Raw[i+1] == 'n' && wh.Raw[i+2] == 'd' { 696 index = i + 3 697 } 698 } else if wh.Raw[i] == 'o' { 699 if len(wh.Raw) < i+2 { 700 break 701 } else if wh.Raw[i+1] == 'r' { 702 index = i + 2 703 } 704 } else { 705 break 706 } 707 } 708 return index 709 } 710 711 func (wh WhereRaw) Statement(wheres string, whereArgs []interface{}) (string, []interface{}) { 712 713 if wh.Raw == "" { 714 return wheres, whereArgs 715 } 716 717 if wheres != "" { 718 if wh.check() != 0 { 719 wheres += wh.Raw + " " 720 } else { 721 wheres += " and " + wh.Raw + " " 722 } 723 724 whereArgs = append(whereArgs, wh.Args...) 725 } else { 726 wheres += wh.Raw[wh.check():] + " " 727 whereArgs = append(whereArgs, wh.Args...) 728 } 729 730 return wheres, whereArgs 731 } 732 733 type Handler func(ctx *context.Context) (success bool, msg string, data interface{}) 734 735 func (h Handler) Wrap() context.Handler { 736 return func(ctx *context.Context) { 737 defer func() { 738 if err := recover(); err != nil { 739 logger.Error(err) 740 ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ 741 "code": 500, 742 "data": "", 743 "msg": "error", 744 }) 745 } 746 }() 747 748 code := 0 749 s, m, d := h(ctx) 750 751 if !s { 752 code = 500 753 } 754 ctx.JSON(http.StatusOK, map[string]interface{}{ 755 "code": code, 756 "data": d, 757 "msg": m, 758 }) 759 } 760 } 761 762 type ContentWrapper func(content template.HTML) template.HTML 763 764 type Action interface { 765 Js() template.JS 766 BtnAttribute() template.HTML 767 BtnClass() template.HTML 768 ExtContent() template.HTML 769 FooterContent() template.HTML 770 SetBtnId(btnId string) 771 SetBtnData(data interface{}) 772 GetCallbacks() context.Node 773 } 774 775 type NilAction struct{} 776 777 func (def *NilAction) SetBtnId(btnId string) {} 778 func (def *NilAction) SetBtnData(data interface{}) {} 779 func (def *NilAction) Js() template.JS { return "" } 780 func (def *NilAction) BtnAttribute() template.HTML { return "" } 781 func (def *NilAction) BtnClass() template.HTML { return "" } 782 func (def *NilAction) ExtContent() template.HTML { return "" } 783 func (def *NilAction) FooterContent() template.HTML { return "" } 784 func (def *NilAction) GetCallbacks() context.Node { return context.Node{} } 785 786 type Actions []Action 787 788 type DefaultAction struct { 789 Attr template.HTML 790 JS template.JS 791 Ext template.HTML 792 Footer template.HTML 793 } 794 795 func NewDefaultAction(attr, ext, footer template.HTML, js template.JS) *DefaultAction { 796 return &DefaultAction{Attr: attr, Ext: ext, Footer: footer, JS: js} 797 } 798 799 func (def *DefaultAction) SetBtnId(btnId string) {} 800 func (def *DefaultAction) SetBtnData(data interface{}) {} 801 func (def *DefaultAction) Js() template.JS { return def.JS } 802 func (def *DefaultAction) BtnAttribute() template.HTML { return def.Attr } 803 func (def *DefaultAction) BtnClass() template.HTML { return "" } 804 func (def *DefaultAction) ExtContent() template.HTML { return def.Ext } 805 func (def *DefaultAction) FooterContent() template.HTML { return def.Footer } 806 func (def *DefaultAction) GetCallbacks() context.Node { return context.Node{} } 807 808 var _ Action = (*DefaultAction)(nil) 809 810 var DefaultPageSizeList = []int{10, 20, 30, 50, 100} 811 812 const DefaultPageSize = 10 813 814 func NewInfoPanel(pk string) *InfoPanel { 815 return &InfoPanel{ 816 curFieldListIndex: -1, 817 PageSizeList: DefaultPageSizeList, 818 DefaultPageSize: DefaultPageSize, 819 processChains: make(DisplayProcessFnChains, 0), 820 Buttons: make(Buttons, 0), 821 Callbacks: make(Callbacks, 0), 822 DisplayGeneratorRecords: make(map[string]struct{}), 823 Wheres: make([]Where, 0), 824 WhereRaws: WhereRaw{}, 825 SortField: pk, 826 TableLayout: "auto", 827 FilterFormInputWidth: 10, 828 FilterFormHeadWidth: 2, 829 AutoRefresh: 0, 830 } 831 } 832 833 func (i *InfoPanel) Where(field string, operator string, arg interface{}) *InfoPanel { 834 i.Wheres = append(i.Wheres, Where{Field: field, Operator: operator, Arg: arg, Join: "and"}) 835 return i 836 } 837 838 func (i *InfoPanel) WhereOr(field string, operator string, arg interface{}) *InfoPanel { 839 i.Wheres = append(i.Wheres, Where{Field: field, Operator: operator, Arg: arg, Join: "or"}) 840 return i 841 } 842 843 func (i *InfoPanel) WhereRaw(raw string, arg ...interface{}) *InfoPanel { 844 i.WhereRaws.Raw = raw 845 i.WhereRaws.Args = arg 846 return i 847 } 848 849 func (i *InfoPanel) AddSelectBox(placeholder string, options FieldOptions, action Action, width ...int) *InfoPanel { 850 options = append(FieldOptions{{Value: "", Text: language.Get("All")}}, options...) 851 action.SetBtnData(options) 852 i.addButton(GetDefaultSelection(placeholder, options, action, width...)). 853 addFooterHTML(action.FooterContent()). 854 addCallback(action.GetCallbacks()) 855 856 return i 857 } 858 859 func (i *InfoPanel) ExportValue() *InfoPanel { 860 i.ExportType = 1 861 return i 862 } 863 864 func (i *InfoPanel) IsExportValue() bool { 865 return i.ExportType == 1 866 } 867 868 func (i *InfoPanel) AddButtonRaw(btn Button, action Action) *InfoPanel { 869 i.Buttons = append(i.Buttons, btn) 870 i.addFooterHTML(action.FooterContent()).addCallback(action.GetCallbacks()) 871 return i 872 } 873 874 func (i *InfoPanel) AddButton(title template.HTML, icon string, action Action, color ...template.HTML) *InfoPanel { 875 i.addButton(GetDefaultButtonGroup(title, icon, action, color...)). 876 addFooterHTML(action.FooterContent()). 877 addCallback(action.GetCallbacks()) 878 return i 879 } 880 881 func (i *InfoPanel) AddActionIconButton(icon string, action Action, ids ...string) *InfoPanel { 882 i.addActionButton(GetActionIconButton(icon, action, ids...)). 883 addFooterHTML(action.FooterContent()). 884 addCallback(action.GetCallbacks()) 885 886 return i 887 } 888 889 func (i *InfoPanel) AddActionButtonFront(title template.HTML, action Action, ids ...string) *InfoPanel { 890 i.SetActionButtonFold() 891 i.ActionButtons = append([]Button{GetActionButton(title, action, ids...)}, i.ActionButtons...) 892 i.addFooterHTML(action.FooterContent()). 893 addCallback(action.GetCallbacks()) 894 return i 895 } 896 897 func (i *InfoPanel) AddActionButton(title template.HTML, action Action, ids ...string) *InfoPanel { 898 i.SetActionButtonFold() 899 i.addActionButton(GetActionButton(title, action, ids...)). 900 addFooterHTML(action.FooterContent()). 901 addCallback(action.GetCallbacks()) 902 903 return i 904 } 905 906 func (i *InfoPanel) SetActionButtonFold() *InfoPanel { 907 i.ActionButtonFold = true 908 return i 909 } 910 911 func (i *InfoPanel) AddLimitFilter(limit int) *InfoPanel { 912 i.processChains = addLimit(limit, i.processChains) 913 return i 914 } 915 916 func (i *InfoPanel) AddTrimSpaceFilter() *InfoPanel { 917 i.processChains = addTrimSpace(i.processChains) 918 return i 919 } 920 921 func (i *InfoPanel) AddSubstrFilter(start int, end int) *InfoPanel { 922 i.processChains = addSubstr(start, end, i.processChains) 923 return i 924 } 925 926 func (i *InfoPanel) AddToTitleFilter() *InfoPanel { 927 i.processChains = addToTitle(i.processChains) 928 return i 929 } 930 931 func (i *InfoPanel) AddToUpperFilter() *InfoPanel { 932 i.processChains = addToUpper(i.processChains) 933 return i 934 } 935 936 func (i *InfoPanel) AddToLowerFilter() *InfoPanel { 937 i.processChains = addToLower(i.processChains) 938 return i 939 } 940 941 func (i *InfoPanel) AddXssFilter() *InfoPanel { 942 i.processChains = addXssFilter(i.processChains) 943 return i 944 } 945 946 func (i *InfoPanel) AddXssJsFilter() *InfoPanel { 947 i.processChains = addXssJsFilter(i.processChains) 948 return i 949 } 950 951 func (i *InfoPanel) SetExportProcessFn(fn ExportProcessFn) *InfoPanel { 952 i.ExportProcessFn = fn 953 return i 954 } 955 956 func (i *InfoPanel) SetDeleteHook(fn DeleteFn) *InfoPanel { 957 i.DeleteHook = fn 958 return i 959 } 960 961 func (i *InfoPanel) SetDeleteHookWithRes(fn DeleteFnWithRes) *InfoPanel { 962 i.DeleteHookWithRes = fn 963 return i 964 } 965 966 func (i *InfoPanel) SetQueryFilterFn(fn QueryFilterFn) *InfoPanel { 967 i.QueryFilterFn = fn 968 return i 969 } 970 971 func (i *InfoPanel) AddUpdateParametersFn(fn UpdateParametersFn) *InfoPanel { 972 i.UpdateParametersFns = append(i.UpdateParametersFns, fn) 973 return i 974 } 975 976 func (i *InfoPanel) SetWrapper(wrapper ContentWrapper) *InfoPanel { 977 i.Wrapper = wrapper 978 return i 979 } 980 981 func (i *InfoPanel) SetPreDeleteFn(fn DeleteFn) *InfoPanel { 982 i.PreDeleteFn = fn 983 return i 984 } 985 986 func (i *InfoPanel) SetDeleteFn(fn DeleteFn) *InfoPanel { 987 i.DeleteFn = fn 988 return i 989 } 990 991 func (i *InfoPanel) SetGetDataFn(fn GetDataFn) *InfoPanel { 992 i.GetDataFn = fn 993 return i 994 } 995 996 func (i *InfoPanel) SetPrimaryKey(name string, typ db.DatabaseType) *InfoPanel { 997 i.primaryKey = primaryKey{Name: name, Type: typ} 998 return i 999 } 1000 1001 func (i *InfoPanel) SetTableFixed() *InfoPanel { 1002 i.TableLayout = "fixed" 1003 return i 1004 } 1005 1006 func (i *InfoPanel) AddColumn(head string, fun FieldFilterFn) *InfoPanel { 1007 i.FieldList = append(i.FieldList, Field{ 1008 Head: head, 1009 Field: head, 1010 TypeName: db.Varchar, 1011 Sortable: false, 1012 EditAble: false, 1013 EditType: table.Text, 1014 FieldDisplay: FieldDisplay{ 1015 Display: fun, 1016 DisplayProcessChains: chooseDisplayProcessChains(i.processChains), 1017 }, 1018 }) 1019 i.curFieldListIndex++ 1020 return i 1021 } 1022 1023 func (i *InfoPanel) AddColumnButtons(head string, buttons ...Button) *InfoPanel { 1024 var content, js template.HTML 1025 for _, btn := range buttons { 1026 btn.GetAction().SetBtnId("." + btn.ID()) 1027 btnContent, btnJs := btn.Content() 1028 content += btnContent 1029 js += template.HTML(btnJs) 1030 i.FooterHtml += template.HTML(ParseTableDataTmpl(btn.GetAction().FooterContent())) 1031 i.Callbacks = i.Callbacks.AddCallback(btn.GetAction().GetCallbacks()) 1032 } 1033 i.FooterHtml += template.HTML("<script>") + template.HTML(ParseTableDataTmpl(js)) + template.HTML("</script>") 1034 i.FieldList = append(i.FieldList, Field{ 1035 Head: head, 1036 Field: head, 1037 TypeName: db.Varchar, 1038 Sortable: false, 1039 EditAble: false, 1040 EditType: table.Text, 1041 FieldDisplay: FieldDisplay{ 1042 Display: func(value FieldModel) interface{} { 1043 pk := db.GetValueFromDatabaseType(i.primaryKey.Type, value.Row[i.primaryKey.Name], i.isFromJSON()) 1044 var v = make(map[string]InfoItem) 1045 for key, item := range value.Row { 1046 itemValue := fmt.Sprintf("%v", item) 1047 v[key] = InfoItem{Value: itemValue, Content: template.HTML(itemValue)} 1048 } 1049 return template.HTML(ParseTableDataTmplWithID(pk.HTML(), string(content), v)) 1050 }, 1051 DisplayProcessChains: chooseDisplayProcessChains(i.processChains), 1052 }, 1053 }) 1054 i.curFieldListIndex++ 1055 return i 1056 } 1057 1058 func (i *InfoPanel) AddFieldTr(ctx *context.Context, head, field string, typeName db.DatabaseType) *InfoPanel { 1059 return i.AddFieldWithTranslation(ctx, head, field, typeName) 1060 } 1061 1062 func (i *InfoPanel) AddFieldWithTranslation(ctx *context.Context, head, field string, typeName db.DatabaseType) *InfoPanel { 1063 return i.AddField(language.GetWithLang(head, ctx.Lang()), field, typeName) 1064 } 1065 1066 func (i *InfoPanel) AddField(head, field string, typeName db.DatabaseType) *InfoPanel { 1067 i.FieldList = append(i.FieldList, Field{ 1068 Head: head, 1069 Field: field, 1070 TypeName: typeName, 1071 Sortable: false, 1072 Joins: make(Joins, 0), 1073 EditAble: false, 1074 EditType: table.Text, 1075 FieldDisplay: FieldDisplay{ 1076 Display: func(value FieldModel) interface{} { 1077 return value.Value 1078 }, 1079 DisplayProcessChains: chooseDisplayProcessChains(i.processChains), 1080 }, 1081 }) 1082 i.curFieldListIndex++ 1083 return i 1084 } 1085 1086 func (i *InfoPanel) AddFilter(head, field string, typeName db.DatabaseType, fn UpdateParametersFn, filterType ...FilterType) *InfoPanel { 1087 return i.AddField(head, field, typeName).FieldHide().FieldFilterable(filterType...).AddUpdateParametersFn(fn) 1088 } 1089 1090 // Field attribute setting functions 1091 // ==================================================== 1092 1093 func (i *InfoPanel) FieldDisplay(filter FieldFilterFn) *InfoPanel { 1094 i.FieldList[i.curFieldListIndex].Display = filter 1095 return i 1096 } 1097 1098 type FieldLabelParam struct { 1099 Color template.HTML 1100 Type string 1101 } 1102 1103 func (i *InfoPanel) FieldLabel(args ...FieldLabelParam) *InfoPanel { 1104 i.addDisplayChains(displayFnGens["label"].Get(args)) 1105 return i 1106 } 1107 1108 func (i *InfoPanel) FieldImage(width, height string, prefix ...string) *InfoPanel { 1109 i.addDisplayChains(displayFnGens["image"].Get(width, height, prefix)) 1110 return i 1111 } 1112 1113 func (i *InfoPanel) FieldBool(flags ...string) *InfoPanel { 1114 i.addDisplayChains(displayFnGens["bool"].Get(flags)) 1115 return i 1116 } 1117 1118 func (i *InfoPanel) FieldLink(src string, openInNewTab ...bool) *InfoPanel { 1119 i.addDisplayChains(displayFnGens["link"].Get(src, openInNewTab)) 1120 return i 1121 } 1122 1123 func (i *InfoPanel) FieldFileSize() *InfoPanel { 1124 i.addDisplayChains(displayFnGens["filesize"].Get()) 1125 return i 1126 } 1127 1128 func (i *InfoPanel) FieldDate(format string) *InfoPanel { 1129 i.addDisplayChains(displayFnGens["date"].Get(format)) 1130 return i 1131 } 1132 1133 func (i *InfoPanel) FieldIcon(icons map[string]string, defaultIcon string) *InfoPanel { 1134 i.addDisplayChains(displayFnGens["link"].Get(icons, defaultIcon)) 1135 return i 1136 } 1137 1138 type FieldDotColor string 1139 1140 const ( 1141 FieldDotColorDanger FieldDotColor = "danger" 1142 FieldDotColorInfo FieldDotColor = "info" 1143 FieldDotColorPrimary FieldDotColor = "primary" 1144 FieldDotColorSuccess FieldDotColor = "success" 1145 ) 1146 1147 func (i *InfoPanel) FieldDot(icons map[string]FieldDotColor, defaultDot FieldDotColor) *InfoPanel { 1148 i.addDisplayChains(displayFnGens["dot"].Get(icons, defaultDot)) 1149 return i 1150 } 1151 1152 type FieldProgressBarData struct { 1153 Style string 1154 Size string 1155 Max int 1156 } 1157 1158 func (i *InfoPanel) FieldProgressBar(data ...FieldProgressBarData) *InfoPanel { 1159 i.addDisplayChains(displayFnGens["progressbar"].Get(data)) 1160 return i 1161 } 1162 1163 func (i *InfoPanel) FieldLoading(data []string) *InfoPanel { 1164 i.addDisplayChains(displayFnGens["loading"].Get(data)) 1165 return i 1166 } 1167 1168 func (i *InfoPanel) FieldDownLoadable(prefix ...string) *InfoPanel { 1169 i.addDisplayChains(displayFnGens["downloadable"].Get(prefix)) 1170 return i 1171 } 1172 1173 func (i *InfoPanel) FieldCopyable(prefix ...string) *InfoPanel { 1174 i.addDisplayChains(displayFnGens["copyable"].Get(prefix)) 1175 if _, ok := i.DisplayGeneratorRecords["copyable"]; !ok { 1176 i.addFooterHTML(`<script>` + displayFnGens["copyable"].JS() + `</script>`) 1177 i.DisplayGeneratorRecords["copyable"] = struct{}{} 1178 } 1179 return i 1180 } 1181 1182 type FieldGetImgArrFn func(value string) []string 1183 1184 func (i *InfoPanel) FieldCarousel(fn FieldGetImgArrFn, size ...int) *InfoPanel { 1185 i.addDisplayChains(displayFnGens["carousel"].Get(fn, size)) 1186 return i 1187 } 1188 1189 func (i *InfoPanel) FieldQrcode() *InfoPanel { 1190 i.addDisplayChains(displayFnGens["qrcode"].Get()) 1191 if _, ok := i.DisplayGeneratorRecords["qrcode"]; !ok { 1192 i.addFooterHTML(`<script>` + displayFnGens["qrcode"].JS() + `</script>`) 1193 i.DisplayGeneratorRecords["qrcode"] = struct{}{} 1194 } 1195 return i 1196 } 1197 1198 func (i *InfoPanel) FieldWidth(width int) *InfoPanel { 1199 i.FieldList[i.curFieldListIndex].Width = width 1200 return i 1201 } 1202 1203 func (i *InfoPanel) FieldSortable() *InfoPanel { 1204 i.FieldList[i.curFieldListIndex].Sortable = true 1205 return i 1206 } 1207 1208 func (i *InfoPanel) FieldEditOptions(options FieldOptions, extra ...map[string]string) *InfoPanel { 1209 if i.FieldList[i.curFieldListIndex].EditType.IsSwitch() { 1210 if len(extra) == 0 { 1211 options[0].Extra = map[string]string{ 1212 "size": "small", 1213 "onColor": "primary", 1214 "offColor": "default", 1215 } 1216 } else { 1217 if extra[0]["size"] == "" { 1218 extra[0]["size"] = "small" 1219 } 1220 if extra[0]["onColor"] == "" { 1221 extra[0]["onColor"] = "primary" 1222 } 1223 if extra[0]["offColor"] == "" { 1224 extra[0]["offColor"] = "default" 1225 } 1226 options[0].Extra = extra[0] 1227 } 1228 } 1229 i.FieldList[i.curFieldListIndex].EditOptions = options 1230 return i 1231 } 1232 1233 func (i *InfoPanel) FieldEditAble(editType ...table.Type) *InfoPanel { 1234 i.FieldList[i.curFieldListIndex].EditAble = true 1235 if len(editType) > 0 { 1236 i.FieldList[i.curFieldListIndex].EditType = editType[0] 1237 } 1238 return i 1239 } 1240 1241 func (i *InfoPanel) FieldAsEditParam() *InfoPanel { 1242 i.FieldList[i.curFieldListIndex].IsEditParam = true 1243 return i 1244 } 1245 1246 func (i *InfoPanel) FieldAsDeleteParam() *InfoPanel { 1247 i.FieldList[i.curFieldListIndex].IsDeleteParam = true 1248 return i 1249 } 1250 1251 func (i *InfoPanel) FieldAsDetailParam() *InfoPanel { 1252 i.FieldList[i.curFieldListIndex].IsDetailParam = true 1253 return i 1254 } 1255 1256 func (i *InfoPanel) FieldFixed() *InfoPanel { 1257 i.FieldList[i.curFieldListIndex].Fixed = true 1258 return i 1259 } 1260 1261 type FilterType struct { 1262 Options FieldOptions 1263 Process func(string) string 1264 OptionExt map[string]interface{} 1265 FormType form.Type 1266 HelpMsg template.HTML 1267 Style template.HTMLAttr 1268 Operator FilterOperator 1269 Head string 1270 Placeholder string 1271 Width int 1272 HeadWidth int 1273 InputWidth int 1274 NoHead bool 1275 NoIcon bool 1276 } 1277 1278 func (i *InfoPanel) FieldFilterable(filterType ...FilterType) *InfoPanel { 1279 i.FieldList[i.curFieldListIndex].Filterable = true 1280 1281 if len(filterType) == 0 { 1282 i.FieldList[i.curFieldListIndex].FilterFormFields = append(i.FieldList[i.curFieldListIndex].FilterFormFields, 1283 FilterFormField{ 1284 Type: form.Text, 1285 Head: i.FieldList[i.curFieldListIndex].Head, 1286 Placeholder: language.Get("input") + " " + i.FieldList[i.curFieldListIndex].Head, 1287 }) 1288 } 1289 1290 for _, filter := range filterType { 1291 var ff FilterFormField 1292 ff.Operator = filter.Operator 1293 if filter.FormType == form.Default { 1294 ff.Type = form.Text 1295 } else { 1296 ff.Type = filter.FormType 1297 } 1298 ff.Head = modules.AorB(!filter.NoHead && filter.Head == "", 1299 i.FieldList[i.curFieldListIndex].Head, filter.Head) 1300 ff.Width = filter.Width 1301 ff.HeadWidth = filter.HeadWidth 1302 ff.InputWidth = filter.InputWidth 1303 ff.HelpMsg = filter.HelpMsg 1304 ff.NoIcon = filter.NoIcon 1305 ff.Style = filter.Style 1306 ff.ProcessFn = filter.Process 1307 ff.Placeholder = modules.AorB(filter.Placeholder == "", language.Get("input")+" "+ff.Head, filter.Placeholder) 1308 ff.Options = filter.Options 1309 if len(filter.OptionExt) > 0 { 1310 s, _ := json.Marshal(filter.OptionExt) 1311 ff.OptionExt = template.JS(s) 1312 } 1313 i.FieldList[i.curFieldListIndex].FilterFormFields = append(i.FieldList[i.curFieldListIndex].FilterFormFields, ff) 1314 } 1315 1316 return i 1317 } 1318 1319 func (i *InfoPanel) FieldFilterOptions(options FieldOptions) *InfoPanel { 1320 i.FieldList[i.curFieldListIndex].FilterFormFields[0].Options = options 1321 i.FieldList[i.curFieldListIndex].FilterFormFields[0].OptionExt = `{"allowClear": "true"}` 1322 return i 1323 } 1324 1325 func (i *InfoPanel) FieldFilterOptionsFromTable(table, textFieldName, valueFieldName string, process ...OptionTableQueryProcessFn) *InfoPanel { 1326 var fn OptionTableQueryProcessFn 1327 if len(process) > 0 { 1328 fn = process[0] 1329 } 1330 i.FieldList[i.curFieldListIndex].FilterFormFields[0].OptionTable = OptionTable{ 1331 Table: table, 1332 TextField: textFieldName, 1333 ValueField: valueFieldName, 1334 QueryProcessFn: fn, 1335 } 1336 return i 1337 } 1338 1339 func (i *InfoPanel) FieldFilterProcess(process func(string) string) *InfoPanel { 1340 i.FieldList[i.curFieldListIndex].FilterFormFields[0].ProcessFn = process 1341 return i 1342 } 1343 1344 func (i *InfoPanel) FieldFilterOptionExt(m map[string]interface{}) *InfoPanel { 1345 s, _ := json.Marshal(m) 1346 i.FieldList[i.curFieldListIndex].FilterFormFields[0].OptionExt = template.JS(s) 1347 return i 1348 } 1349 1350 func (i *InfoPanel) FieldFilterOnSearch(url string, handler Handler, delay ...int) *InfoPanel { 1351 ext, callback := searchJS(i.FieldList[i.curFieldListIndex].FilterFormFields[0].OptionExt, url, handler, delay...) 1352 i.FieldList[i.curFieldListIndex].FilterFormFields[0].OptionExt = ext 1353 i.Callbacks = append(i.Callbacks, callback) 1354 return i 1355 } 1356 1357 func (i *InfoPanel) FieldFilterOnChooseCustom(js template.HTML) *InfoPanel { 1358 i.FooterHtml += chooseCustomJS(i.FieldList[i.curFieldListIndex].Field, js) 1359 return i 1360 } 1361 1362 func (i *InfoPanel) FieldFilterOnChooseMap(m map[string]LinkField) *InfoPanel { 1363 i.FooterHtml += chooseMapJS(i.FieldList[i.curFieldListIndex].Field, m) 1364 return i 1365 } 1366 1367 func (i *InfoPanel) FieldFilterOnChoose(val, field string, value template.HTML) *InfoPanel { 1368 i.FooterHtml += chooseJS(i.FieldList[i.curFieldListIndex].Field, field, val, value) 1369 return i 1370 } 1371 1372 func (i *InfoPanel) OperationURL(id string) string { 1373 return config.Url("/operation/" + utils.WrapURL(id)) 1374 } 1375 1376 func (i *InfoPanel) FieldFilterOnChooseAjax(field, url string, handler Handler) *InfoPanel { 1377 js, callback := chooseAjax(i.FieldList[i.curFieldListIndex].Field, field, i.OperationURL(url), handler) 1378 i.FooterHtml += js 1379 i.Callbacks = append(i.Callbacks, callback) 1380 return i 1381 } 1382 1383 func (i *InfoPanel) FieldFilterOnChooseHide(value string, field ...string) *InfoPanel { 1384 i.FooterHtml += chooseHideJS(i.FieldList[i.curFieldListIndex].Field, []string{value}, field...) 1385 return i 1386 } 1387 1388 func (i *InfoPanel) FieldFilterOnChooseShow(value string, field ...string) *InfoPanel { 1389 i.FooterHtml += chooseShowJS(i.FieldList[i.curFieldListIndex].Field, []string{value}, field...) 1390 return i 1391 } 1392 1393 func (i *InfoPanel) FieldFilterOnChooseDisable(value string, field ...string) *InfoPanel { 1394 i.FooterHtml += chooseDisableJS(i.FieldList[i.curFieldListIndex].Field, []string{value}, field...) 1395 return i 1396 } 1397 1398 func (i *InfoPanel) FieldHide() *InfoPanel { 1399 i.FieldList[i.curFieldListIndex].Hide = true 1400 return i 1401 } 1402 1403 func (i *InfoPanel) FieldHideForList() *InfoPanel { 1404 i.FieldList[i.curFieldListIndex].HideForList = true 1405 return i 1406 } 1407 1408 func (i *InfoPanel) FieldJoin(join Join) *InfoPanel { 1409 i.FieldList[i.curFieldListIndex].Joins = append(i.FieldList[i.curFieldListIndex].Joins, join) 1410 return i 1411 } 1412 1413 func (i *InfoPanel) FieldLimit(limit int) *InfoPanel { 1414 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddLimit(limit) 1415 return i 1416 } 1417 1418 func (i *InfoPanel) FieldTrimSpace() *InfoPanel { 1419 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddTrimSpace() 1420 return i 1421 } 1422 1423 func (i *InfoPanel) FieldSubstr(start int, end int) *InfoPanel { 1424 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddSubstr(start, end) 1425 return i 1426 } 1427 1428 func (i *InfoPanel) FieldToTitle() *InfoPanel { 1429 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddToTitle() 1430 return i 1431 } 1432 1433 func (i *InfoPanel) FieldToUpper() *InfoPanel { 1434 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddToUpper() 1435 return i 1436 } 1437 1438 func (i *InfoPanel) FieldToLower() *InfoPanel { 1439 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].AddToLower() 1440 return i 1441 } 1442 1443 func (i *InfoPanel) FieldXssFilter() *InfoPanel { 1444 i.FieldList[i.curFieldListIndex].DisplayProcessChains = i.FieldList[i.curFieldListIndex].DisplayProcessChains. 1445 Add(func(value FieldModel) interface{} { 1446 return html.EscapeString(value.Value) 1447 }) 1448 return i 1449 } 1450 1451 // InfoPanel attribute setting functions 1452 // ==================================================== 1453 1454 func (i *InfoPanel) SetTable(table string) *InfoPanel { 1455 i.Table = table 1456 return i 1457 } 1458 1459 func (i *InfoPanel) SetPageSizeList(pageSizeList []int) *InfoPanel { 1460 i.PageSizeList = pageSizeList 1461 return i 1462 } 1463 1464 func (i *InfoPanel) SetDefaultPageSize(defaultPageSize int) *InfoPanel { 1465 i.DefaultPageSize = defaultPageSize 1466 return i 1467 } 1468 1469 func (i *InfoPanel) GetPageSizeList() []string { 1470 var pageSizeList = make([]string, len(i.PageSizeList)) 1471 for j := 0; j < len(i.PageSizeList); j++ { 1472 pageSizeList[j] = strconv.Itoa(i.PageSizeList[j]) 1473 } 1474 return pageSizeList 1475 } 1476 1477 func (i *InfoPanel) GetSort() string { 1478 switch i.Sort { 1479 case SortAsc: 1480 return "asc" 1481 default: 1482 return "desc" 1483 } 1484 } 1485 1486 func (i *InfoPanel) SetTitle(title string) *InfoPanel { 1487 i.Title = title 1488 return i 1489 } 1490 1491 func (i *InfoPanel) SetTabGroups(groups TabGroups) *InfoPanel { 1492 i.TabGroups = groups 1493 return i 1494 } 1495 1496 func (i *InfoPanel) SetTabHeaders(headers ...string) *InfoPanel { 1497 i.TabHeaders = headers 1498 return i 1499 } 1500 1501 func (i *InfoPanel) SetDescription(desc string) *InfoPanel { 1502 i.Description = desc 1503 return i 1504 } 1505 1506 func (i *InfoPanel) SetFilterFormLayout(layout form.Layout) *InfoPanel { 1507 i.FilterFormLayout = layout 1508 return i 1509 } 1510 1511 func (i *InfoPanel) SetFilterFormHeadWidth(w int) *InfoPanel { 1512 i.FilterFormHeadWidth = w 1513 return i 1514 } 1515 1516 func (i *InfoPanel) SetFilterFormInputWidth(w int) *InfoPanel { 1517 i.FilterFormInputWidth = w 1518 return i 1519 } 1520 1521 func (i *InfoPanel) SetSortField(field string) *InfoPanel { 1522 i.SortField = field 1523 return i 1524 } 1525 1526 func (i *InfoPanel) SetSortAsc() *InfoPanel { 1527 i.Sort = SortAsc 1528 return i 1529 } 1530 1531 func (i *InfoPanel) SetSortDesc() *InfoPanel { 1532 i.Sort = SortDesc 1533 return i 1534 } 1535 1536 func (i *InfoPanel) SetAction(action template.HTML) *InfoPanel { 1537 i.Action = action 1538 return i 1539 } 1540 1541 func (i *InfoPanel) SetHeaderHtml(header template.HTML) *InfoPanel { 1542 i.HeaderHtml += header 1543 return i 1544 } 1545 1546 func (i *InfoPanel) SetFooterHtml(footer template.HTML) *InfoPanel { 1547 i.FooterHtml += footer 1548 return i 1549 } 1550 1551 func (i *InfoPanel) HasError() bool { 1552 return i.PageError != nil 1553 } 1554 1555 func (i *InfoPanel) SetError(err errors.PageError, content ...template.HTML) *InfoPanel { 1556 i.PageError = err 1557 if len(content) > 0 { 1558 i.PageErrorHTML = content[0] 1559 } 1560 return i 1561 } 1562 1563 func (i *InfoPanel) SetNoCompress() *InfoPanel { 1564 i.NoCompress = true 1565 return i 1566 } 1567 1568 func (i *InfoPanel) SetHideSideBar() *InfoPanel { 1569 i.HideSideBar = true 1570 return i 1571 } 1572 1573 func (i *InfoPanel) SetAutoRefresh(interval uint) *InfoPanel { 1574 i.AutoRefresh = interval 1575 return i 1576 } 1577 1578 func (i *InfoPanel) Set404Error(content ...template.HTML) *InfoPanel { 1579 i.SetError(errors.PageError404, content...) 1580 return i 1581 } 1582 1583 func (i *InfoPanel) Set403Error(content ...template.HTML) *InfoPanel { 1584 i.SetError(errors.PageError403, content...) 1585 return i 1586 } 1587 1588 func (i *InfoPanel) Set400Error(content ...template.HTML) *InfoPanel { 1589 i.SetError(errors.PageError401, content...) 1590 return i 1591 } 1592 1593 func (i *InfoPanel) Set500Error(content ...template.HTML) *InfoPanel { 1594 i.SetError(errors.PageError500, content...) 1595 return i 1596 } 1597 1598 func (i *InfoPanel) HideNewButton() *InfoPanel { 1599 i.IsHideNewButton = true 1600 return i 1601 } 1602 1603 func (i *InfoPanel) HideExportButton() *InfoPanel { 1604 i.IsHideExportButton = true 1605 return i 1606 } 1607 1608 func (i *InfoPanel) HideFilterButton() *InfoPanel { 1609 i.IsHideFilterButton = true 1610 return i 1611 } 1612 1613 func (i *InfoPanel) HideRowSelector() *InfoPanel { 1614 i.IsHideRowSelector = true 1615 return i 1616 } 1617 1618 func (i *InfoPanel) HidePagination() *InfoPanel { 1619 i.IsHidePagination = true 1620 return i 1621 } 1622 1623 func (i *InfoPanel) HideFilterArea() *InfoPanel { 1624 i.IsHideFilterArea = true 1625 return i 1626 } 1627 1628 func (i *InfoPanel) HideQueryInfo() *InfoPanel { 1629 i.IsHideQueryInfo = true 1630 return i 1631 } 1632 1633 func (i *InfoPanel) HideEditButton() *InfoPanel { 1634 i.IsHideEditButton = true 1635 return i 1636 } 1637 1638 func (i *InfoPanel) HideDeleteButton() *InfoPanel { 1639 i.IsHideDeleteButton = true 1640 return i 1641 } 1642 1643 func (i *InfoPanel) HideDetailButton() *InfoPanel { 1644 i.IsHideDetailButton = true 1645 return i 1646 } 1647 1648 func (i *InfoPanel) HideCheckBoxColumn() *InfoPanel { 1649 return i.HideColumn(1) 1650 } 1651 1652 func (i *InfoPanel) HideColumn(n int) *InfoPanel { 1653 i.AddCSS(template.CSS(fmt.Sprintf(` 1654 .box-body table.table tbody tr td:nth-child(%v), .box-body table.table tbody tr th:nth-child(%v) { 1655 display: none; 1656 }`, n, n))) 1657 return i 1658 } 1659 1660 func (i *InfoPanel) addFooterHTML(footer template.HTML) *InfoPanel { 1661 i.FooterHtml += template.HTML(ParseTableDataTmpl(footer)) 1662 return i 1663 } 1664 1665 func (i *InfoPanel) AddCSS(css template.CSS) *InfoPanel { 1666 return i.addFooterHTML(template.HTML("<style>" + css + "</style>")) 1667 } 1668 1669 func (i *InfoPanel) AddJS(js template.JS) *InfoPanel { 1670 return i.addFooterHTML(template.HTML("<script>" + js + "</script>")) 1671 } 1672 1673 func (i *InfoPanel) AddJSModule(js template.JS) *InfoPanel { 1674 return i.addFooterHTML(template.HTML("<script type='module'>" + js + "</script>")) 1675 } 1676 1677 func (i *InfoPanel) addCallback(node context.Node) *InfoPanel { 1678 i.Callbacks = i.Callbacks.AddCallback(node) 1679 return i 1680 } 1681 1682 func (i *InfoPanel) addButton(btn Button) *InfoPanel { 1683 i.Buttons = append(i.Buttons, btn) 1684 return i 1685 } 1686 1687 func (i *InfoPanel) addActionButton(btn Button) *InfoPanel { 1688 i.ActionButtons = append(i.ActionButtons, btn) 1689 return i 1690 } 1691 1692 func (i *InfoPanel) isFromJSON() bool { 1693 return i.GetDataFn != nil 1694 } 1695 1696 func (i *InfoPanel) addDisplayChains(fn FieldFilterFn) *InfoPanel { 1697 i.FieldList[i.curFieldListIndex].DisplayProcessChains = 1698 i.FieldList[i.curFieldListIndex].DisplayProcessChains.Add(fn) 1699 return i 1700 }