table_view.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var filters = require('views/common/filter_view');
  20. var sort = require('views/common/sort_view');
  21. App.TableView = Em.View.extend({
  22. /**
  23. * Shows if all data is loaded and filtered
  24. * @type {Boolean}
  25. */
  26. filteringComplete: false,
  27. /**
  28. * Loaded from local storage startIndex value
  29. * @type {Number}
  30. */
  31. startIndexOnLoad: null,
  32. /**
  33. * Loaded from server persist value
  34. * @type {Number}
  35. */
  36. displayLengthOnLoad: null,
  37. /**
  38. * Do filtering, using saved in the local storage filter conditions
  39. */
  40. willInsertElement:function () {
  41. var self = this;
  42. var name = this.get('controller.name');
  43. this.set('startIndexOnLoad', App.db.getStartIndex(name));
  44. if (App.db.getDisplayLength(name)) {
  45. this.set('displayLength', App.db.getDisplayLength(name));
  46. } else {
  47. self.dataLoading().done(function (initValue) {
  48. self.set('displayLength', initValue);
  49. });
  50. }
  51. var filterConditions = App.db.getFilterConditions(name);
  52. if (filterConditions) {
  53. this.set('filterConditions', filterConditions);
  54. var childViews = this.get('childViews');
  55. filterConditions.forEach(function(condition) {
  56. var view = childViews.findProperty('column', condition.iColumn);
  57. if (view) {
  58. view.set('value', condition.value);
  59. Em.run.next(function() {
  60. view.showClearFilter();
  61. });
  62. }
  63. });
  64. } else {
  65. this.clearFilters();
  66. }
  67. Em.run.next(function() {
  68. Em.run.next(function() {
  69. self.set('filteringComplete', true);
  70. });
  71. });
  72. },
  73. /**
  74. * Load user preference value on hosts page from server
  75. */
  76. dataLoading: function() {
  77. var dfd = $.Deferred();
  78. var self = this;
  79. this.getUserPref(this.displayLengthKey()).done(function () {
  80. var curLength = self.get('displayLengthOnLoad');
  81. self.set('displayLengthOnLoad', null);
  82. dfd.resolve(curLength);
  83. });
  84. return dfd.promise();
  85. },
  86. /**
  87. * Persist-key of current table displayLength property
  88. * @param {String} loginName current user login name
  89. * @returns {String}
  90. */
  91. displayLengthKey: function (loginName) {
  92. if (App.get('testMode')) {
  93. return 'pagination_displayLength';
  94. }
  95. loginName = loginName ? loginName : App.router.get('loginName');
  96. return this.get('controller.name') + '-pagination-displayLength-' + loginName;
  97. },
  98. /**
  99. * get display length persist value from server with displayLengthKey
  100. */
  101. getUserPref: function(key){
  102. return App.ajax.send({
  103. name: 'settings.get.user_pref',
  104. sender: this,
  105. data: {
  106. key: key
  107. },
  108. success: 'getDisplayLengthSuccessCallback',
  109. error: 'getDisplayLengthErrorCallback'
  110. });
  111. },
  112. /**
  113. * Set received from server value to <code>displayLengthOnLoad</code>
  114. * @param {Number} response
  115. * @param {Object} request
  116. * @param {Object} data
  117. * @returns {*}
  118. */
  119. getDisplayLengthSuccessCallback: function (response, request, data) {
  120. console.log('Got DisplayLength value from server with key ' + data.key + '. Value is: ' + response);
  121. this.set('displayLengthOnLoad', response);
  122. return response;
  123. },
  124. /**
  125. * Set default value to <code>displayLengthOnLoad</code> (and send it on server) if value wasn't found on server
  126. * @returns {Number}
  127. */
  128. getDisplayLengthErrorCallback: function () {
  129. // this user is first time login
  130. console.log('Persist did NOT find the key');
  131. var displayLengthDefault = "10";
  132. this.set('displayLengthOnLoad', displayLengthDefault);
  133. this.postUserPref(this.displayLengthKey(), displayLengthDefault);
  134. return displayLengthDefault;
  135. },
  136. /**
  137. * Post display length persist key/value to server
  138. * @param {String} key
  139. * @param {Object} value
  140. */
  141. postUserPref: function (key, value) {
  142. var keyValuePair = {};
  143. keyValuePair[key] = JSON.stringify(value);
  144. App.ajax.send({
  145. name: 'settings.post.user_pref',
  146. sender: this,
  147. data: {
  148. keyValuePair: keyValuePair
  149. }
  150. });
  151. },
  152. /**
  153. * Do pagination after filtering and sorting
  154. * Don't call this method! It's already used where it's need
  155. */
  156. showProperPage: function() {
  157. var self = this;
  158. Em.run.next(function() {
  159. Em.run.next(function() {
  160. if(self.get('startIndexOnLoad')) {
  161. self.set('startIndex', self.get('startIndexOnLoad'));
  162. }
  163. });
  164. });
  165. },
  166. /**
  167. * Return pagination information displayed on the page
  168. * @type {String}
  169. */
  170. paginationInfo: function () {
  171. return this.t('tableView.filters.paginationInfo').format(this.get('startIndex'), this.get('endIndex'), this.get('filteredContent.length'));
  172. }.property('displayLength', 'filteredContent.length', 'startIndex', 'endIndex'),
  173. paginationLeft: Ember.View.extend({
  174. tagName: 'a',
  175. template: Ember.Handlebars.compile('<i class="icon-arrow-left"></i>'),
  176. classNameBindings: ['class'],
  177. class: function () {
  178. if (this.get("parentView.startIndex") > 1) {
  179. return "paginate_previous";
  180. }
  181. return "paginate_disabled_previous";
  182. }.property("parentView.startIndex", 'filteredContent.length'),
  183. click: function () {
  184. this.get('parentView').previousPage();
  185. }
  186. }),
  187. paginationRight: Ember.View.extend({
  188. tagName: 'a',
  189. template: Ember.Handlebars.compile('<i class="icon-arrow-right"></i>'),
  190. classNameBindings: ['class'],
  191. class: function () {
  192. if ((this.get("parentView.endIndex")) < this.get("parentView.filteredContent.length")) {
  193. return "paginate_next";
  194. }
  195. return "paginate_disabled_next";
  196. }.property("parentView.endIndex", 'filteredContent.length'),
  197. click: function () {
  198. this.get('parentView').nextPage();
  199. }
  200. }),
  201. /**
  202. * Select View with list of "rows-per-page" options
  203. * @type {Ember.View}
  204. */
  205. rowsPerPageSelectView: Em.Select.extend({
  206. content: ['10', '25', '50'],
  207. change: function () {
  208. this.get('parentView').saveDisplayLength();
  209. }
  210. }),
  211. /**
  212. * Start index for displayed content on the page
  213. */
  214. startIndex: 1,
  215. /**
  216. * Calculate end index for displayed content on the page
  217. */
  218. endIndex: function () {
  219. return Math.min(this.get('filteredContent.length'), this.get('startIndex') + parseInt(this.get('displayLength')) - 1);
  220. }.property('startIndex', 'displayLength', 'filteredContent.length'),
  221. /**
  222. * Onclick handler for previous page button on the page
  223. */
  224. previousPage: function () {
  225. var result = this.get('startIndex') - parseInt(this.get('displayLength'));
  226. this.set('startIndex', (result < 2) ? 1 : result);
  227. },
  228. /**
  229. * Onclick handler for next page button on the page
  230. */
  231. nextPage: function () {
  232. var result = this.get('startIndex') + parseInt(this.get('displayLength'));
  233. if (result - 1 < this.get('filteredContent.length')) {
  234. this.set('startIndex', result);
  235. }
  236. },
  237. /**
  238. * The number of rows to show on every page
  239. * @type {Number}
  240. */
  241. displayLength: null,
  242. /**
  243. * Calculates default value for startIndex property after applying filter or changing displayLength
  244. */
  245. updatePaging: function () {
  246. this.set('startIndex', Math.min(1, this.get('filteredContent.length')));
  247. }.observes('displayLength', 'filteredContent.length'),
  248. /**
  249. * Apply each filter to each row
  250. *
  251. * @param {Number} iColumn number of column by which filter
  252. * @param {Object} value
  253. * @param {String} type
  254. */
  255. updateFilter: function (iColumn, value, type) {
  256. var filterCondition = this.get('filterConditions').findProperty('iColumn', iColumn);
  257. if (filterCondition) {
  258. filterCondition.value = value;
  259. }
  260. else {
  261. filterCondition = {
  262. iColumn: iColumn,
  263. value: value,
  264. type: type
  265. };
  266. this.get('filterConditions').push(filterCondition);
  267. }
  268. this.saveFilterConditions();
  269. this.filtersUsedCalc();
  270. this.filter();
  271. },
  272. saveFilterConditions: function() {
  273. App.db.setFilterConditions(this.get('controller.name'), this.get('filterConditions'));
  274. },
  275. saveDisplayLength: function() {
  276. var self = this;
  277. Em.run.next(function() {
  278. App.db.setDisplayLength(self.get('controller.name'), self.get('displayLength'));
  279. if (!App.testMode) {
  280. self.postUserPref(self.displayLengthKey(), self.get('displayLength'));
  281. }
  282. });
  283. },
  284. saveStartIndex: function() {
  285. if (this.get('filteringComplete')) {
  286. App.db.setStartIndex(this.get('controller.name'), this.get('startIndex'));
  287. }
  288. }.observes('startIndex'),
  289. clearFilterCondition: function() {
  290. App.db.setFilterConditions(this.get('controller.name'), null);
  291. },
  292. clearStartIndex: function() {
  293. App.db.setStartIndex(this.get('controller.name'), null);
  294. },
  295. /**
  296. * Contain filter conditions for each column
  297. * @type {Array}
  298. */
  299. filterConditions: [],
  300. /**
  301. * Contains content after implementing filters
  302. * @type {Array}
  303. */
  304. filteredContent: [],
  305. /**
  306. * Determine if <code>filteredContent</code> is empty or not
  307. * @type {Boolean}
  308. */
  309. hasFilteredItems: function() {
  310. return !!this.get('filteredContent.length');
  311. }.property('filteredContent.length'),
  312. /**
  313. * Contains content to show on the current page of data page view
  314. * @type {Array}
  315. */
  316. pageContent: function () {
  317. return this.get('filteredContent').slice(this.get('startIndex') - 1, this.get('endIndex'));
  318. }.property('filteredContent.length', 'startIndex', 'endIndex'),
  319. /**
  320. * Filter table by filterConditions
  321. */
  322. filter: function () {
  323. var content = this.get('content');
  324. var filterConditions = this.get('filterConditions').filterProperty('value');
  325. var result;
  326. var assoc = this.get('colPropAssoc');
  327. if (filterConditions.length) {
  328. result = content.filter(function (item) {
  329. var match = true;
  330. filterConditions.forEach(function (condition) {
  331. var filterFunc = filters.getFilterByType(condition.type, false);
  332. if (match) {
  333. match = filterFunc(item.get(assoc[condition.iColumn]), condition.value);
  334. }
  335. });
  336. return match;
  337. });
  338. this.set('filteredContent', result);
  339. } else {
  340. this.set('filteredContent', content.toArray());
  341. }
  342. }.observes('content'),
  343. /**
  344. * Does any filter is used on the page
  345. * @type {Boolean}
  346. */
  347. filtersUsed: false,
  348. /**
  349. * Determine if some filters are used on the page
  350. * Set <code>filtersUsed</code> value
  351. */
  352. filtersUsedCalc: function() {
  353. var filterConditions = this.get('filterConditions');
  354. if (!filterConditions.length) {
  355. this.set('filtersUsed', false);
  356. return;
  357. }
  358. var filtersUsed = false;
  359. filterConditions.forEach(function(filterCondition) {
  360. if (filterCondition.value.toString() !== '') {
  361. filtersUsed = true;
  362. }
  363. });
  364. this.set('filtersUsed', filtersUsed);
  365. },
  366. /**
  367. * Run <code>clearFilter</code> in the each child filterView
  368. */
  369. clearFilters: function() {
  370. this.set('filterConditions', []);
  371. this.get('_childViews').forEach(function(childView) {
  372. if (childView['clearFilter']) {
  373. childView.clearFilter();
  374. }
  375. });
  376. }
  377. });