Skip to content

Commit

Permalink
added direct selection capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
tmtek committed Nov 6, 2018
1 parent 373ea61 commit fefc893
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 9 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tmtek/convo",
"version": "0.2.21",
"version": "0.2.22",
"description": "A uility for building conversational responses in DialogFlow fufillments",
"main": "index.js",
"scripts": {
Expand Down
9 changes: 9 additions & 0 deletions src/convo-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ class ConvoApp {
.forListPage(data => this._onRespondForList(data));
}

presentSelection(convo, type, item) {
return convo.select(type, item)
.forSelection(data => this.onRespondForSelection(data));
}

onListSelectUI(convo, type, itemName) {
return convo.selectFromListPage(ConvoApp.ensureNumber(itemName.split('_')[1]));
}
Expand Down Expand Up @@ -166,6 +171,10 @@ class ConvoApp {
}

onRespondForListSelection({ convo, type, item }) {
return this.onRespondForSelection({ convo, type, item });
}

onRespondForSelection({ convo, type, item }) {
return convo.speak('Nothing was selected');
}

Expand Down
34 changes: 32 additions & 2 deletions src/convo.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,36 @@ class Convo {
return this;
}

getSelection(type) {
return this.getContext('selection');
}

hasSelection(type) {
return this.getContext('selection') && (!type || this.getContext('selection').type === type);
}

clearSelection() {
let selection = this.getSelection();
if (selection) {
this.setContext('selection', 0, null);
this.setContext(`selected_${selection.type}`, 0, null);
}
}

select(type, item) {
this.setContext('selection', 10, { type, item });
this.setContext(`selected_${type}`, 10, { active: true });
return this;
}

forSelection(func) {
if (this.hasSelection()) {
let { item, type } = this.getSelection();
func({ convo: this, item, type });
}
return this;
}

selectFromList(index = 0){
if (!this.hasList()) {
throw new Error('Can\'t select an item if there\'s no list.');
Expand All @@ -427,7 +457,7 @@ class Convo {
}
listContext.selectedIndex = index;
this.setContext('list', 10, listContext);
this.setContext(`list_select_${listContext.type}`, 10, { active: true });
this.select(listContext.type, listContext.list[listContext.selectedIndex]);
return this;
}

Expand Down Expand Up @@ -458,7 +488,7 @@ class Convo {
let listContext = this.getContext('list');
if (listContext) {
this.getContext('list').selectedIndex = -1;
this.setContext(`list_select_${listContext.type}`, 0, null);
this.clearSelection();
}
return this;
}
Expand Down
31 changes: 26 additions & 5 deletions test/convo-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,27 @@ describe('ConvoApp', () => {
});
});

describe('#presentSelection', () => {
it('Should call onRespondForSelection when selection is presented', (done) => {
class MyApp extends ConvoApp {
onRegisterIntents(){
this.registerIntent('selectThing', (convo, params, option) => Convo.ask(
this.presentSelection(convo, 'thing', { value: 'test' })
));
}
onRespondForSelection({ convo, type, item }) {
assert(convo);
assert(type === 'thing');
assert(item);
assert(item.value === 'test');
done();
}

}
new MyApp().intent(new Convo(), 'selectThing');
});
});

describe('#registerListIntents', () => {
it('Should be able to repeat the list with list_repeat', (done) => {
let list = ['test 1', 'test 2', 'test 3', 'test 4', 'test 5'];
Expand Down Expand Up @@ -608,7 +629,7 @@ describe('ConvoApp', () => {
listLength: list.length
}));
}
onRespondForListSelection({ convo, type, item }) {
onRespondForSelection({ convo, type, item }) {
return convo.speak(JSON.stringify({
type,
item
Expand Down Expand Up @@ -645,7 +666,7 @@ describe('ConvoApp', () => {
listLength: list.length
}));
}
onRespondForListSelection({ convo, type, item }) {
onRespondForSelection({ convo, type, item }) {
return convo.speak(JSON.stringify({
type,
item
Expand Down Expand Up @@ -682,7 +703,7 @@ describe('ConvoApp', () => {
listLength: list.length
}));
}
onRespondForListSelection({ convo, type, item }) {
onRespondForSelection({ convo, type, item }) {
return convo.speak(JSON.stringify({
type,
item
Expand Down Expand Up @@ -719,7 +740,7 @@ describe('ConvoApp', () => {
listLength: list.length
}));
}
onRespondForListSelection({ convo, type, item }) {
onRespondForSelection({ convo, type, item }) {
return convo.speak(JSON.stringify({
type,
item
Expand Down Expand Up @@ -788,7 +809,7 @@ describe('ConvoApp', () => {
listLength: list.length
}));
}
onRespondForListSelection({ convo, type, item }) {
onRespondForSelection({ convo, type, item }) {
return convo.speak(JSON.stringify({
type,
item
Expand Down
60 changes: 60 additions & 0 deletions test/convo.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,43 @@ describe('Convo', () => {
});
});

describe('#select', () => {
it('Should select an item and report back on it.', () => {
let convo = new Convo().select('thing', { value: 'the thing' });
assert(convo.hasSelection());
assert(convo.hasSelection('thing'));
assert(convo.getSelection().item.value === 'the thing');
});
it('Should respond back negatively when there is no selection.', () => {
let convo = new Convo();
assert(!convo.hasSelection());
assert(!convo.hasSelection('thing'));
assert(convo.getSelection() === null);
});
it('Should be able to discriminate on types.', () => {
let convo = new Convo().select('thing', { value: 'the thing' });
assert(convo.hasSelection());
assert(!convo.hasSelection('thing2'));
});
it('Should be able to clear selection.', () => {
let convo = new Convo().select('thing', { value: 'the thing' });
assert(convo.hasSelection());
assert(convo.hasSelection('thing'));
assert(convo.getSelection().item.value === 'the thing');
convo.clearSelection();
assert(!convo.hasSelection());
assert(!convo.hasSelection('thing'));
assert(convo.getSelection() === null);
});
it('Should be to present selection.', () => {
let convo = new Convo().select('thing', { value: 'the thing' });
convo.forSelection(({ type, item }) => {
assert(type === 'thing');
assert(item.value === 'the thing');
});
});
});

describe('#setList', () => {
it('Should throw an error if a type or a list is not passed.', () => {
assert.throws(() => new Convo().setList());
Expand Down Expand Up @@ -1157,6 +1194,29 @@ describe('Convo', () => {
`there should not be a selection.${JSON.stringify(convo.getListSelection(), null, 2)}`
);
});
it('Should have list selection and selection match when selection is from list.', () => {
let convo = new Convo()
.setList('items', ['item 1', 'item 2', 'item 3'])
.selectFromList(0);
assert(
convo.getListSelection().item === convo.getSelection().item,
`there should not be a selection.${JSON.stringify(convo.getListSelection(), null, 2)}`
);
});
it('Should not have list selection and selection match when selection is not from list.', () => {
let convo = new Convo()
.setList('items', ['item 1', 'item 2', 'item 3'])
.selectFromList(0)
.select('thing', 'item 4');
assert(convo.getListSelection().item !== convo.getSelection().item);
});
it('Should have list section override a direct selection.', () => {
let convo = new Convo()
.setList('items', ['item 1', 'item 2', 'item 3'])
.select('thing', 'item 4')
.selectFromList(0);
assert(convo.getListSelection().item === convo.getSelection().item);
});
});

describe('#forListSelection', () => {
Expand Down

0 comments on commit fefc893

Please sign in to comment.