footable.state.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
  3. * @version 3.1.6
  4. * @link http://fooplugins.com
  5. * @copyright Steven Usher & Brad Vincent 2015
  6. * @license Released under the GPLv3 license.
  7. */
  8. (function($, F){
  9. // global int to use if the table has no ID
  10. var _uid = 0,
  11. // a hash value for the current url
  12. _url_hash = (function(str){
  13. var i, l, hval = 0x811c9dc5;
  14. for (i = 0, l = str.length; i < l; i++) {
  15. hval ^= str.charCodeAt(i);
  16. hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
  17. }
  18. return hval >>> 0;
  19. })(location.origin + location.pathname);
  20. F.State = F.Component.extend(/** @lends FooTable.State */{
  21. /**
  22. * The state component adds the ability for the table to remember its basic state for filtering, paging and sorting.
  23. * @constructs
  24. * @extends FooTable.Component
  25. * @param {FooTable.Table} table - The parent {@link FooTable.Table} object for the component.
  26. * @returns {FooTable.State}
  27. */
  28. construct: function(table){
  29. // call the constructor of the base class
  30. this._super(table, table.o.state.enabled);
  31. // Change this value if an update to this component requires any stored data to be reset
  32. this._key = '1';
  33. /**
  34. * The key to use to store the state for this table.
  35. * @type {(null|string)}
  36. */
  37. this.key = this._key + (F.is.string(table.o.state.key) ? table.o.state.key : this._uid());
  38. /**
  39. * Whether or not to allow the filtering component to store it's state.
  40. * @type {boolean}
  41. */
  42. this.filtering = F.is.boolean(table.o.state.filtering) ? table.o.state.filtering : true;
  43. /**
  44. * Whether or not to allow the paging component to store it's state.
  45. * @type {boolean}
  46. */
  47. this.paging = F.is.boolean(table.o.state.paging) ? table.o.state.paging : true;
  48. /**
  49. * Whether or not to allow the sorting component to store it's state.
  50. * @type {boolean}
  51. */
  52. this.sorting = F.is.boolean(table.o.state.sorting) ? table.o.state.sorting : true;
  53. },
  54. /* PROTECTED */
  55. /**
  56. * Checks the supplied data and options for the state component.
  57. * @instance
  58. * @protected
  59. * @param {object} data - The jQuery data object from the parent table.
  60. * @fires FooTable.State#"preinit.ft.state"
  61. * @this FooTable.State
  62. */
  63. preinit: function(data){
  64. var self = this;
  65. /**
  66. * The preinit.ft.state event is raised before the UI is created and provides the tables jQuery data object for additional options parsing.
  67. * Calling preventDefault on this event will disable the component.
  68. * @event FooTable.State#"preinit.ft.state"
  69. * @param {jQuery.Event} e - The jQuery.Event object for the event.
  70. * @param {FooTable.Table} ft - The instance of the plugin raising the event.
  71. * @param {object} data - The jQuery data object of the table raising the event.
  72. */
  73. this.ft.raise('preinit.ft.state', [data]).then(function(){
  74. self.enabled = F.is.boolean(data.state)
  75. ? data.state
  76. : self.enabled;
  77. if (!self.enabled) return;
  78. self.key = self._key + (F.is.string(data.stateKey) ? data.stateKey : self.key);
  79. self.filtering = F.is.boolean(data.stateFiltering) ? data.stateFiltering : self.filtering;
  80. self.paging = F.is.boolean(data.statePaging) ? data.statePaging : self.paging;
  81. self.sorting = F.is.boolean(data.stateSorting) ? data.stateSorting : self.sorting;
  82. }, function(){
  83. self.enabled = false;
  84. });
  85. },
  86. /**
  87. * Gets the state value for the specified key for this table.
  88. * @instance
  89. * @param {string} key - The key to get the value for.
  90. * @returns {(*|null)}
  91. */
  92. get: function(key){
  93. return JSON.parse(localStorage.getItem(this.key + ':' + key));
  94. },
  95. /**
  96. * Sets the state value for the specified key for this table.
  97. * @instance
  98. * @param {string} key - The key to set the value for.
  99. * @param {*} data - The value to store for the key. This value must be JSON.stringify friendly.
  100. */
  101. set: function(key, data){
  102. localStorage.setItem(this.key + ':' + key, JSON.stringify(data));
  103. },
  104. /**
  105. * Clears the state value for the specified key for this table.
  106. * @instance
  107. * @param {string} key - The key to clear the value for.
  108. */
  109. remove: function(key){
  110. localStorage.removeItem(this.key + ':' + key);
  111. },
  112. /**
  113. * Executes the {@link FooTable.Component#readState} function on all components.
  114. * @instance
  115. */
  116. read: function(){
  117. this.ft.execute(false, true, 'readState');
  118. },
  119. /**
  120. * Executes the {@link FooTable.Component#writeState} function on all components.
  121. * @instance
  122. */
  123. write: function(){
  124. this.ft.execute(false, true, 'writeState');
  125. },
  126. /**
  127. * Executes the {@link FooTable.Component#clearState} function on all components.
  128. * @instance
  129. */
  130. clear: function(){
  131. this.ft.execute(false, true, 'clearState');
  132. },
  133. /**
  134. * Generates a unique identifier for the current {@link FooTable.Table} if one is not supplied through the options.
  135. * This value is a combination of the url hash and either the element ID or an incremented global int value.
  136. * @instance
  137. * @returns {*}
  138. * @private
  139. */
  140. _uid: function(){
  141. var id = this.ft.$el.attr('id');
  142. return _url_hash + '_' + (F.is.string(id) ? id : ++_uid);
  143. }
  144. });
  145. F.components.register('state', F.State, 700);
  146. })(jQuery, FooTable);
  147. (function(F){
  148. /**
  149. * This method is called from the {@link FooTable.State#read} method and allows a component to retrieve its' stored state.
  150. * @instance
  151. * @protected
  152. * @function
  153. */
  154. F.Component.prototype.readState = function(){};
  155. /**
  156. * This method is called from the {@link FooTable.State#write} method and allows a component to write its' current state to the store.
  157. * @instance
  158. * @protected
  159. * @function
  160. */
  161. F.Component.prototype.writeState = function(){};
  162. /**
  163. * This method is called from the {@link FooTable.State#clear} method and allows a component to clear any stored state.
  164. * @instance
  165. * @protected
  166. * @function
  167. */
  168. F.Component.prototype.clearState = function(){};
  169. })(FooTable);
  170. (function(F){
  171. /**
  172. * An object containing the state options for the plugin. Added by the {@link FooTable.State} component.
  173. * @type {object}
  174. * @prop {boolean} enabled=false - Whether or not to allow state to be stored for the table. This overrides the individual component enable options.
  175. * @prop {boolean} filtering=true - Whether or not to allow the filtering state to be stored.
  176. * @prop {boolean} paging=true - Whether or not to allow the filtering state to be stored.
  177. * @prop {boolean} sorting=true - Whether or not to allow the filtering state to be stored.
  178. * @prop {string} key=null - The unique key to use to store the table's data.
  179. */
  180. F.Defaults.prototype.state = {
  181. enabled: false,
  182. filtering: true,
  183. paging: true,
  184. sorting: true,
  185. key: null
  186. };
  187. })(FooTable);
  188. (function(F){
  189. if (!F.Filtering) return;
  190. /**
  191. * Allows the filtering component to retrieve its' stored state.
  192. */
  193. F.Filtering.prototype.readState = function(){
  194. if (this.ft.state.filtering){
  195. var state = this.ft.state.get('filtering');
  196. if (F.is.hash(state) && !F.is.emptyArray(state.filters)){
  197. this.filters = this.ensure(state.filters);
  198. }
  199. }
  200. };
  201. /**
  202. * Allows the filtering component to write its' current state to the store.
  203. */
  204. F.Filtering.prototype.writeState = function(){
  205. if (this.ft.state.filtering) {
  206. var filters = F.arr.map(this.filters, function (f) {
  207. return {
  208. name: f.name,
  209. query: f.query instanceof F.Query ? f.query.val() : f.query,
  210. columns: F.arr.map(f.columns, function (c) {
  211. return c.name;
  212. }),
  213. hidden: f.hidden,
  214. space: f.space,
  215. connectors: f.connectors,
  216. ignoreCase: f.ignoreCase
  217. };
  218. });
  219. this.ft.state.set('filtering', {filters: filters});
  220. }
  221. };
  222. /**
  223. * Allows the filtering component to clear any stored state.
  224. */
  225. F.Filtering.prototype.clearState = function(){
  226. if (this.ft.state.filtering) {
  227. this.ft.state.remove('filtering');
  228. }
  229. };
  230. })(FooTable);
  231. (function(F){
  232. if (!F.Paging) return;
  233. /**
  234. * Allows the paging component to retrieve its' stored state.
  235. */
  236. F.Paging.prototype.readState = function(){
  237. if (this.ft.state.paging) {
  238. var state = this.ft.state.get('paging');
  239. if (F.is.hash(state)) {
  240. this.current = state.current;
  241. this.size = state.size;
  242. }
  243. }
  244. };
  245. /**
  246. * Allows the paging component to write its' current state to the store.
  247. */
  248. F.Paging.prototype.writeState = function(){
  249. if (this.ft.state.paging) {
  250. this.ft.state.set('paging', {
  251. current: this.current,
  252. size: this.size
  253. });
  254. }
  255. };
  256. /**
  257. * Allows the paging component to clear any stored state.
  258. */
  259. F.Paging.prototype.clearState = function(){
  260. if (this.ft.state.paging) {
  261. this.ft.state.remove('paging');
  262. }
  263. };
  264. })(FooTable);
  265. (function(F){
  266. if (!F.Sorting) return;
  267. /**
  268. * Allows the sorting component to retrieve its' stored state.
  269. */
  270. F.Sorting.prototype.readState = function(){
  271. if (this.ft.state.sorting) {
  272. var state = this.ft.state.get('sorting');
  273. if (F.is.hash(state)) {
  274. var column = this.ft.columns.get(state.column);
  275. if (column instanceof F.Column) {
  276. this.column = column;
  277. this.column.direction = state.direction;
  278. }
  279. }
  280. }
  281. };
  282. /**
  283. * Allows the sorting component to write its' current state to the store.
  284. */
  285. F.Sorting.prototype.writeState = function(){
  286. if (this.ft.state.sorting && this.column instanceof F.Column){
  287. this.ft.state.set('sorting', {
  288. column: this.column.name,
  289. direction: this.column.direction
  290. });
  291. }
  292. };
  293. /**
  294. * Allows the sorting component to clear any stored state.
  295. */
  296. F.Sorting.prototype.clearState = function(){
  297. if (this.ft.state.sorting) {
  298. this.ft.state.remove('sorting');
  299. }
  300. };
  301. })(FooTable);
  302. (function(F){
  303. // hook into the _construct method so we can add the state property to the table.
  304. F.Table.extend('_construct', function(ready){
  305. this.state = this.use(FooTable.State);
  306. return this._super(ready);
  307. });
  308. // hook into the _preinit method so we can trigger a plugin wide read state operation.
  309. F.Table.extend('_preinit', function(){
  310. var self = this;
  311. return self._super().then(function(){
  312. if (self.state.enabled){
  313. self.state.read();
  314. }
  315. });
  316. });
  317. // hook into the draw method so we can trigger a plugin wide write state operation.
  318. F.Table.extend('draw', function(){
  319. var self = this;
  320. return self._super().then(function(){
  321. if (self.state.enabled){
  322. self.state.write();
  323. }
  324. });
  325. });
  326. })(FooTable);