Skip to content

Commit b06fc27

Browse files
jiangtydjschnei
authored andcommitted
Re-introduce ajax player search (#194)
* return most relevant player matches from server if querying by string * fixes * frontend for ajax player search (rm logic, debounce) * reformat app module deps * fix filtering on promises * loading spinner for ajax call
1 parent 9d3d4c5 commit b06fc27

6 files changed

Lines changed: 47 additions & 115 deletions

File tree

server.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,15 @@ def get(self):
8686

8787
class PlayerListResource(restful.Resource):
8888

89+
# returns: match_quality
90+
# if match_quality > 0, consider it a match
8991
def _player_matches_query(self, player, query):
9092
player_name = player.name.lower()
9193
query = query.lower()
9294

9395
# try matching the full name first
9496
if player_name == query:
95-
return True
96-
97-
# if query is >= 3 chars, allow substring matching
98-
# this is to allow players with very short names to appear for small
99-
# search terms
100-
if len(query) >= 3 and query in player_name:
101-
return True
97+
return 10
10298

10399
# split the player name on common dividers and try to match against
104100
# each part starting from the beginning
@@ -107,28 +103,31 @@ def _player_matches_query(self, player, query):
107103
for token in tokens:
108104
if token:
109105
if token.startswith(query):
110-
return True
106+
return 5
107+
108+
# if query is >= 3 chars, allow substring matching
109+
# this is to allow players with very short names to appear for small
110+
# search terms
111+
if len(query) >= 3 and query in player_name:
112+
return 1
111113

112114
# no match
113-
return False
115+
return 0
114116

115117
def _get_players_matching_query(self, players, query):
116-
matching_players = []
117-
118-
for player in players:
119-
if self._player_matches_query(player, query):
120-
matching_players.append(player)
118+
# get list of (player, match_quality)
119+
matching_players = [(player, self._player_matches_query(player, query)) for player in players]
121120

122-
# move exact matches to the front so that short names are guaranteed to
123-
# appear
124-
for i in xrange(len(matching_players)):
125-
player = matching_players[i]
126-
if player.name.lower() == query:
127-
matching_players.insert(0, matching_players.pop(i))
121+
# sort by most relevant matches
122+
matching_players = sorted(
123+
filter(lambda x: x[1] > 0, matching_players),
124+
key=lambda x: -x[1])
128125

126+
# restrict to most relevant matches
129127
matching_players = matching_players[:TYPEAHEAD_PLAYER_LIMIT]
130128

131-
return matching_players
129+
# return player objects
130+
return [p[0] for p in matching_players]
132131

133132
def get(self, region):
134133
dao = get_dao(region)

webapp/app/app.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
var app = angular.module('app',
2-
['ngRoute', 'ui.bootstrap',
3-
'app.common',
4-
'app.headToHead',
5-
'app.players',
6-
'app.rankings',
7-
'app.tools',
8-
'app.tournaments']);
1+
var app = angular.module('app', [
2+
'ngRoute',
3+
'ui.bootstrap',
4+
'app.common',
5+
'app.headToHead',
6+
'app.players',
7+
'app.rankings',
8+
'app.tools',
9+
'app.tournaments'
10+
]);
911

1012
app.config(function ($httpProvider) {
1113
$httpProvider.defaults.withCredentials = true;

webapp/app/common/services/region.service.js

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,10 @@ angular.module('app.common').service('RegionService', function ($http, PlayerSer
2929
}
3030
},
3131
populateDataForCurrentRegion: function() {
32-
// get all players instead of just players in region
33-
var curRegion = this.region;
34-
$http.get(hostname + this.region.id + '/players?all=true').
32+
$http.get(hostname + this.region.id + '/players').
3533
success(function(data) {
36-
PlayerService.allPlayerList = data;
37-
38-
// filter players for this region
39-
PlayerService.playerList = {
40-
'players': data.players.filter(
41-
function(player){
42-
return player.regions.some(
43-
function(region){
44-
if(region==null) return false;
45-
return region === curRegion.id;
46-
});
47-
})
48-
};
49-
});
34+
PlayerService.playerList = data;
35+
});
5036

5137
var tournamentURL = '/tournaments';
5238
if(SessionService.loggedIn){

webapp/app/players/services/players.service.js

Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -32,86 +32,26 @@ angular.module('app.players').service('PlayerService', function($http) {
3232
/* FAIL GRACEFULLY */
3333
}
3434
},
35-
// local port of _player_matches_query from backend
36-
// now returns matchQuality instead of just a boolean
37-
// if match_quality > 0, consider it a match
38-
playerMatchesQuery: function(player, query) {
39-
var playerName = player.name.toLowerCase();
40-
var query = query.toLowerCase();
41-
42-
if(playerName === query){
43-
return 10;
44-
}
45-
46-
var rex = /\.|\|| /;
47-
var tokens = playerName.split(rex);
48-
for(var i=0;i<tokens.length;i++){
49-
var token = tokens[i];
50-
if(token.length > 0){
51-
if(token.startsWith(query)){
52-
return 5;
53-
}
54-
}
55-
}
56-
57-
if(query.length >= 3 && playerName.includes(query)){
58-
return 1;
59-
}
60-
61-
// no match
62-
return 0;
63-
},
6435
getPlayerListFromQuery: function(query, filter_fn) {
65-
var TYPEAHEAD_PLAYER_LIMIT = 20;
66-
var filteredPlayers = [];
67-
for (var i = 0; i < this.allPlayerList.players.length; i++) {
68-
var curPlayer = this.allPlayerList.players[i];
69-
70-
// TODO: currently no callers where filter_fn isn't null
71-
if(filter_fn == null || filter_fn(curPlayer)){
72-
var matchQuality = this.playerMatchesQuery(curPlayer, query);
73-
this.addTypeaheadDisplayText(curPlayer);
74-
if(matchQuality > 0){
75-
filteredPlayers.push({'player': curPlayer,
76-
'quality': matchQuality});
77-
}
78-
}
79-
}
80-
81-
filteredPlayers.sort(function(p1, p2){
82-
if(p1.quality < p2.quality) return 1;
83-
else if(p1.quality > p2.quality) return -1;
84-
else return 0;
85-
});
86-
87-
filteredPlayers = filteredPlayers.slice(0, TYPEAHEAD_PLAYER_LIMIT);
88-
89-
filteredPlayers = filteredPlayers.map(p => p.player);
90-
91-
return filteredPlayers;
92-
93-
// let's not send so many get requests
94-
/*
9536
url = hostname + defaultRegion + '/players';
9637
params = {
9738
params: {
9839
query: query
9940
}
10041
}
10142

43+
var _parent = this;
44+
10245
return $http.get(url, params).then(function(response) {
10346
players = response.data.players;
104-
if (filter_fn != undefined) {
105-
filtered_players = []
106-
for (var i = 0; i < players.length; i++) {
107-
if (filter_fn(players[i])) {
108-
filtered_players.push(players[i])
109-
}
110-
}
111-
players = filtered_players;
47+
if (filter_fn !== undefined) {
48+
players = players.filter(filter_fn);
11249
}
50+
players.forEach(function(player) {
51+
_parent.addTypeaheadDisplayText(player);
52+
});
11353
return players;
114-
});*/
54+
});
11555
}
11656
};
11757
return service;

webapp/app/players/views/player_typeahead.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
type="text"
33
class="{{typeaheadClass}}"
44
ng-model="player"
5+
ng-model-options="{ debounce: 250 }"
56
placeholder="{{placeholder}}"
6-
uib-typeahead="p as p.typeahead for p in playerService.getPlayerListFromQuery($viewValue) | filter:notEqual(filteredOut)"
7+
uib-typeahead="p as p.typeahead for p in playerService.getPlayerListFromQuery($viewValue, notEqual(filteredOut))"
8+
typeahead-editable=false
79
typeahead-on-select="onPlayerSelect({item: $item})"
10+
typeahead-loading="loadingPlayers"
811
/>
12+
<i ng-show="loadingPlayers" class="fa fa-spinner fa-spin"></i>

webapp/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<!-- Latest compiled and minified CSS -->
55
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
6+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
67

78
<!-- Optional theme -->
89
<link rel="stylesheet" href="https://bootswatch.com/paper/bootstrap.min.css">

0 commit comments

Comments
 (0)