bootstrap-table-cookie.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /**
  2. * @author: Dennis Hernández
  3. * @webSite: http://djhvscf.github.io/Blog
  4. * @update zhixin wen <wenzhixin2010@gmail.com>
  5. */
  6. const Utils = $.fn.bootstrapTable.utils
  7. const UtilsCookie = {
  8. cookieIds: {
  9. sortOrder: 'bs.table.sortOrder',
  10. sortName: 'bs.table.sortName',
  11. pageNumber: 'bs.table.pageNumber',
  12. pageList: 'bs.table.pageList',
  13. columns: 'bs.table.columns',
  14. searchText: 'bs.table.searchText',
  15. reorderColumns: 'bs.table.reorderColumns',
  16. filterControl: 'bs.table.filterControl',
  17. filterBy: 'bs.table.filterBy'
  18. },
  19. getCurrentHeader (that) {
  20. let header = that.$header
  21. if (that.options.height) {
  22. header = that.$tableHeader
  23. }
  24. return header
  25. },
  26. getCurrentSearchControls (that) {
  27. let searchControls = 'select, input'
  28. if (that.options.height) {
  29. searchControls = 'table select, table input'
  30. }
  31. return searchControls
  32. },
  33. isCookieSupportedByBrowser () {
  34. return !!(navigator.cookieEnabled)
  35. },
  36. isCookieEnabled (that, cookieName) {
  37. return that.options.cookiesEnabled.indexOf(cookieName) !== -1
  38. },
  39. setCookie (that, cookieName, cookieValue) {
  40. if (!that.options.cookie) {
  41. return
  42. }
  43. if (!UtilsCookie.isCookieEnabled(that, cookieName)) {
  44. return
  45. }
  46. cookieName = `${that.options.cookieIdTable}.${cookieName}`
  47. return that._storage.setItem(cookieName, cookieValue)
  48. },
  49. getCookie (that, tableName, cookieName) {
  50. if (!cookieName) {
  51. return null
  52. }
  53. if (!UtilsCookie.isCookieEnabled(that, cookieName)) {
  54. return null
  55. }
  56. cookieName = `${tableName}.${cookieName}`
  57. return that._storage.getItem(cookieName)
  58. },
  59. deleteCookie (that, cookieName) {
  60. cookieName = `${that.options.cookieIdTable}.${cookieName}`
  61. return that._storage.removeItem(cookieName)
  62. },
  63. calculateExpiration (cookieExpire) {
  64. const time = cookieExpire.replace(/[0-9]*/, '') // s,mi,h,d,m,y
  65. cookieExpire = cookieExpire.replace(/[A-Za-z]{1,2}/, '') // number
  66. switch (time.toLowerCase()) {
  67. case 's':
  68. cookieExpire = +cookieExpire
  69. break
  70. case 'mi':
  71. cookieExpire *= 60
  72. break
  73. case 'h':
  74. cookieExpire = cookieExpire * 60 * 60
  75. break
  76. case 'd':
  77. cookieExpire = cookieExpire * 24 * 60 * 60
  78. break
  79. case 'm':
  80. cookieExpire = cookieExpire * 30 * 24 * 60 * 60
  81. break
  82. case 'y':
  83. cookieExpire = cookieExpire * 365 * 24 * 60 * 60
  84. break
  85. default:
  86. cookieExpire = undefined
  87. break
  88. }
  89. if (!cookieExpire) {
  90. return ''
  91. }
  92. const d = new Date()
  93. d.setTime(d.getTime() + cookieExpire * 1000)
  94. return d.toGMTString()
  95. },
  96. initCookieFilters (bootstrapTable) {
  97. setTimeout(() => {
  98. const parsedCookieFilters = JSON.parse(UtilsCookie.getCookie(bootstrapTable, bootstrapTable.options.cookieIdTable, UtilsCookie.cookieIds.filterControl))
  99. if (!bootstrapTable._filterControlValuesLoaded && parsedCookieFilters) {
  100. const cachedFilters = {}
  101. const header = UtilsCookie.getCurrentHeader(bootstrapTable)
  102. const searchControls = UtilsCookie.getCurrentSearchControls(bootstrapTable)
  103. const applyCookieFilters = (element, filteredCookies) => {
  104. filteredCookies.forEach(cookie => {
  105. if (cookie.text === '' || (element.type === 'radio' && element.value.toString() !== cookie.text.toString())) {
  106. return
  107. }
  108. if (element.tagName === 'INPUT' && element.type === 'radio' && element.value.toString() === cookie.text.toString()) {
  109. element.checked = true
  110. cachedFilters[cookie.field] = cookie.text
  111. } else if (element.tagName === 'INPUT') {
  112. element.value = cookie.text
  113. cachedFilters[cookie.field] = cookie.text
  114. } else if (element.tagName === 'SELECT' && bootstrapTable.options.filterControlContainer) {
  115. element.value = cookie.text
  116. cachedFilters[cookie.field] = cookie.text
  117. } else if (cookie.text !== '' && element.tagName === 'SELECT') {
  118. cachedFilters[cookie.field] = cookie.text
  119. for (let i = 0; i < element.length; i++) {
  120. const currentElement = element[i]
  121. if (currentElement.value === cookie.text) {
  122. currentElement.selected = true
  123. return
  124. }
  125. }
  126. const option = document.createElement('option')
  127. option.value = cookie.text
  128. option.text = cookie.text
  129. element.add(option, element[1])
  130. element.selectedIndex = 1
  131. }
  132. })
  133. }
  134. let filterContainer = header
  135. if (bootstrapTable.options.filterControlContainer) {
  136. filterContainer = $(`${bootstrapTable.options.filterControlContainer}`)
  137. }
  138. filterContainer.find(searchControls).each(function () {
  139. const field = $(this).closest('[data-field]').data('field')
  140. const filteredCookies = parsedCookieFilters.filter(cookie => cookie.field === field)
  141. applyCookieFilters(this, filteredCookies)
  142. })
  143. bootstrapTable.initColumnSearch(cachedFilters)
  144. bootstrapTable._filterControlValuesLoaded = true
  145. bootstrapTable.initServer()
  146. }
  147. }, 250)
  148. }
  149. }
  150. $.extend($.fn.bootstrapTable.defaults, {
  151. cookie: false,
  152. cookieExpire: '2h',
  153. cookiePath: null,
  154. cookieDomain: null,
  155. cookieSecure: null,
  156. cookieSameSite: 'Lax',
  157. cookieIdTable: '',
  158. cookiesEnabled: [
  159. 'bs.table.sortOrder', 'bs.table.sortName',
  160. 'bs.table.pageNumber', 'bs.table.pageList',
  161. 'bs.table.columns', 'bs.table.searchText',
  162. 'bs.table.filterControl', 'bs.table.filterBy',
  163. 'bs.table.reorderColumns'
  164. ],
  165. cookieStorage: 'cookieStorage', // localStorage, sessionStorage, customStorage
  166. cookieCustomStorageGet: null,
  167. cookieCustomStorageSet: null,
  168. cookieCustomStorageDelete: null,
  169. // internal variable
  170. _filterControls: [],
  171. _filterControlValuesLoaded: false,
  172. _storage: {
  173. setItem: undefined,
  174. getItem: undefined,
  175. removeItem: undefined
  176. }
  177. })
  178. $.fn.bootstrapTable.methods.push('getCookies')
  179. $.fn.bootstrapTable.methods.push('deleteCookie')
  180. $.extend($.fn.bootstrapTable.utils, {
  181. setCookie: UtilsCookie.setCookie,
  182. getCookie: UtilsCookie.getCookie
  183. })
  184. $.BootstrapTable = class extends $.BootstrapTable {
  185. init () {
  186. if (this.options.cookie) {
  187. if (this.options.cookieStorage === 'cookieStorage' && !UtilsCookie.isCookieSupportedByBrowser()) {
  188. throw new Error('Cookies are not enabled in this browser.')
  189. }
  190. this.configureStorage()
  191. // FilterBy logic
  192. const filterByCookieValue = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.filterBy)
  193. if (typeof filterByCookieValue === 'boolean' && !filterByCookieValue) {
  194. throw new Error('The cookie value of filterBy must be a json!')
  195. }
  196. let filterByCookie = {}
  197. try {
  198. filterByCookie = JSON.parse(filterByCookieValue)
  199. } catch (e) {
  200. throw new Error('Could not parse the json of the filterBy cookie!')
  201. }
  202. this.filterColumns = filterByCookie ? filterByCookie : {}
  203. // FilterControl logic
  204. this._filterControls = []
  205. this._filterControlValuesLoaded = false
  206. this.options.cookiesEnabled = typeof this.options.cookiesEnabled === 'string' ?
  207. this.options.cookiesEnabled.replace('[', '').replace(']', '')
  208. .replace(/'/g, '').replace(/ /g, '').toLowerCase().split(',') :
  209. this.options.cookiesEnabled
  210. if (this.options.filterControl) {
  211. const that = this
  212. this.$el.on('column-search.bs.table', (e, field, text) => {
  213. let isNewField = true
  214. for (let i = 0; i < that._filterControls.length; i++) {
  215. if (that._filterControls[i].field === field) {
  216. that._filterControls[i].text = text
  217. isNewField = false
  218. break
  219. }
  220. }
  221. if (isNewField) {
  222. that._filterControls.push({
  223. field,
  224. text
  225. })
  226. }
  227. UtilsCookie.setCookie(that, UtilsCookie.cookieIds.filterControl, JSON.stringify(that._filterControls))
  228. }).on('created-controls.bs.table', UtilsCookie.initCookieFilters(that))
  229. }
  230. }
  231. super.init()
  232. }
  233. initServer (...args) {
  234. if (
  235. this.options.cookie &&
  236. this.options.filterControl &&
  237. !this._filterControlValuesLoaded
  238. ) {
  239. const cookie = JSON.parse(UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.filterControl))
  240. if (cookie) {
  241. return
  242. }
  243. }
  244. super.initServer(...args)
  245. }
  246. initTable (...args) {
  247. super.initTable(...args)
  248. this.initCookie()
  249. }
  250. onSort (...args) {
  251. super.onSort(...args)
  252. if (!this.options.cookie) {
  253. return
  254. }
  255. if (this.options.sortName === undefined || this.options.sortOrder === undefined) {
  256. UtilsCookie.deleteCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortName)
  257. UtilsCookie.deleteCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortOrder)
  258. return
  259. }
  260. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortOrder, this.options.sortOrder)
  261. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortName, this.options.sortName)
  262. }
  263. onPageNumber (...args) {
  264. super.onPageNumber(...args)
  265. if (!this.options.cookie) {
  266. return
  267. }
  268. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
  269. }
  270. onPageListChange (...args) {
  271. super.onPageListChange(...args)
  272. if (!this.options.cookie) {
  273. return
  274. }
  275. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageList, this.options.pageSize)
  276. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
  277. }
  278. onPagePre (...args) {
  279. super.onPagePre(...args)
  280. if (!this.options.cookie) {
  281. return
  282. }
  283. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
  284. }
  285. onPageNext (...args) {
  286. super.onPageNext(...args)
  287. if (!this.options.cookie) {
  288. return
  289. }
  290. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
  291. }
  292. _toggleColumn (...args) {
  293. super._toggleColumn(...args)
  294. if (!this.options.cookie) {
  295. return
  296. }
  297. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.columns, JSON.stringify(this.getVisibleColumns().map(column => column.field)))
  298. }
  299. _toggleAllColumns (...args) {
  300. super._toggleAllColumns(...args)
  301. if (!this.options.cookie) {
  302. return
  303. }
  304. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.columns, JSON.stringify(this.getVisibleColumns().map(column => column.field)))
  305. }
  306. selectPage (page) {
  307. super.selectPage(page)
  308. if (!this.options.cookie) {
  309. return
  310. }
  311. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, page)
  312. }
  313. onSearch (event) {
  314. super.onSearch(event, arguments.length > 1 ? arguments[1] : true)
  315. if (!this.options.cookie) {
  316. return
  317. }
  318. if (this.options.search) {
  319. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.searchText, this.searchText)
  320. }
  321. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
  322. }
  323. initHeader (...args) {
  324. if (this.options.reorderableColumns && this.options.cookie) {
  325. this.columnsSortOrder = JSON.parse(UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.reorderColumns))
  326. }
  327. super.initHeader(...args)
  328. }
  329. persistReorderColumnsState (that) {
  330. UtilsCookie.setCookie(that, UtilsCookie.cookieIds.reorderColumns, JSON.stringify(that.columnsSortOrder))
  331. }
  332. filterBy (...args) {
  333. super.filterBy(...args)
  334. if (!this.options.cookie) {
  335. return
  336. }
  337. UtilsCookie.setCookie(this, UtilsCookie.cookieIds.filterBy, JSON.stringify(this.filterColumns))
  338. }
  339. initCookie () {
  340. if (!this.options.cookie) {
  341. return
  342. }
  343. if ((this.options.cookieIdTable === '') || (this.options.cookieExpire === '')) {
  344. console.error('Configuration error. Please review the cookieIdTable and the cookieExpire property. If the properties are correct, then this browser does not support cookies.')
  345. this.options.cookie = false // Make sure that the cookie extension is disabled
  346. return
  347. }
  348. const sortOrderCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortOrder)
  349. const sortOrderNameCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortName)
  350. const pageNumberCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.pageNumber)
  351. const pageListCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.pageList)
  352. const searchTextCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.searchText)
  353. const columnsCookieValue = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.columns)
  354. if (typeof columnsCookieValue === 'boolean' && !columnsCookieValue) {
  355. throw new Error('The cookie value of filterBy must be a json!')
  356. }
  357. let columnsCookie = {}
  358. try {
  359. columnsCookie = JSON.parse(columnsCookieValue)
  360. } catch (e) {
  361. throw new Error('Could not parse the json of the columns cookie!', columnsCookieValue)
  362. }
  363. // sortOrder
  364. this.options.sortOrder = sortOrderCookie ? sortOrderCookie : this.options.sortOrder
  365. // sortName
  366. this.options.sortName = sortOrderNameCookie ? sortOrderNameCookie : this.options.sortName
  367. // pageNumber
  368. this.options.pageNumber = pageNumberCookie ? +pageNumberCookie : this.options.pageNumber
  369. // pageSize
  370. this.options.pageSize = pageListCookie ? pageListCookie === this.options.formatAllRows() ? pageListCookie : +pageListCookie : this.options.pageSize
  371. // searchText
  372. if (UtilsCookie.isCookieEnabled(this, 'bs.table.searchText') && this.options.searchText === '') {
  373. this.options.searchText = searchTextCookie ? searchTextCookie : ''
  374. }
  375. if (columnsCookie) {
  376. for (const column of this.columns) {
  377. column.visible = columnsCookie.filter(columnField => {
  378. if (this.isSelectionColumn(column)) {
  379. return true
  380. }
  381. /**
  382. * This is needed for the old saved cookies or the table will show no columns!
  383. * It can be removed in 2-3 Versions Later!!
  384. * TODO: Remove this part some versions later e.g. 1.17.3
  385. */
  386. if (columnField instanceof Object) {
  387. return columnField.field === column.field
  388. }
  389. return columnField === column.field
  390. }).length > 0 || !column.switchable
  391. }
  392. }
  393. }
  394. getCookies () {
  395. const bootstrapTable = this
  396. const cookies = {}
  397. $.each(UtilsCookie.cookieIds, (key, value) => {
  398. cookies[key] = UtilsCookie.getCookie(bootstrapTable, bootstrapTable.options.cookieIdTable, value)
  399. if (key === 'columns') {
  400. cookies[key] = JSON.parse(cookies[key])
  401. }
  402. })
  403. return cookies
  404. }
  405. deleteCookie (cookieName) {
  406. if (!cookieName) {
  407. return
  408. }
  409. UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds[cookieName])
  410. }
  411. configureStorage () {
  412. const that = this
  413. this._storage = {}
  414. switch (this.options.cookieStorage) {
  415. case 'cookieStorage':
  416. this._storage.setItem = function (cookieName, cookieValue) {
  417. document.cookie = [
  418. cookieName, '=', encodeURIComponent(cookieValue),
  419. `; expires=${UtilsCookie.calculateExpiration(that.options.cookieExpire)}`,
  420. that.options.cookiePath ? `; path=${that.options.cookiePath}` : '',
  421. that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : '',
  422. that.options.cookieSecure ? '; secure' : '',
  423. `;SameSite=${ that.options.cookieSameSite}`
  424. ].join('')
  425. }
  426. this._storage.getItem = function (cookieName) {
  427. const value = `; ${document.cookie}`
  428. const parts = value.split(`; ${cookieName}=`)
  429. return parts.length === 2 ? decodeURIComponent(parts.pop().split(';').shift()) : null
  430. }
  431. this._storage.removeItem = function (cookieName) {
  432. document.cookie = [
  433. encodeURIComponent(cookieName), '=',
  434. '; expires=Thu, 01 Jan 1970 00:00:00 GMT',
  435. that.options.cookiePath ? `; path=${that.options.cookiePath}` : '',
  436. that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : '',
  437. `;SameSite=${ that.options.cookieSameSite}`
  438. ].join('')
  439. }
  440. break
  441. case 'localStorage':
  442. this._storage.setItem = function (cookieName, cookieValue) {
  443. localStorage.setItem(cookieName, cookieValue)
  444. }
  445. this._storage.getItem = function (cookieName) {
  446. return localStorage.getItem(cookieName)
  447. }
  448. this._storage.removeItem = function (cookieName) {
  449. localStorage.removeItem(cookieName)
  450. }
  451. break
  452. case 'sessionStorage':
  453. this._storage.setItem = function (cookieName, cookieValue) {
  454. sessionStorage.setItem(cookieName, cookieValue)
  455. }
  456. this._storage.getItem = function (cookieName) {
  457. return sessionStorage.getItem(cookieName)
  458. }
  459. this._storage.removeItem = function (cookieName) {
  460. sessionStorage.removeItem(cookieName)
  461. }
  462. break
  463. case 'customStorage':
  464. if (
  465. !this.options.cookieCustomStorageSet ||
  466. !this.options.cookieCustomStorageGet ||
  467. !this.options.cookieCustomStorageDelete
  468. ) {
  469. throw new Error('The following options must be set while using the customStorage: cookieCustomStorageSet, cookieCustomStorageGet and cookieCustomStorageDelete')
  470. }
  471. this._storage.setItem = function (cookieName, cookieValue) {
  472. Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageSet, [cookieName, cookieValue], '')
  473. }
  474. this._storage.getItem = function (cookieName) {
  475. return Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageGet, [cookieName], '')
  476. }
  477. this._storage.removeItem = function (cookieName) {
  478. Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageDelete, [cookieName], '')
  479. }
  480. break
  481. default:
  482. throw new Error('Storage method not supported.')
  483. }
  484. }
  485. }