Skip to content
Permalink
Browse files

initial version of autocomplete

  • Loading branch information
aviraldg committed Jun 1, 2016
1 parent a145ab7 commit b979a16199fe1a14474dd7d3b9e32ba0eaffd03f
@@ -26,6 +26,7 @@
"favico.js": "^0.3.10",
"filesize": "^3.1.2",
"flux": "^2.0.3",
"fuse.js": "^2.2.0",
"glob": "^5.0.14",
"highlight.js": "^8.9.1",
"linkifyjs": "^2.0.0-beta.4",
@@ -0,0 +1,3 @@
export default class AutocompleteProvider {

}
@@ -0,0 +1,7 @@
import CommandProvider from './CommandProvider';

const COMPLETERS = [CommandProvider].map(completer => new completer());

export function getCompletions(query: String) {
return COMPLETERS.map(completer => completer.getCompletions(query));
}
@@ -0,0 +1,65 @@
import AutocompleteProvider from './AutocompleteProvider';
import Q from 'q';
import Fuse from 'fuse.js';

const COMMANDS = [
{
command: '/me',
args: '<message>',
description: 'Displays action'
},
{
command: '/ban',
args: '<user-id> [reason]',
description: 'Bans user with given id'
},
{
command: '/deop'
},
{
command: '/encrypt'
},
{
command: '/invite'
},
{
command: '/join',
args: '<room-alias>',
description: 'Joins room with given alias'
},
{
command: '/kick',
args: '<user-id> [reason]',
description: 'Kicks user with given id'
},
{
command: '/nick',
args: '<display-name>',
description: 'Changes your display nickname'
}
];

export default class CommandProvider extends AutocompleteProvider {
constructor() {
super();
this.fuse = new Fuse(COMMANDS, {
keys: ['command', 'args', 'description']
});
}

getCompletions(query: String) {
let completions = [];
const matches = query.match(/(^\/\w+)/);
if(!!matches) {
const command = matches[0];
completions = this.fuse.search(command).map(result => {
return {
title: result.command,
subtitle: result.args,
description: result.description
};
});
}
return Q.when(completions);
}
}
@@ -0,0 +1,67 @@
import React from 'react';

import {getCompletions} from '../../../autocomplete/Autocompleter';

export default class Autocomplete extends React.Component {
constructor(props) {
super(props);
this.state = {
completions: []
};
}

componentWillReceiveProps(props, state) {
getCompletions(props.query)[0].then(completions => {
console.log(completions);
this.setState({
completions
});
});
}

render() {
const pinElement = document.querySelector(this.props.pinSelector);
if(!pinElement) return null;

const position = pinElement.getBoundingClientRect();

const style = {
position: 'fixed',
border: '1px solid gray',
background: 'white',
borderRadius: '4px'
};

this.props.pinTo.forEach(direction => {
console.log(`${direction} = ${position[direction]}`);
style[direction] = position[direction];
});

const renderedCompletions = this.state.completions.map((completion, i) => {
return (
<div key={i} class="mx_Autocomplete_Completion">
<strong>{completion.title}</strong>
<em>{completion.subtitle}</em>
<span style={{color: 'gray', float: 'right'}}>{completion.description}</span>
</div>
);
});

return (
<div className="mx_Autocomplete" style={style}>
{renderedCompletions}
</div>
);
}
}

Autocomplete.propTypes = {
// the query string for which to show autocomplete suggestions
query: React.PropTypes.string.isRequired,

// CSS selector indicating which element to pin the autocomplete to
pinSelector: React.PropTypes.string.isRequired,

// attributes on which the autocomplete should match the pinElement
pinTo: React.PropTypes.array.isRequired
};
@@ -20,6 +20,7 @@ var MatrixClientPeg = require('../../../MatrixClientPeg');
var Modal = require('../../../Modal');
var sdk = require('../../../index');
var dis = require('../../../dispatcher');
import Autocomplete from './Autocomplete';


module.exports = React.createClass({
@@ -45,6 +46,12 @@ module.exports = React.createClass({
opacity: React.PropTypes.number,
},

getInitialState: function () {
return {
autocompleteQuery: ''
};
},

onUploadClick: function(ev) {
this.refs.uploadInput.click();
},
@@ -117,6 +124,12 @@ module.exports = React.createClass({
});
},

onInputContentChanged(content: String) {
this.setState({
autocompleteQuery: content
})
},

render: function() {
var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
var uploadInputStyle = {display: 'none'};
@@ -170,7 +183,8 @@ module.exports = React.createClass({

controls.push(
<MessageComposerInput key="controls_input" tabComplete={this.props.tabComplete}
onResize={this.props.onResize} room={this.props.room} />,
onResize={this.props.onResize} room={this.props.room}
onContentChanged={(content) => this.onInputContentChanged(content) } />,
uploadButton,
hangupButton,
callButton,
@@ -191,6 +205,8 @@ module.exports = React.createClass({
{controls}
</div>
</div>

<Autocomplete query={this.state.autocompleteQuery} pinSelector=".mx_RoomView_statusArea" pinTo={['top', 'left', 'width']} />
</div>
);
}
@@ -73,6 +73,8 @@ module.exports = React.createClass({

// js-sdk Room object
room: React.PropTypes.object.isRequired,

onContentChanged: React.PropTypes.func
},

componentWillMount: function() {
@@ -276,6 +278,8 @@ module.exports = React.createClass({
{
this.resizeInput();
}

this.props.onContentChanged && this.props.onContentChanged(this.refs.textarea.value);
},

onEnter: function(ev) {

0 comments on commit b979a16

Please sign in to comment.
You can’t perform that action at this time.