Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 4bc8ec3

Browse files
committed
room, user, ddg autocomplete providers (wip)
1 parent 0df201c commit 4bc8ec3

File tree

9 files changed

+163
-19
lines changed

9 files changed

+163
-19
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"react-dom": "^15.0.1",
3939
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#c3d942e",
4040
"sanitize-html": "^1.11.1",
41-
"velocity-vector": "vector-im/velocity#059e3b2"
41+
"velocity-vector": "vector-im/velocity#059e3b2",
42+
"whatwg-fetch": "^1.0.0"
4243
},
4344
"//babelversion": [
4445
"brief experiments with babel6 seems to show that it generates source ",

src/MatrixClientPeg.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ limitations under the License.
2020
var Matrix = require("matrix-js-sdk");
2121
var GuestAccess = require("./GuestAccess");
2222

23-
var matrixClient = null;
23+
let matrixClient: MatrixClient = null;
2424

2525
var localStorage = window.localStorage;
2626

@@ -82,7 +82,7 @@ class MatrixClient {
8282
this.guestAccess = guestAccess;
8383
}
8484

85-
get() {
85+
get(): MatrixClient {
8686
return matrixClient;
8787
}
8888

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export default class AutocompleteProvider {
2-
2+
getName(): string {
3+
return 'Default Provider';
4+
}
35
}

src/autocomplete/Autocompleter.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import CommandProvider from './CommandProvider';
2+
import DuckDuckGoProvider from './DuckDuckGoProvider';
3+
import RoomProvider from './RoomProvider';
4+
import UserProvider from './UserProvider';
25

3-
const COMPLETERS = [CommandProvider].map(completer => new completer());
6+
const PROVIDERS = [
7+
CommandProvider,
8+
DuckDuckGoProvider,
9+
RoomProvider,
10+
UserProvider
11+
].map(completer => new completer());
412

513
export function getCompletions(query: String) {
6-
return COMPLETERS.map(completer => completer.getCompletions(query));
14+
return PROVIDERS.map(provider => {
15+
return {
16+
completions: provider.getCompletions(query),
17+
provider
18+
};
19+
});
720
}

src/autocomplete/CommandProvider.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,8 @@ export default class CommandProvider extends AutocompleteProvider {
6262
}
6363
return Q.when(completions);
6464
}
65+
66+
getName() {
67+
return 'Commands';
68+
}
6569
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import AutocompleteProvider from './AutocompleteProvider';
2+
import Q from 'q';
3+
import 'whatwg-fetch';
4+
5+
const DDG_REGEX = /\/ddg\w+(.+)$/;
6+
const REFERER = 'vector';
7+
8+
export default class DuckDuckGoProvider extends AutocompleteProvider {
9+
static getQueryUri(query: String) {
10+
return `http://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&t=${encodeURIComponent(REFERER)}`;
11+
}
12+
13+
getCompletions(query: String) {
14+
if(!query)
15+
return Q.when([]);
16+
17+
let promise = Q.defer();
18+
fetch(DuckDuckGoProvider.getQueryUri(query), {
19+
method: 'GET'
20+
}).then(response => {
21+
let results = response.Results.map(result => {
22+
return {
23+
title: result.Text,
24+
description: result.Result
25+
};
26+
});
27+
promise.resolve(results);
28+
});
29+
return promise;
30+
}
31+
32+
getName() {
33+
return 'Results from DuckDuckGo';
34+
}
35+
}

src/autocomplete/RoomProvider.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import AutocompleteProvider from './AutocompleteProvider';
2+
import Q from 'q';
3+
import MatrixClientPeg from '../MatrixClientPeg';
4+
5+
const ROOM_REGEX = /(?=#)[^\s]*/g;
6+
7+
export default class RoomProvider extends AutocompleteProvider {
8+
constructor() {
9+
super();
10+
}
11+
12+
getCompletions(query: String) {
13+
let client = MatrixClientPeg.get();
14+
let completions = [];
15+
const matches = query.match(ROOM_REGEX);
16+
if(!!matches) {
17+
const command = matches[0];
18+
completions = client.getRooms().map(room => {
19+
return {
20+
title: room.name,
21+
subtitle: room.roomId
22+
};
23+
});
24+
}
25+
return Q.when(completions);
26+
}
27+
28+
getName() {
29+
return 'Rooms';
30+
}
31+
}

src/autocomplete/UserProvider.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import AutocompleteProvider from './AutocompleteProvider';
2+
import Q from 'q';
3+
import MatrixClientPeg from '../MatrixClientPeg';
4+
5+
const ROOM_REGEX = /@[^\s]*/g;
6+
7+
export default class UserProvider extends AutocompleteProvider {
8+
constructor() {
9+
super();
10+
}
11+
12+
getCompletions(query: String) {
13+
let client = MatrixClientPeg.get();
14+
let completions = [];
15+
const matches = query.match(ROOM_REGEX);
16+
if(!!matches) {
17+
const command = matches[0];
18+
completions = client.getUsers().map(user => {
19+
return {
20+
title: user.displayName,
21+
description: user.userId
22+
};
23+
});
24+
}
25+
return Q.when(completions);
26+
}
27+
28+
getName() {
29+
return 'Users';
30+
}
31+
}

src/components/views/rooms/Autocomplete.js

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,28 @@ export default class Autocomplete extends React.Component {
1111
}
1212

1313
componentWillReceiveProps(props, state) {
14-
getCompletions(props.query)[0].then(completions => {
15-
console.log(completions);
16-
this.setState({
17-
completions
18-
});
14+
getCompletions(props.query).map(completionResult => {
15+
try {
16+
completionResult.completions.then(completions => {
17+
let i = this.state.completions.findIndex(
18+
completion => completion.provider === completionResult.provider
19+
);
20+
21+
i = i == -1 ? this.state.completions.length : i;
22+
console.log(completionResult);
23+
let newCompletions = Object.assign([], this.state.completions);
24+
completionResult.completions = completions;
25+
newCompletions[i] = completionResult;
26+
console.log(newCompletions);
27+
this.setState({
28+
completions: newCompletions
29+
});
30+
}, err => {
31+
32+
});
33+
} catch (e) {
34+
// An error in one provider shouldn't mess up the rest.
35+
}
1936
});
2037
}
2138

@@ -33,18 +50,28 @@ export default class Autocomplete extends React.Component {
3350
};
3451

3552
this.props.pinTo.forEach(direction => {
36-
console.log(`${direction} = ${position[direction]}`);
3753
style[direction] = position[direction];
3854
});
3955

40-
const renderedCompletions = this.state.completions.map((completion, i) => {
41-
return (
42-
<div key={i} class="mx_Autocomplete_Completion">
43-
<strong>{completion.title}</strong>
44-
<em>{completion.subtitle}</em>
45-
<span style={{color: 'gray', float: 'right'}}>{completion.description}</span>
56+
const renderedCompletions = this.state.completions.map((completionResult, i) => {
57+
console.log(completionResult);
58+
let completions = completionResult.completions.map((completion, i) => {
59+
return (
60+
<div key={i} class="mx_Autocomplete_Completion">
61+
<strong>{completion.title}</strong>
62+
<em>{completion.subtitle}</em>
63+
<span style={{color: 'gray', float: 'right'}}>{completion.description}</span>
64+
</div>
65+
);
66+
});
67+
68+
69+
return completions.length > 0 ? (
70+
<div key={i} class="mx_Autocomplete_ProviderSection">
71+
<strong>{completionResult.provider.getName()}</strong>
72+
{completions}
4673
</div>
47-
);
74+
) : null;
4875
});
4976

5077
return (

0 commit comments

Comments
 (0)