UNPKG

ember-cli-filtertable-inbox-health

Version:
329 lines (305 loc) 11.6 kB
import Em from 'ember'; export default Em.Component.extend({ /* System settings */ layoutName: 'components/filter-table', selectAll: false, // select-all button off by default deselectAll: false, // toggle for deselecting all (w/o all being selected) model: "", selectedRecords: Em.A([]), updateSelectedRecords: function() { var sr = this.get('selectedRecords'), fr = this.get('filteredRecords'); Em.run.once(function() { sr.clear(); sr.addObjects(fr.filterBy('selected', true)); Em.debug("Selected: %@".fmt(sr.get('length'))); }); }.observes('filteredRecords.@each.selected'), loadSelectedRecordsOnController: function() { var to = this.get('targetObject'); if (to === undefined || to === null) { Em.debug("WARNING: no target object found. Are we testing?"); return; } if (Em.isBlank(to.get('selectedRecords'))) { this.set('targetObject.selectedRecords', this.get('selectedRecords')); } }.on('init'), isTree: false, showSearchAncestors: true, /* General table settings */ viewLimit: 20, columnNum: 2, headerFilterColspan: function() { var diff = (this.get('showCheckboxes')) ? 1 : 0; return this.get('columnNum') + diff; }.property('columnNum'), /* Elements pertaining to the input box used for filtereing results */ showTextFilter: true, textFilter: "", // The search bar at the top for filtering filterField: 'name', /* Checkbox select/deselect all logic */ showCheckboxes: true, noneSelected: function() { return this.get('selectedRecords.length') < 1; }.property('selectedRecords.@each'), oneSelected: function() { return this.get('selectedRecords.length') === 1; }.property('selectedRecords.@each'), oneOrMoreSelected: function() { return this.get('selectedRecords.length') > 0; }.property('selectedRecords.@each'), allSelected: function() { return this.get('selectedRecords.length') === this.get('filteredRecords.length'); }.property('selectedRecords.@each', 'filteredRecords.@each'), /* Tree view settings */ applyTreeFilter: function(records) { /* All expand/collapse logic is done here. We don't dynamically add records * in the template. Instead we add them to the list here and rely on the * sorting by depth first to ensure the correct order. */ if (this.get('isTree') === false) { return records; } function getSubtree(record) { // Returns an array containing the whole subtree of the parent var records = [record]; if (record.get('isExpanded') === true) { // This needs to become a promise for async references record.get('children.content').forEach(function(child) { records = records.concat(getSubtree(child)); }); } return records; } function isAncestor(node, filterResults) { var _isAncestor = false; node.get('children').forEach(function(child) { if (filterResults.indexOf(child) > -1) { // this is a direct parent of a search result _isAncestor = true; } if (isAncestor(child, filterResults) === true) { // this child is a distant ancestor; _isAncestor = true; } }); return _isAncestor; } function getAncestors(node, filterResults) { var ancestors = []; if (filterResults.indexOf(node) > -1) { ancestors.push(node); } else { if (isAncestor(node, filterResults)) { ancestors.push(node); var childAncestors = []; node.get('children').forEach(function(child) { childAncestors = childAncestors.concat( getAncestors(child, filterResults)); }); ancestors = ancestors.concat(childAncestors); } } return ancestors; } var finalGroups = Em.A([]); Em.debug("If text filter is empty, display root nodes"); if (Em.isBlank(this.get('textFilter'))) { // work off the root nodes records.forEach(function(r) { if (r.get('depth') < 2) { finalGroups = finalGroups.concat(getSubtree(r)); } }); } else { if (this.get('showSearchAncestors') === false) { // show only matching search results finalGroups = records; } else { // Construct a tree containing the ancestry lines of the matching // search results. We do this by traversing the tree from all the roots var roots = this.get('_prefilterRecords').filterBy('depth', 1); Em.debug('- Getting ancestry -'); roots.forEach(function(r) { Em.debug(' %@'.fmt(r.get('name'))); finalGroups = finalGroups.concat(getAncestors(r, records)); }); } } return finalGroups; }, filteredRecords: Em.A([]), // Displayed records toggleAllSelection: function() { // Called when selectAll checkbox is toggled and ensures all records' // selection status matches that decreed by the select-all button var fRecords = this.get('filteredRecords'), sRecords = this.get('selectedRecords'), aRecords = this.get('content').filterBy('selected', true); Em.debug("Select-all checkbox selected? %@".fmt(this.get('selectAll'))); Em.run.once(this, function() { if (this.get('selectAll') === true) { // Select-all button checked, ensure that all visible records are // selected, and invisible records are unchecked if (sRecords.get('length') === fRecords.get('length')) { // all records are already selected return; } // unselecting hidden records, and select all visible records aRecords.forEach(function(r) { r.set('selected', false); }); fRecords.forEach(function(r) { r.set('selected', true); }); } else { // select-all is unchecked, so lets unselect all if all visible records // are selected if (sRecords.get('length') === fRecords.get('length')) { // deselect-all since all are selected aRecords.forEach(function(r) { r.set('selected', false); }); } } }); }.observes('selectAll'), toggleSelectAllCheckbox: function() { Em.run.once(this, function() { var as = this.get('allSelected'), sa = this.get('selectAll'); if (as !== sa) { Em.debug("Set select-all checkbox to table state"); this.set('selectAll', as); } }); }.observes('selectedRecords.@each'), deselectAllRecords: function() { if (this.get('deselectAll') !== true) { // only run this when deselectAll is set to true. it is automatically // returned to false once everything has been deselected; return; } // Explicitly deselect all. Just setting selectAll to false isn't // sufficient since not all records may be selected at this point if (this.get('selectAll') === true) { // all records are selected, so we can simply deselect them all this.set('selectAll', false); } else { var aRecords = this.get('content').filterBy('selected', true); aRecords.forEach(function(r) { r.set('selected', false); }); } this.set('deselectAll', false); }.observes('deselectAll'), hasNoFilteredRecords: function() { return this.get('filteredRecords.length') < 1; }.property('filteredRecords.@each'), hasNoActualRecords: function() { return this.get('content').get('length') < 1; }.property('content.@each'), applyTextFilter: function () { var filter = this.get('textFilter'); var store = this.get('targetObject.store'); var controller = this.get('targetObject'); this.set('_ignoreReload', true); if (!Em.isBlank(filter)) { Em.debug("Applying text filter to records"); filter = filter.toLowerCase(); store.find(this.get('model'), { filter_string: filter }).then(function (data) { controller.set('content', data); }, function (error) { Em.debug("No records found"); }); } else{ store.find(this.get('model')).then(function (data) { controller.set('content', data); }, function (error) { Em.debug("No records found"); }); } }, loadRecords: function () { Em.debug('Refreshing visible records'); if (this.get('_ignoreReload') === true) { Em.debug("Don't reload for targetObject.reload value change"); this.set('_ignoreReload', false); return; } this.applyTextFilter(); var ac = this.get('arrangedContent') || this.get('content.arrangedContent') || this.get('content'); if (Em.isEmpty(ac)) { this.set('filteredRecords', []); return; } // ac = ac.toArray(); // make copy of the content record // this.set('_prefilterRecords', ac); if (!Em.isBlank(this.get('targetObject.applyDropdownFilter'))) { ac = this.get('targetObject').applyDropdownFilter(ac); } // ac = this.applyTreeFilter(ac); // Em.debug("Showing filteredRecords"); // var vl = this.get('viewLimit'); // if (vl > 0 && ac.get('length') > this.get('viewLimit')) { // Em.debug("\tChopping records to viewLimit"); // ac = ac.splice(0, this.get('viewLimit')); // } this.set('filteredRecords', ac); if (this.get('reloadRecords') === true) { this.set('_ignoreReload', true); this.set('reloadRecords', false); } }.observes('textFilter', 'reloadRecords'), loadOnContentChange: function() { if (Em.isEmpty(this.get('content'))) { return; } Em.run.once(this, 'loadRecords'); }.on('init').observes('content.@each'), actions: { // custom actions which the user can implement. Its a direct link to a // controller action handler submit: function(actionName, record) { this.get('targetObject').send(actionName, record); }, remove: function(actionName, record) { this.get('targetObject').send(actionName, record); }, showModal: function(actionName, record) { this.sendAction('onShowModal', actionName, record); }, toggleExpand: function(record) { Em.debug("Expanding/Collapsing record"); var e = record.get('isExpanded') || false; if (record.get('childNum') < 1) { Em.debug("Cannot expand record without children"); return; } record.set('isExpanded', !e); this.set('reloadRecords', true); }, sortBy: function (field) { var propertyString = field + '_sorted'; var sortDirection = ""; if (this.get(propertyString) == true) { sortDirection = "DESC" this.set(propertyString, false); } else { sortDirection = "ASC" this.set(propertyString, true); } var store = this.get('targetObject.store'); var controller = this.get('targetObject'); store.find(this.get('model'), { sort_param: field, sort_dir: sortDirection }).then(function (data) { controller.set('content', data); }, function (error) { Em.debug("No records found"); }); } } });