add correct returns to sortable search matches

also cleaned up code style

rancher/rancher#18288
This commit is contained in:
Westly Wright 2019-02-22 15:39:30 -07:00
parent 7537421efc
commit 4f0ad7ecbe
No known key found for this signature in database
GPG Key ID: 4FAB3D8673DC54A3
2 changed files with 94 additions and 83 deletions

View File

@ -33,6 +33,7 @@ function toggleInput(node, on) {
} }
} }
} }
export function matches(fields, token, item) { export function matches(fields, token, item) {
let tokenMayBeIp = /^[0-9a-f\.:]+$/i.test(token); let tokenMayBeIp = /^[0-9a-f\.:]+$/i.test(token);
@ -66,8 +67,8 @@ export function matches(fields, token, item) {
if ( val === token ) { if ( val === token ) {
return true; return true;
} }
break;
return false;
case 'ip': case 'ip':
if ( tokenMayBeIp ) { if ( tokenMayBeIp ) {
let re = new RegExp(`(?:^|\.)${ token }(?:\.|$)`); let re = new RegExp(`(?:^|\.)${ token }(?:\.|$)`);
@ -76,18 +77,20 @@ export function matches(fields, token, item) {
return true; return true;
} }
} }
break;
return false;
case 'prefix': case 'prefix':
if ( val.indexOf(token) === 0) { if ( val.indexOf(token) === 0) {
return true; return true;
} }
break;
return false;
default: default:
if ( val.indexOf(token) >= 0) { if ( val.indexOf(token) >= 0) {
return true; return true;
} }
return false;
} }
} }
} }
@ -96,9 +99,9 @@ export function matches(fields, token, item) {
} }
export default Component.extend(Sortable, StickyHeader, { export default Component.extend(Sortable, StickyHeader, {
prefs: service(), prefs: service(),
intl: service(), intl: service(),
bulkActionHandler: service(), bulkActionHandler: service(),
layout, layout,
body: null, body: null,
@ -121,22 +124,23 @@ export default Component.extend(Sortable, StickyHeader, {
checkWidth: 40, checkWidth: 40,
actionsWidth: 40, actionsWidth: 40,
availableActions: null, availableActions: null,
selectedNodes: null, selectedNodes: null,
prevNode: null, prevNode: null,
searchText: null, searchText: null,
isVisible: true, isVisible: true,
page: 1, page: 1,
pagingLabel: 'pagination.generic', pagingLabel: 'pagination.generic',
showHeader: or('bulkActions', 'searchInPlace'), showHeader: or('bulkActions', 'searchInPlace'),
// ----- // -----
sortableContent: alias('body'), sortableContent: alias('body'),
init() { init() {
this._super(...arguments); this._super(...arguments);
this.set('selectedNodes', []); set(this, 'selectedNodes', []);
if (get(this, 'bulkActions')) { if (get(this, 'bulkActions')) {
this.actionsChanged(); this.actionsChanged();
} }
@ -144,7 +148,7 @@ export default Component.extend(Sortable, StickyHeader, {
if ( get(this, 'bulkActions') ) { if ( get(this, 'bulkActions') ) {
run.schedule('afterRender', () => { run.schedule('afterRender', () => {
let table = $(this.element).find('> TABLE'); // eslint-disable-line let table = $(this.element).find('> TABLE'); // eslint-disable-line
let self = this; // need this context in click function and can't use arrow func there let self = this; // need this context in click function and can't use arrow func there
table.on('click', '> TBODY > TR', (e) => { table.on('click', '> TBODY > TR', (e) => {
self.rowClick(e); self.rowClick(e);
@ -169,11 +173,11 @@ export default Component.extend(Sortable, StickyHeader, {
let map = {}; let map = {};
let groupKey = get(this, 'groupByKey'); let groupKey = get(this, 'groupByKey');
let refKey = get(this, 'groupByRef'); let refKey = get(this, 'groupByRef');
get(this, 'pagedContent').forEach((obj) => { get(this, 'pagedContent').forEach((obj) => {
let group = get(obj, groupKey) || ''; let group = get(obj, groupKey) || '';
let ref = get(obj, refKey) || { displayName: group }; let ref = get(obj, refKey) || { displayName: group };
let entry = map[group]; let entry = map[group];
if ( entry ) { if ( entry ) {
@ -184,7 +188,9 @@ export default Component.extend(Sortable, StickyHeader, {
ref, ref,
items: [obj] items: [obj]
}; };
map[group] = entry; map[group] = entry;
ary.push(entry); ary.push(entry);
} }
if ( get(this, 'selectedNodes').includes(obj) ) { if ( get(this, 'selectedNodes').includes(obj) ) {
@ -199,7 +205,6 @@ export default Component.extend(Sortable, StickyHeader, {
}, },
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments);
if (get(this, 'isVisible')) { if (get(this, 'isVisible')) {
this.triggerResize(); this.triggerResize();
} }
@ -207,18 +212,19 @@ export default Component.extend(Sortable, StickyHeader, {
actions: { actions: {
clearSearch() { clearSearch() {
this.set('searchText', ''); set(this, 'searchText', '');
}, },
executeBulkAction(name, e) { executeBulkAction(name, e) {
e.preventDefault(); e.preventDefault();
let handler = get(this, 'bulkActionHandler'); let handler = get(this, 'bulkActionHandler');
let nodes = get(this, 'selectedNodes'); let nodes = get(this, 'selectedNodes');
if (isAlternate(e)) { if (isAlternate(e)) {
var available = get(this, 'availableActions'); var available = get(this, 'availableActions');
var action = available.findBy('action', name); var action = available.findBy('action', name);
let alt = get(action, 'altAction'); let alt = get(action, 'altAction');
if ( alt ) { if ( alt ) {
name = alt; name = alt;
@ -243,7 +249,7 @@ export default Component.extend(Sortable, StickyHeader, {
// Pick a new sort if the current column disappears. // Pick a new sort if the current column disappears.
headersChanged: observer('headers.@each.name', function() { headersChanged: observer('headers.@each.name', function() {
let sortBy = get(this, 'sortBy'); let sortBy = get(this, 'sortBy');
let headers = get(this, 'headers') || []; let headers = get(this, 'headers') || [];
if ( headers && headers.get('length') ) { if ( headers && headers.get('length') ) {
@ -263,19 +269,19 @@ export default Component.extend(Sortable, StickyHeader, {
pageCountChanged: observer('indexFrom', 'filtered.length', function() { pageCountChanged: observer('indexFrom', 'filtered.length', function() {
// Go to the last page if we end up past the last page // Go to the last page if we end up past the last page
let from = get(this, 'indexFrom'); let from = get(this, 'indexFrom');
let last = get(this, 'filtered.length'); let last = get(this, 'filtered.length');
var perPage = get(this, 'perPage'); var perPage = get(this, 'perPage');
if ( get(this, 'page') > 1 && from > last) { if ( get(this, 'page') > 1 && from > last) {
let page = Math.ceil(last / perPage); let page = Math.ceil(last / perPage);
this.set('page', page); set(this, 'page', page);
} }
}), }),
sortKeyChanged: observer('sortBy', function() { sortKeyChanged: observer('sortBy', function() {
this.set('page', 1); set(this, 'page', 1);
}), }),
actionsChanged: observer('selectedNodes.@each._availableActions', 'pagedContent.@each._availableActions', function() { actionsChanged: observer('selectedNodes.@each._availableActions', 'pagedContent.@each._availableActions', function() {
@ -283,11 +289,12 @@ export default Component.extend(Sortable, StickyHeader, {
return; return;
} }
let nodes = get(this, 'selectedNodes'); let nodes = get(this, 'selectedNodes');
let disableAll = false; let disableAll = false;
if ( !nodes.length ) { if ( !nodes.length ) {
disableAll = true; disableAll = true;
let firstNode = get(this, 'pagedContent.firstObject'); let firstNode = get(this, 'pagedContent.firstObject');
if ( firstNode ) { if ( firstNode ) {
@ -307,6 +314,7 @@ export default Component.extend(Sortable, StickyHeader, {
if ( !obj ) { if ( !obj ) {
obj = $().extend(true, {}, act);// eslint-disable-line obj = $().extend(true, {}, act);// eslint-disable-line
map[act.action] = obj; map[act.action] = obj;
} }
@ -326,11 +334,12 @@ export default Component.extend(Sortable, StickyHeader, {
if ( !obj ) { if ( !obj ) {
obj = $().extend(true, {}, act); // eslint-disable-line obj = $().extend(true, {}, act); // eslint-disable-line
map[act.action] = obj; map[act.action] = obj;
} }
obj.available = (obj.available || 0) + (act.enabled === false ? 0 : 1 ); obj.available = (obj.available || 0) + (act.enabled === false ? 0 : 1 );
obj.total = (obj.total || 0) + 1; obj.total = (obj.total || 0) + 1;
}) })
}); });
@ -350,7 +359,7 @@ export default Component.extend(Sortable, StickyHeader, {
}); });
} }
this.set('availableActions', out); set(this, 'availableActions', out);
}), }),
searchInPlace: computed('search', 'searchToWormhole', function() { searchInPlace: computed('search', 'searchToWormhole', function() {
return get(this, 'search') && !get(this, 'searchToWormhole'); return get(this, 'search') && !get(this, 'searchToWormhole');
@ -385,15 +394,15 @@ export default Component.extend(Sortable, StickyHeader, {
// For data-title properties on <td>s // For data-title properties on <td>s
dt: computed('headers.@each.{name,label,translationKey}', 'intl.locale', function() { dt: computed('headers.@each.{name,label,translationKey}', 'intl.locale', function() {
let intl = get(this, 'intl'); let intl = get(this, 'intl');
let out = { let out = {
select: `${ intl.t('generic.select') }: `, select: `${ intl.t('generic.select') }: `,
actions: `${ intl.t('generic.actions') }: `, actions: `${ intl.t('generic.actions') }: `,
}; };
get(this, 'headers').forEach((header) => { get(this, 'headers').forEach((header) => {
let name = get(header, 'name'); let name = get(header, 'name');
let dtKey = get(header, 'dtTranslationKey'); let dtKey = get(header, 'dtTranslationKey');
let key = get(header, 'translationKey'); let key = get(header, 'translationKey');
if ( dtKey ) { if ( dtKey ) {
out[name] = `${ intl.t(dtKey) }: `; out[name] = `${ intl.t(dtKey) }: `;
@ -426,33 +435,35 @@ export default Component.extend(Sortable, StickyHeader, {
}), }),
filtered: computed('arranged.[]', 'searchText', function() { filtered: computed('arranged.[]', 'searchText', function() {
let out = get(this, 'arranged').slice(); let out = get(this, 'arranged').slice();
let searchFields = get(this, 'searchFields'); let searchFields = get(this, 'searchFields');
let searchText = (get(this, 'searchText') || '').trim().toLowerCase(); let searchText = (get(this, 'searchText') || '').trim().toLowerCase();
let subSearchField = get(this, 'subSearchField'); let subSearchField = get(this, 'subSearchField');
let subFields = get(this, 'subFields'); let subFields = get(this, 'subFields');
let subMatches = null; let subMatches = null;
if ( searchText.length ) { if ( searchText.length ) {
subMatches = {}; subMatches = {};
let searchTokens = searchText.split(/\s*[, ]\s*/); let searchTokens = searchText.split(/\s*[, ]\s*/);
for ( let i = out.length - 1 ; i >= 0 ; i-- ) { for ( let i = out.length - 1 ; i >= 0 ; i-- ) {
let hits = 0; let hits = 0;
let row = out[i]; let row = out[i];
let mainFound = true; let mainFound = true;
for ( let j = 0 ; j < searchTokens.length ; j++ ) { for ( let j = 0 ; j < searchTokens.length ; j++ ) {
let expect = true; let expect = true;
let token = searchTokens[j]; let token = searchTokens[j];
if ( token.substr(0, 1) === '!' ) { if ( token.substr(0, 1) === '!' ) {
expect = false; expect = false;
token = token.substr(1); token = token.substr(1);
} }
if ( token && matches(searchFields, token, row) !== expect ) { if ( token && matches(searchFields, token, row) !== expect ) {
mainFound = false; mainFound = false;
break; break;
} }
} }
@ -465,15 +476,16 @@ export default Component.extend(Sortable, StickyHeader, {
for ( let l = 0 ; l < searchTokens.length ; l++ ) { for ( let l = 0 ; l < searchTokens.length ; l++ ) {
let expect = true; let expect = true;
let token = searchTokens[l]; let token = searchTokens[l];
if ( token.substr(0, 1) === '!' ) { if ( token.substr(0, 1) === '!' ) {
expect = false; expect = false;
token = token.substr(1); token = token.substr(1);
} }
if ( matches(subFields, token, subRows[k]) !== expect ) { if ( matches(subFields, token, subRows[k]) !== expect ) {
subFound = false; subFound = false;
break; break;
} }
} }
@ -492,7 +504,7 @@ export default Component.extend(Sortable, StickyHeader, {
} }
} }
this.set('subMatches', subMatches); set(this, 'subMatches', subMatches);
return out; return out;
}), }),
@ -509,11 +521,11 @@ export default Component.extend(Sortable, StickyHeader, {
}), }),
pageCountContent: computed('indexFrom', 'indexTo', 'pagedContent.totalPages', function() { pageCountContent: computed('indexFrom', 'indexTo', 'pagedContent.totalPages', function() {
let from = get(this, 'indexFrom') || 0; let from = get(this, 'indexFrom') || 0;
let to = get(this, 'indexTo') || 0; let to = get(this, 'indexTo') || 0;
let count = get(this, 'filtered.length') || 0; let count = get(this, 'filtered.length') || 0;
let pages = get(this, 'pagedContent.totalPages') || 0; let pages = get(this, 'pagedContent.totalPages') || 0;
let out = ''; let out = '';
if ( pages <= 1 ) { if ( pages <= 1 ) {
out = `${ count } Item${ count === 1 ? '' : 's' }`; out = `${ count } Item${ count === 1 ? '' : 's' }`;
@ -530,7 +542,7 @@ export default Component.extend(Sortable, StickyHeader, {
}, },
set(key, value) { set(key, value) {
var content = this.get('pagedContent').filterBy('canBulkRemove'); var content = get(this, 'pagedContent').filterBy('canBulkRemove');
if ( value ) { if ( value ) {
this.toggleMulti(content, []); this.toggleMulti(content, []);
@ -546,8 +558,8 @@ export default Component.extend(Sortable, StickyHeader, {
cleanupOrphans() { cleanupOrphans() {
// Remove selected items not in the current content // Remove selected items not in the current content
let content = get(this, 'pagedContent'); let content = get(this, 'pagedContent');
let nodesToAdd = []; let nodesToAdd = [];
let nodesToRemove = []; let nodesToRemove = [];
get(this, 'selectedNodes').forEach((node) => { get(this, 'selectedNodes').forEach((node) => {
@ -566,16 +578,16 @@ export default Component.extend(Sortable, StickyHeader, {
// ------ // ------
rowClick(e) { rowClick(e) {
let tagName = e.target.tagName; let tagName = e.target.tagName;
let tgt = $(e.target); // eslint-disable-line let tgt = $(e.target); // eslint-disable-line
if ( tagName === 'A' || tagName === 'BUTTON' || tgt.parents('.btn').length || typeof tgt.data('ember-action') !== 'undefined' || tgt.hasClass('copy-btn') ) { if ( tagName === 'A' || tagName === 'BUTTON' || tgt.parents('.btn').length || typeof tgt.data('ember-action') !== 'undefined' || tgt.hasClass('copy-btn') ) {
return; return;
} }
let content = get(this, 'pagedContent'); let content = get(this, 'pagedContent');
let selection = get(this, 'selectedNodes'); let selection = get(this, 'selectedNodes');
let isCheckbox = tagName === 'INPUT' || tgt.hasClass('row-check'); let isCheckbox = tagName === 'INPUT' || tgt.hasClass('row-check');
let tgtRow = $(e.currentTarget); // eslint-disable-line let tgtRow = $(e.currentTarget); // eslint-disable-line
if ( tgtRow.hasClass('separator-row') || tgt.hasClass('select-all-check')) { if ( tgtRow.hasClass('separator-row') || tgt.hasClass('select-all-check')) {
return; return;
@ -602,7 +614,7 @@ export default Component.extend(Sortable, StickyHeader, {
} }
let isSelected = selection.includes(node); let isSelected = selection.includes(node);
let prevNode = get(this, 'prevNode'); let prevNode = get(this, 'prevNode');
// PrevNode is only valid if it's in the current content // PrevNode is only valid if it's in the current content
if ( !prevNode || !content.includes(prevNode) ) { if ( !prevNode || !content.includes(prevNode) ) {
@ -625,19 +637,18 @@ export default Component.extend(Sortable, StickyHeader, {
this.toggleMulti([node], content); this.toggleMulti([node], content);
} }
this.set('prevNode', node); set(this, 'prevNode', node);
}, },
nodesBetween(a, b) { nodesBetween(a, b) {
let toToggle = []; let toToggle = [];
let key = get(this, 'groupByKey'); let key = get(this, 'groupByKey');
if ( key ) { if ( key ) {
// Grouped has 2 levels to look through // Grouped has 2 levels to look through
let grouped = get(this, 'groupedContent'); let grouped = get(this, 'groupedContent');
let from = this.groupIdx(a);
let from = this.groupIdx(a); let to = this.groupIdx(b);
let to = this.groupIdx(b);
if ( !from || !to ) { if ( !from || !to ) {
return []; return [];
@ -650,7 +661,7 @@ export default Component.extend(Sortable, StickyHeader, {
for ( let i = from.group ; i <= to.group ; i++ ) { for ( let i = from.group ; i <= to.group ; i++ ) {
let items = grouped.objectAt(i).items; let items = grouped.objectAt(i).items;
let j = (from.group === i ? from.item : 0); let j = (from.group === i ? from.item : 0);
while ( items[j] && ( i < to.group || j <= to.item )) { while ( items[j] && ( i < to.group || j <= to.item )) {
toToggle.push(items[j]); toToggle.push(items[j]);
@ -660,11 +671,11 @@ export default Component.extend(Sortable, StickyHeader, {
} else { } else {
// Ungrouped is much simpler // Ungrouped is much simpler
let content = get(this, 'pagedContent'); let content = get(this, 'pagedContent');
let from = content.indexOf(a); let from = content.indexOf(a);
let to = content.indexOf(b); let to = content.indexOf(b);
[from, to] = [Math.min(from, to), Math.max(from, to)]; [from, to] = [Math.min(from, to), Math.max(from, to)];
toToggle = content.slice(from, to + 1); toToggle = content.slice(from, to + 1);
} }
return toToggle; return toToggle;

View File

@ -1,4 +1,4 @@
<table class="fixed grid sortable-table {{if internalBulkActions 'has-actions'}} {{if groupByKey 'bordered'}} {{if subRows 'has-sub-rows bordered'}} {{tableClassNames}}"> <table class="fixed grid sortable-table {{if internalBulkActions "has-actions"}} {{if groupByKey "bordered"}} {{if subRows "has-sub-rows bordered"}} {{tableClassNames}}">
<thead> <thead>
<tr class="fixed-header-placeholder"> <tr class="fixed-header-placeholder">
{{#if internalBulkActions}} {{#if internalBulkActions}}
@ -17,7 +17,7 @@
<div class="bulk-actions pull-left"> <div class="bulk-actions pull-left">
{{#each availableActions as |action index|}} {{#each availableActions as |action index|}}
{{#if action.enabled}} {{#if action.enabled}}
<a class="btn btn-sm bg-primary" href="#" onclick={{action 'executeBulkAction' action.action}} tabindex={{index}}> <a class="btn btn-sm bg-primary" href="#" onclick={{action "executeBulkAction" action.action}} tabindex={{index}}>
{{t action.label}} {{t action.label}}
<i class="{{action.icon}}"></i> <i class="{{action.icon}}"></i>
</a> </a>
@ -37,7 +37,7 @@
<div class="pull-left"> <div class="pull-left">
{{#if leftActions}} {{#if leftActions}}
<div class="vertical-middle pr-20"> <div class="vertical-middle pr-20">
{{yield this 'left-actions'}} {{yield this "left-actions"}}
</div> </div>
{{/if}} {{/if}}
</div> </div>
@ -46,11 +46,11 @@
{{#if search}} {{#if search}}
<div class="vertical-middle"> <div class="vertical-middle">
{{#ember-wormhole to=searchToWormhole renderInPlace=(not searchToWormhole)}} {{#ember-wormhole to=searchToWormhole renderInPlace=(not searchToWormhole)}}
<div class="{{unless searchToWormhole 'pull-right'}} search-group input-group"> <div class="{{unless searchToWormhole "pull-right"}} search-group input-group">
{{input value=searchText aria-title=(t 'generic.search') type="search" class="input-sm pull-right" placeholder=(t 'generic.search')}} {{input value=searchText aria-title=(t "generic.search") type="search" class="input-sm pull-right" placeholder=(t "generic.search")}}
{{#if searchText}} {{#if searchText}}
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn bg-transparent text-info pl-10 pr-10" {{action 'clearSearch'}}><i class="icon icon-close"/></button> <button class="btn bg-transparent text-info pl-10 pr-10" {{action "clearSearch"}}><i class="icon icon-close"/></button>
</span> </span>
{{/if}} {{/if}}
</div> </div>
@ -60,7 +60,7 @@
{{#if rightActions}} {{#if rightActions}}
<div class="vertical-middle pl-20"> <div class="vertical-middle pl-20">
{{yield this 'right-actions'}} {{yield this "right-actions"}}
</div> </div>
{{/if}} {{/if}}
</div> </div>
@ -89,7 +89,7 @@
</thead> </thead>
{{#if prefix}} {{#if prefix}}
<tbody> <tbody>
{{yield this 'prefix'}} {{yield this "prefix"}}
</tbody> </tbody>
{{/if}} {{/if}}
@ -97,33 +97,33 @@
{{#if extraGroups.length}} {{#if extraGroups.length}}
{{#each extraGroups as |group|}} {{#each extraGroups as |group|}}
<tbody class="group"> <tbody class="group">
{{yield this 'group' group}} {{yield this "group" group}}
{{yield this 'norows'}} {{yield this "norows"}}
</tbody> </tbody>
{{/each}} {{/each}}
{{/if}} {{/if}}
{{#each groupedContent as |group|}} {{#each groupedContent as |group|}}
<tbody class="group"> <tbody class="group">
{{yield this 'group' group}} {{yield this "group" group}}
{{#each group.items as |row|}} {{#each group.items as |row|}}
{{yield this 'row' row dt (array-includes childFilterNodes row.id)}} {{yield this "row" row dt (array-includes childFilterNodes row.id)}}
{{/each}} {{/each}}
</tbody> </tbody>
{{else}} {{else}}
{{yield this (if arranged.length 'nomatch' 'norows')}} {{yield this (if arranged.length "nomatch" "norows")}}
{{/each}} {{/each}}
{{else}} {{else}}
<tbody> <tbody>
{{#each pagedContent as |row|}} {{#each pagedContent as |row|}}
{{yield this 'row' row dt (array-includes childFilterNodes row.id)}} {{yield this "row" row dt (array-includes childFilterNodes row.id)}}
{{else}} {{else}}
{{yield this (if arranged.length 'nomatch' 'norows')}} {{yield this (if arranged.length "nomatch" "norows")}}
{{/each}} {{/each}}
</tbody> </tbody>
{{/if}} {{/if}}
{{#if suffix}} {{#if suffix}}
{{yield this 'suffix'}} {{yield this "suffix"}}
{{/if}} {{/if}}
</table> </table>