bootstrap-editable.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* eslint-disable no-unused-vars */
  2. /**
  3. * @author zhixin wen <wenzhixin2010@gmail.com>
  4. * extensions: https://github.com/vitalets/x-editable
  5. */
  6. const Utils = $.fn.bootstrapTable.utils
  7. $.extend($.fn.bootstrapTable.defaults, {
  8. editable: true,
  9. onEditableInit () {
  10. return false
  11. },
  12. onEditableSave (field, row, rowIndex, oldValue, $el) {
  13. return false
  14. },
  15. onEditableShown (field, row, $el, editable) {
  16. return false
  17. },
  18. onEditableHidden (field, row, $el, reason) {
  19. return false
  20. }
  21. })
  22. $.extend($.fn.bootstrapTable.columnDefaults, {
  23. alwaysUseFormatter: false
  24. })
  25. $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
  26. 'editable-init.bs.table': 'onEditableInit',
  27. 'editable-save.bs.table': 'onEditableSave',
  28. 'editable-shown.bs.table': 'onEditableShown',
  29. 'editable-hidden.bs.table': 'onEditableHidden'
  30. })
  31. $.BootstrapTable = class extends $.BootstrapTable {
  32. initTable () {
  33. super.initTable()
  34. if (!this.options.editable) {
  35. return
  36. }
  37. this.editedCells = []
  38. $.each(this.columns, (i, column) => {
  39. if (!column.editable) {
  40. return
  41. }
  42. const editableOptions = {}
  43. const editableDataMarkup = []
  44. const editableDataPrefix = 'editable-'
  45. const processDataOptions = (key, value) => {
  46. // Replace camel case with dashes.
  47. const dashKey = key.replace(/([A-Z])/g, $1 => `-${$1.toLowerCase()}`)
  48. if (dashKey.indexOf(editableDataPrefix) === 0) {
  49. editableOptions[dashKey.replace(editableDataPrefix, 'data-')] = value
  50. }
  51. }
  52. $.each(this.options, processDataOptions)
  53. column.formatter = column.formatter || (value => value)
  54. column._formatter = column._formatter ? column._formatter : column.formatter
  55. column.formatter = (value, row, index) => {
  56. let result = Utils.calculateObjectValue(column, column._formatter, [value, row, index], value)
  57. result = typeof result === 'undefined' || result === null ? this.options.undefinedText : result
  58. if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) {
  59. const uniqueId = Utils.getItemField(row, this.options.uniqueId, false)
  60. if ($.inArray(column.field + uniqueId, this.editedCells) !== -1) {
  61. result = value
  62. }
  63. }
  64. $.each(column, processDataOptions)
  65. $.each(editableOptions, (key, value) => {
  66. editableDataMarkup.push(` ${key}="${value}"`)
  67. })
  68. let noEditFormatter = false
  69. const editableOpts = Utils.calculateObjectValue(column,
  70. column.editable, [index, row], {})
  71. if (editableOpts.hasOwnProperty('noEditFormatter')) {
  72. noEditFormatter = editableOpts.noEditFormatter(value, row, index)
  73. }
  74. if (noEditFormatter === false) {
  75. return `<a href="javascript:void(0)"
  76. data-name="${column.field}"
  77. data-pk="${row[this.options.idField]}"
  78. data-value="${result}"
  79. ${editableDataMarkup.join('')}></a>`
  80. }
  81. return noEditFormatter
  82. }
  83. })
  84. }
  85. initBody (fixedScroll) {
  86. super.initBody(fixedScroll)
  87. if (!this.options.editable) {
  88. return
  89. }
  90. $.each(this.columns, (i, column) => {
  91. if (!column.editable) {
  92. return
  93. }
  94. const data = this.getData({ escape: true })
  95. const $field = this.$body.find(`a[data-name="${column.field}"]`)
  96. $field.each((i, element) => {
  97. const $element = $(element)
  98. const $tr = $element.closest('tr')
  99. const index = $tr.data('index')
  100. const row = data[index]
  101. const editableOpts = Utils.calculateObjectValue(column,
  102. column.editable, [index, row, $element], {})
  103. $element.editable(editableOpts)
  104. })
  105. $field.off('save').on('save', ({ currentTarget }, { submitValue }) => {
  106. const $this = $(currentTarget)
  107. const data = this.getData()
  108. const rowIndex = $this.parents('tr[data-index]').data('index')
  109. const row = data[rowIndex]
  110. const oldValue = row[column.field]
  111. if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) {
  112. const uniqueId = Utils.getItemField(row, this.options.uniqueId, false)
  113. if ($.inArray(column.field + uniqueId, this.editedCells) === -1) {
  114. this.editedCells.push(column.field + uniqueId)
  115. }
  116. }
  117. submitValue = Utils.escapeHTML(submitValue)
  118. $this.data('value', submitValue)
  119. row[column.field] = submitValue
  120. this.trigger('editable-save', column.field, row, rowIndex, oldValue, $this)
  121. this.initBody()
  122. })
  123. $field.off('shown').on('shown', ({ currentTarget }, editable) => {
  124. const $this = $(currentTarget)
  125. const data = this.getData()
  126. const rowIndex = $this.parents('tr[data-index]').data('index')
  127. const row = data[rowIndex]
  128. this.trigger('editable-shown', column.field, row, $this, editable)
  129. })
  130. $field.off('hidden').on('hidden', ({ currentTarget }, reason) => {
  131. const $this = $(currentTarget)
  132. const data = this.getData()
  133. const rowIndex = $this.parents('tr[data-index]').data('index')
  134. const row = data[rowIndex]
  135. this.trigger('editable-hidden', column.field, row, $this, reason)
  136. })
  137. })
  138. this.trigger('editable-init')
  139. }
  140. getData (params) {
  141. const data = super.getData(params)
  142. if (params && params.escape) {
  143. for (const row of data) {
  144. for (const [key, value] of Object.entries(row)) {
  145. row[key] = Utils.unescapeHTML(value)
  146. }
  147. }
  148. }
  149. return data
  150. }
  151. }