index.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. normalizeAccent (value) {
  67. if (typeof value !== 'string') {
  68. return value
  69. }
  70. return value.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
  71. },
  72. updateFieldGroup (columns) {
  73. const allColumns = [].concat(...columns)
  74. for (const c of columns) {
  75. for (const r of c) {
  76. if (r.colspanGroup > 1) {
  77. let colspan = 0
  78. for (let i = r.colspanIndex; i < r.colspanIndex + r.colspanGroup; i++) {
  79. const column = allColumns.find(col => col.fieldIndex === i)
  80. if (column.visible) {
  81. colspan++
  82. }
  83. }
  84. r.colspan = colspan
  85. r.visible = colspan > 0
  86. }
  87. }
  88. }
  89. },
  90. getScrollBarWidth () {
  91. if (this.cachedWidth === undefined) {
  92. const $inner = $('<div/>').addClass('fixed-table-scroll-inner')
  93. const $outer = $('<div/>').addClass('fixed-table-scroll-outer')
  94. $outer.append($inner)
  95. $('body').append($outer)
  96. const w1 = $inner[0].offsetWidth
  97. $outer.css('overflow', 'scroll')
  98. let w2 = $inner[0].offsetWidth
  99. if (w1 === w2) {
  100. w2 = $outer[0].clientWidth
  101. }
  102. $outer.remove()
  103. this.cachedWidth = w1 - w2
  104. }
  105. return this.cachedWidth
  106. },
  107. calculateObjectValue (self, name, args, defaultValue) {
  108. let func = name
  109. if (typeof name === 'string') {
  110. // support obj.func1.func2
  111. const names = name.split('.')
  112. if (names.length > 1) {
  113. func = window
  114. for (const f of names) {
  115. func = func[f]
  116. }
  117. } else {
  118. func = window[name]
  119. }
  120. }
  121. if (func !== null && typeof func === 'object') {
  122. return func
  123. }
  124. if (typeof func === 'function') {
  125. return func.apply(self, args || [])
  126. }
  127. if (
  128. !func &&
  129. typeof name === 'string' &&
  130. this.sprintf(name, ...args)
  131. ) {
  132. return this.sprintf(name, ...args)
  133. }
  134. return defaultValue
  135. },
  136. compareObjects (objectA, objectB, compareLength) {
  137. const aKeys = Object.keys(objectA)
  138. const bKeys = Object.keys(objectB)
  139. if (compareLength && aKeys.length !== bKeys.length) {
  140. return false
  141. }
  142. for (const key of aKeys) {
  143. if (bKeys.includes(key) && objectA[key] !== objectB[key]) {
  144. return false
  145. }
  146. }
  147. return true
  148. },
  149. escapeHTML (text) {
  150. if (typeof text === 'string') {
  151. return text
  152. .replace(/&/g, '&amp;')
  153. .replace(/</g, '&lt;')
  154. .replace(/>/g, '&gt;')
  155. .replace(/"/g, '&quot;')
  156. .replace(/'/g, '&#039;')
  157. .replace(/`/g, '&#x60;')
  158. }
  159. return text
  160. },
  161. unescapeHTML (text) {
  162. if (typeof text === 'string') {
  163. return text
  164. .replace(/&amp;/g, '&')
  165. .replace(/&lt;/g, '<')
  166. .replace(/&gt;/g, '>')
  167. .replace(/&quot;/g, '"')
  168. .replace(/&#039;/g, '\'')
  169. .replace(/&#x60;/g, '`')
  170. }
  171. return text
  172. },
  173. getRealDataAttr (dataAttr) {
  174. for (const [attr, value] of Object.entries(dataAttr)) {
  175. const auxAttr = attr.split(/(?=[A-Z])/).join('-').toLowerCase()
  176. if (auxAttr !== attr) {
  177. dataAttr[auxAttr] = value
  178. delete dataAttr[attr]
  179. }
  180. }
  181. return dataAttr
  182. },
  183. getItemField (item, field, escape) {
  184. let value = item
  185. if (typeof field !== 'string' || item.hasOwnProperty(field)) {
  186. return escape ? this.escapeHTML(item[field]) : item[field]
  187. }
  188. const props = field.split('.')
  189. for (const p of props) {
  190. value = value && value[p]
  191. }
  192. return escape ? this.escapeHTML(value) : value
  193. },
  194. isIEBrowser () {
  195. return navigator.userAgent.includes('MSIE ') ||
  196. /Trident.*rv:11\./.test(navigator.userAgent)
  197. },
  198. findIndex (items, item) {
  199. for (const it of items) {
  200. if (JSON.stringify(it) === JSON.stringify(item)) {
  201. return items.indexOf(it)
  202. }
  203. }
  204. return -1
  205. },
  206. trToData (columns, $els) {
  207. const data = []
  208. const m = []
  209. $els.each((y, el) => {
  210. const row = {}
  211. // save tr's id, class and data-* attributes
  212. row._id = $(el).attr('id')
  213. row._class = $(el).attr('class')
  214. row._data = this.getRealDataAttr($(el).data())
  215. $(el).find('>td,>th').each((_x, el) => {
  216. const cspan = +$(el).attr('colspan') || 1
  217. const rspan = +$(el).attr('rowspan') || 1
  218. let x = _x
  219. // skip already occupied cells in current row
  220. for (; m[y] && m[y][x]; x++) {
  221. // ignore
  222. }
  223. // mark matrix elements occupied by current cell with true
  224. for (let tx = x; tx < x + cspan; tx++) {
  225. for (let ty = y; ty < y + rspan; ty++) {
  226. if (!m[ty]) { // fill missing rows
  227. m[ty] = []
  228. }
  229. m[ty][tx] = true
  230. }
  231. }
  232. const field = columns[x].field
  233. row[field] = $(el).html().trim()
  234. // save td's id, class and data-* attributes
  235. row[`_${field}_id`] = $(el).attr('id')
  236. row[`_${field}_class`] = $(el).attr('class')
  237. row[`_${field}_rowspan`] = $(el).attr('rowspan')
  238. row[`_${field}_colspan`] = $(el).attr('colspan')
  239. row[`_${field}_title`] = $(el).attr('title')
  240. row[`_${field}_data`] = this.getRealDataAttr($(el).data())
  241. })
  242. data.push(row)
  243. })
  244. return data
  245. },
  246. sort (a, b, order, sortStable, aPosition, bPosition) {
  247. if (a === undefined || a === null) {
  248. a = ''
  249. }
  250. if (b === undefined || b === null) {
  251. b = ''
  252. }
  253. if (sortStable && a === b) {
  254. a = aPosition
  255. b = bPosition
  256. }
  257. // If both values are numeric, do a numeric comparison
  258. if (this.isNumeric(a) && this.isNumeric(b)) {
  259. // Convert numerical values form string to float.
  260. a = parseFloat(a)
  261. b = parseFloat(b)
  262. if (a < b) {
  263. return order * -1
  264. }
  265. if (a > b) {
  266. return order
  267. }
  268. return 0
  269. }
  270. if (a === b) {
  271. return 0
  272. }
  273. // If value is not a string, convert to string
  274. if (typeof a !== 'string') {
  275. a = a.toString()
  276. }
  277. if (a.localeCompare(b) === -1) {
  278. return order * -1
  279. }
  280. return order
  281. },
  282. getResizeEventName (id = '') {
  283. id = id || `${+new Date()}${~~(Math.random() * 1000000)}`
  284. return `resize.bootstrap-table-${id}`
  285. },
  286. hasDetailViewIcon (options) {
  287. return options.detailView && options.detailViewIcon && !options.cardView
  288. },
  289. checkAutoMergeCells (data) {
  290. for (const row of data) {
  291. for (const key of Object.keys(row)) {
  292. if (key.startsWith('_') && (key.endsWith('_rowspan') || key.endsWith('_colspan'))) {
  293. return true
  294. }
  295. }
  296. }
  297. return false
  298. }
  299. }