index.js 8.1 KB

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