index.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. export default {
  2. // it only does '%s', and return '' when arguments are undefined
  3. sprintf (_str, ...args) {
  4. let flag = true
  5. let i = 0
  6. const str = _str.replace(/%s/g, () => {
  7. const arg = args[i++]
  8. if (typeof arg === 'undefined') {
  9. flag = false
  10. return ''
  11. }
  12. return arg
  13. })
  14. return flag ? str : ''
  15. },
  16. isEmptyObject (obj = {}) {
  17. return Object.entries(obj).length === 0 && obj.constructor === Object
  18. },
  19. isNumeric (n) {
  20. return !isNaN(parseFloat(n)) && isFinite(n)
  21. },
  22. getFieldTitle (list, value) {
  23. for (const item of list) {
  24. if (item.field === value) {
  25. return item.title
  26. }
  27. }
  28. return ''
  29. },
  30. setFieldIndex (columns) {
  31. let totalCol = 0
  32. const flag = []
  33. for (const column of columns[0]) {
  34. totalCol += column.colspan || 1
  35. }
  36. for (let i = 0; i < columns.length; i++) {
  37. flag[i] = []
  38. for (let j = 0; j < totalCol; j++) {
  39. flag[i][j] = false
  40. }
  41. }
  42. for (let i = 0; i < columns.length; i++) {
  43. for (const r of columns[i]) {
  44. const rowspan = r.rowspan || 1
  45. const colspan = r.colspan || 1
  46. const index = flag[i].indexOf(false)
  47. r.colspanIndex = index
  48. if (colspan === 1) {
  49. r.fieldIndex = index
  50. // when field is undefined, use index instead
  51. if (typeof r.field === 'undefined') {
  52. r.field = index
  53. }
  54. } else {
  55. r.colspanGroup = r.colspan
  56. }
  57. for (let k = 0; k < rowspan; k++) {
  58. flag[i + k][index] = true
  59. }
  60. for (let k = 0; k < colspan; k++) {
  61. flag[i][index + k] = true
  62. }
  63. }
  64. }
  65. },
  66. updateFieldGroup (columns) {
  67. const allColumns = [].concat(...columns)
  68. for (const c of columns) {
  69. for (const r of c) {
  70. if (r.colspanGroup > 1) {
  71. let colspan = 0
  72. for (let i = r.colspanIndex; i < r.colspanIndex + r.colspanGroup; i++) {
  73. const column = allColumns.find(col => col.fieldIndex === i)
  74. if (column.visible) {
  75. colspan++
  76. }
  77. }
  78. r.colspan = colspan
  79. r.visible = colspan > 0
  80. }
  81. }
  82. }
  83. },
  84. getScrollBarWidth () {
  85. if (this.cachedWidth === undefined) {
  86. const $inner = $('<div/>').addClass('fixed-table-scroll-inner')
  87. const $outer = $('<div/>').addClass('fixed-table-scroll-outer')
  88. $outer.append($inner)
  89. $('body').append($outer)
  90. const w1 = $inner[0].offsetWidth
  91. $outer.css('overflow', 'scroll')
  92. let w2 = $inner[0].offsetWidth
  93. if (w1 === w2) {
  94. w2 = $outer[0].clientWidth
  95. }
  96. $outer.remove()
  97. this.cachedWidth = w1 - w2
  98. }
  99. return this.cachedWidth
  100. },
  101. calculateObjectValue (self, name, args, defaultValue) {
  102. let func = name
  103. if (typeof name === 'string') {
  104. // support obj.func1.func2
  105. const names = name.split('.')
  106. if (names.length > 1) {
  107. func = window
  108. for (const f of names) {
  109. func = func[f]
  110. }
  111. } else {
  112. func = window[name]
  113. }
  114. }
  115. if (func !== null && typeof func === 'object') {
  116. return func
  117. }
  118. if (typeof func === 'function') {
  119. return func.apply(self, args || [])
  120. }
  121. if (
  122. !func &&
  123. typeof name === 'string' &&
  124. this.sprintf(name, ...args)
  125. ) {
  126. return this.sprintf(name, ...args)
  127. }
  128. return defaultValue
  129. },
  130. compareObjects (objectA, objectB, compareLength) {
  131. const aKeys = Object.keys(objectA)
  132. const bKeys = Object.keys(objectB)
  133. if (compareLength && aKeys.length !== bKeys.length) {
  134. return false
  135. }
  136. for (const key of aKeys) {
  137. if (bKeys.includes(key) && objectA[key] !== objectB[key]) {
  138. return false
  139. }
  140. }
  141. return true
  142. },
  143. escapeHTML (text) {
  144. if (typeof text === 'string') {
  145. return text
  146. .replace(/&/g, '&amp;')
  147. .replace(/</g, '&lt;')
  148. .replace(/>/g, '&gt;')
  149. .replace(/"/g, '&quot;')
  150. .replace(/'/g, '&#039;')
  151. .replace(/`/g, '&#x60;')
  152. }
  153. return text
  154. },
  155. unescapeHTML (text) {
  156. if (typeof text === 'string') {
  157. return text
  158. .replace(/&amp;/g, '&')
  159. .replace(/&lt;/g, '<')
  160. .replace(/&gt;/g, '>')
  161. .replace(/&quot;/g, '"')
  162. .replace(/&#039;/g, '\'')
  163. .replace(/&#x60;/g, '`')
  164. }
  165. return text
  166. },
  167. getRealDataAttr (dataAttr) {
  168. for (const [attr, value] of Object.entries(dataAttr)) {
  169. const auxAttr = attr.split(/(?=[A-Z])/).join('-').toLowerCase()
  170. if (auxAttr !== attr) {
  171. dataAttr[auxAttr] = value
  172. delete dataAttr[attr]
  173. }
  174. }
  175. return dataAttr
  176. },
  177. getItemField (item, field, escape) {
  178. let value = item
  179. if (typeof field !== 'string' || item.hasOwnProperty(field)) {
  180. return escape ? this.escapeHTML(item[field]) : item[field]
  181. }
  182. const props = field.split('.')
  183. for (const p of props) {
  184. value = value && value[p]
  185. }
  186. return escape ? this.escapeHTML(value) : value
  187. },
  188. isIEBrowser () {
  189. return navigator.userAgent.includes('MSIE ') ||
  190. /Trident.*rv:11\./.test(navigator.userAgent)
  191. },
  192. findIndex (items, item) {
  193. for (const it of items) {
  194. if (JSON.stringify(it) === JSON.stringify(item)) {
  195. return items.indexOf(it)
  196. }
  197. }
  198. return -1
  199. },
  200. trToData (columns, $els) {
  201. const data = []
  202. const m = []
  203. $els.each((y, el) => {
  204. const row = {}
  205. // save tr's id, class and data-* attributes
  206. row._id = $(el).attr('id')
  207. row._class = $(el).attr('class')
  208. row._data = this.getRealDataAttr($(el).data())
  209. $(el).find('>td,>th').each((_x, el) => {
  210. const cspan = +$(el).attr('colspan') || 1
  211. const rspan = +$(el).attr('rowspan') || 1
  212. let x = _x
  213. // skip already occupied cells in current row
  214. for (; m[y] && m[y][x]; x++) {
  215. // ignore
  216. }
  217. // mark matrix elements occupied by current cell with true
  218. for (let tx = x; tx < x + cspan; tx++) {
  219. for (let ty = y; ty < y + rspan; ty++) {
  220. if (!m[ty]) { // fill missing rows
  221. m[ty] = []
  222. }
  223. m[ty][tx] = true
  224. }
  225. }
  226. const field = columns[x].field
  227. row[field] = $(el).html().trim()
  228. // save td's id, class and data-* attributes
  229. row[`_${field}_id`] = $(el).attr('id')
  230. row[`_${field}_class`] = $(el).attr('class')
  231. row[`_${field}_rowspan`] = $(el).attr('rowspan')
  232. row[`_${field}_colspan`] = $(el).attr('colspan')
  233. row[`_${field}_title`] = $(el).attr('title')
  234. row[`_${field}_data`] = this.getRealDataAttr($(el).data())
  235. })
  236. data.push(row)
  237. })
  238. return data
  239. },
  240. sort (a, b, order, sortStable, aPosition, bPosition) {
  241. if (a === undefined || a === null) {
  242. a = ''
  243. }
  244. if (b === undefined || b === null) {
  245. b = ''
  246. }
  247. if (sortStable && a === b) {
  248. a = aPosition
  249. b = bPosition
  250. }
  251. // If both values are numeric, do a numeric comparison
  252. if (this.isNumeric(a) && this.isNumeric(b)) {
  253. // Convert numerical values form string to float.
  254. a = parseFloat(a)
  255. b = parseFloat(b)
  256. if (a < b) {
  257. return order * -1
  258. }
  259. if (a > b) {
  260. return order
  261. }
  262. return 0
  263. }
  264. if (a === b) {
  265. return 0
  266. }
  267. // If value is not a string, convert to string
  268. if (typeof a !== 'string') {
  269. a = a.toString()
  270. }
  271. if (a.localeCompare(b) === -1) {
  272. return order * -1
  273. }
  274. return order
  275. },
  276. getResizeEventName (id = '') {
  277. id = id || `${+new Date()}${~~(Math.random() * 1000000)}`
  278. return `resize.bootstrap-table-${id}`
  279. },
  280. hasDetailViewIcon (options) {
  281. return options.detailView && options.detailViewIcon && !options.cardView
  282. }
  283. }