/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var App = require('app'); var filters = require('views/common/filter_view'); App.TableView = Em.View.extend(App.UserPref, { init: function() { this.set('filterConditions', []); this._super(); }, /** * Defines to show pagination or show all records * @type {Boolean} */ pagination: true, /** * Shows if all data is loaded and filtered * @type {Boolean} */ filteringComplete: false, /** * intermediary for filteringComplete * @type {Boolean} */ tableFilteringComplete: false, /** * The number of rows to show on every page * The value should be a number converted into string type in order to support select element API * Example: "10", "25" * @type {String} */ displayLength: null, /** * default value of display length * The value should be a number converted into string type in order to support select element API * Example: "10", "25" */ defaultDisplayLength: "10", /** * number of items in table after applying filters */ filteredCount: function () { return this.get('filteredContent.length'); }.property('filteredContent.length'), /** * total number of items in table before applying filters */ totalCount: function () { return this.get('content.length'); }.property('content.length'), /** * Do filtering, using saved in the local storage filter conditions */ willInsertElement:function () { var self = this; var name = this.get('controller.name'); if (!this.get('displayLength')) { if (App.db.getDisplayLength(name)) { this.set('displayLength', App.db.getDisplayLength(name)); } else { this.getUserPref(this.displayLengthKey()).complete(function(){ self.initFilters(); }); return; } } this.initFilters(); }, /** * initialize filters * restore values from local DB * or clear filters in case there is no filters to restore */ initFilters: function () { var name = this.get('controller.name'); var self = this; var filterConditions = App.db.getFilterConditions(name); if (filterConditions) { this.set('filterConditions', filterConditions); var childViews = this.get('childViews'); filterConditions.forEach(function (condition, index, filteredConditions) { var view = !Em.isNone(condition.iColumn) && childViews.findProperty('column', condition.iColumn); if (view) { if (view.get('emptyValue')) { view.clearFilter(); self.saveFilterConditions(condition.iColumn, view.get('appliedEmptyValue'), condition.type, false); } else { view.set('value', condition.value); } Em.run.next(function () { view.showClearFilter(); // check if it is the last iteration if (filteredConditions.length - index - 1 === 0) { self.set('tableFilteringComplete', true); } }); } }); } else { this.set('tableFilteringComplete', true); } }, /** * Persist-key of current table displayLength property * @param {String} loginName current user login name * @returns {String} */ displayLengthKey: function (loginName) { if (App.get('testMode')) { return 'pagination_displayLength'; } loginName = loginName ? loginName : App.router.get('loginName'); return this.get('controller.name') + '-pagination-displayLength-' + loginName; }, /** * Set received from server value to displayLengthOnLoad * @param {Number} response * @param {Object} request * @param {Object} data * @returns {*} */ getUserPrefSuccessCallback: function (response, request, data) { console.log('Got DisplayLength value from server with key ' + data.key + '. Value is: ' + response); this.set('displayLength', response); return response; }, /** * Set default value to displayLength (and send it on server) if value wasn't found on server * @returns {Number} */ getUserPrefErrorCallback: function () { // this user is first time login console.log('Persist did NOT find the key'); var displayLengthDefault = this.get('defaultDisplayLength'); this.set('displayLength', displayLengthDefault); if (App.isAccessible('upgrade_ADMIN')) { this.saveDisplayLength(); } this.filter(); return displayLengthDefault; }, /** * Return pagination information displayed on the page * @type {String} */ paginationInfo: function () { return this.t('tableView.filters.paginationInfo').format(this.get('startIndex'), this.get('endIndex'), this.get('filteredCount')); }.property('filteredCount', 'endIndex'), paginationLeft: Ember.View.extend({ tagName: 'a', template: Ember.Handlebars.compile(''), classNameBindings: ['class'], class: function () { if (this.get("parentView.startIndex") > 1) { return "paginate_previous"; } return "paginate_disabled_previous"; }.property("parentView.startIndex", 'parentView.filteredCount'), click: function () { if (this.get('class') === "paginate_previous") { this.get('parentView').previousPage(); } } }), paginationRight: Ember.View.extend({ tagName: 'a', template: Ember.Handlebars.compile(''), classNameBindings: ['class'], class: function () { if ((this.get("parentView.endIndex")) < this.get("parentView.filteredCount")) { return "paginate_next"; } return "paginate_disabled_next"; }.property("parentView.endIndex", 'parentView.filteredCount'), click: function () { if (this.get('class') === "paginate_next") { this.get('parentView').nextPage(); } } }), paginationFirst: Ember.View.extend({ tagName: 'a', template: Ember.Handlebars.compile(''), classNameBindings: ['class'], class: function () { if ((this.get("parentView.endIndex")) > parseInt(this.get("parentView.displayLength"))) { return "paginate_previous"; } return "paginate_disabled_previous"; }.property("parentView.endIndex", 'parentView.filteredCount'), click: function () { if (this.get('class') === "paginate_previous") { this.get('parentView').firstPage(); } } }), paginationLast: Ember.View.extend({ tagName: 'a', template: Ember.Handlebars.compile(''), classNameBindings: ['class'], class: function () { if (this.get("parentView.endIndex") !== this.get("parentView.filteredCount")) { return "paginate_next"; } return "paginate_disabled_next"; }.property("parentView.endIndex", 'parentView.filteredCount'), click: function () { if (this.get('class') === "paginate_next") { this.get('parentView').lastPage(); } } }), /** * Select View with list of "rows-per-page" options * @type {Ember.View} */ rowsPerPageSelectView: Em.Select.extend({ content: ['10', '25', '50', '100'], change: function () { this.get('parentView').saveDisplayLength(); } }), /** * Start index for displayed content on the page */ startIndex: 1, /** * Calculate end index for displayed content on the page */ endIndex: function () { if (this.get('pagination') && this.get('displayLength')) { return Math.min(this.get('filteredCount'), this.get('startIndex') + parseInt(this.get('displayLength')) - 1); } else { return this.get('filteredCount') || 0; } }.property('startIndex', 'displayLength', 'filteredCount'), /** * Onclick handler for previous page button on the page */ previousPage: function () { var result = this.get('startIndex') - parseInt(this.get('displayLength')); this.set('startIndex', (result < 2) ? 1 : result); }, /** * Onclick handler for next page button on the page */ nextPage: function () { var result = this.get('startIndex') + parseInt(this.get('displayLength')); if (result - 1 < this.get('filteredCount')) { this.set('startIndex', result); } }, /** * Onclick handler for first page button on the page */ firstPage: function () { this.set('startIndex', 1); }, /** * Onclick handler for last page button on the page */ lastPage: function () { var pagesCount = this.get('filteredCount') / parseInt(this.get('displayLength')); var startIndex = (this.get('filteredCount') % parseInt(this.get('displayLength')) === 0) ? (pagesCount - 1) * parseInt(this.get('displayLength')) : Math.floor(pagesCount) * parseInt(this.get('displayLength')); this.set('startIndex', ++startIndex); }, /** * Calculates default value for startIndex property after applying filter or changing displayLength */ updatePaging: function (controller, property) { var displayLength = this.get('displayLength'); var filteredContentLength = this.get('filteredCount'); if (property == 'displayLength') { this.set('startIndex', Math.min(1, filteredContentLength)); } else if (!filteredContentLength) { this.set('startIndex', 0); } else if (this.get('startIndex') > filteredContentLength) { this.set('startIndex', Math.floor((filteredContentLength - 1) / displayLength) * displayLength + 1); } else if (!this.get('startIndex')) { this.set('startIndex', 1); } }.observes('displayLength', 'filteredCount'), /** * Apply each filter to each row * * @param {Number} iColumn number of column by which filter * @param {Object} value * @param {String} type */ updateFilter: function (iColumn, value, type) { this.saveFilterConditions(iColumn, value, type, false); this.filtersUsedCalc(); this.filter(); }, /** * save filter conditions to local storage * @param iColumn {Number} * @param value {String|Array} * @param type {String} * @param skipFilter {Boolean} */ saveFilterConditions: function(iColumn, value, type, skipFilter) { var filterCondition = this.get('filterConditions').findProperty('iColumn', iColumn); if (filterCondition) { filterCondition.value = value; filterCondition.skipFilter = skipFilter; } else { filterCondition = { skipFilter: skipFilter, iColumn: iColumn, value: value, type: type }; this.get('filterConditions').push(filterCondition); } App.db.setFilterConditions(this.get('controller.name'), this.get('filterConditions')); }, saveDisplayLength: function() { var self = this; Em.run.next(function() { App.db.setDisplayLength(self.get('controller.name'), self.get('displayLength')); if (!App.get('testMode')) { if (App.isAccessible('upgrade_ADMIN')) { self.postUserPref(self.displayLengthKey(), self.get('displayLength')); } } }); }, clearFilterCondition: function() { App.db.setFilterConditions(this.get('controller.name'), null); }, /** * Contain filter conditions for each column * @type {Array} */ filterConditions: [], /** * Contains content after implementing filters * @type {Array} */ filteredContent: [], /** * Determine if filteredContent is empty or not * @type {Boolean} */ hasFilteredItems: function() { return !!this.get('filteredCount'); }.property('filteredCount'), /** * Contains content to show on the current page of data page view * @type {Array} */ pageContent: function () { return this.get('filteredContent').slice(this.get('startIndex') - 1, this.get('endIndex')); }.property('filteredCount', 'startIndex', 'endIndex'), /** * Filter table by filterConditions */ filter: function () { var content = this.get('content'); var filterConditions = this.get('filterConditions').filterProperty('value'); var result; var assoc = this.get('colPropAssoc'); if (filterConditions.length) { result = content.filter(function (item) { var match = true; filterConditions.forEach(function (condition) { var filterFunc = filters.getFilterByType(condition.type, false); if (match) { match = filterFunc(item.get(assoc[condition.iColumn]), condition.value); } }); return match; }); this.set('filteredContent', result); } else { this.set('filteredContent', content.toArray()); } }.observes('content.length'), /** * sort content by active sort column */ sortContent: function() { var activeSort = App.db.getSortingStatuses(this.get('controller.name')).find(function (sort) { return (sort.status === 'sorting_asc' || sort.status === 'sorting_desc'); }); var sortIndexes = { 'sorting_asc': 1, 'sorting_desc': -1 }; this.get('content').sort(function (a, b) { if (a.get(activeSort.name) > b.get(activeSort.name)) return sortIndexes[activeSort.status]; if (a.get(activeSort.name) < b.get(activeSort.name)) return -(sortIndexes[activeSort.status]); return 0; }); this.filter(); }, /** * Does any filter is used on the page * @type {Boolean} */ filtersUsed: false, /** * Determine if some filters are used on the page * Set filtersUsed value */ filtersUsedCalc: function() { var filterConditions = this.get('filterConditions'); if (!filterConditions.length) { this.set('filtersUsed', false); return; } var filtersUsed = false; filterConditions.forEach(function(filterCondition) { if (filterCondition.value.toString() !== '') { filtersUsed = true; } }); this.set('filtersUsed', filtersUsed); }, /** * Run clearFilter in the each child filterView */ clearFilters: function() { this.set('filterConditions', []); this.get('_childViews').forEach(function(childView) { if (childView['clearFilter']) { childView.clearFilter(); } }); } });