Skip to content

Commit

Permalink
Merge branch 'develop' into release/0.2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
justinvdm committed May 12, 2015
2 parents d5f4d05 + 2bb797d commit 5b8cd8d
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 59 deletions.
76 changes: 52 additions & 24 deletions lib/states/choices.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ var ChoiceState = State.extend(function(self, name, opts) {
/**:ChoiceState.process_choice(choice)
Return ``true`` if the choice has been handled completely or ``false``
if the choice should be propagated to the next state handler.
This allows sub-classes to provide custom processing for special
choices (e.g. forward and back options for navigating through long
choice lists).
:param Choice choice: choice to be processed.
*/
return false;
Expand Down Expand Up @@ -200,7 +200,7 @@ var ChoiceState = State.extend(function(self, name, opts) {
var text = self.error
? self.error.response
: self.question_text;

var choices = self.current_choices();
choices = self.shorten_choices(text, choices);
choices.forEach(function(choice, index) {
Expand Down Expand Up @@ -385,39 +385,67 @@ var PaginatedChoiceState = ChoiceState.extend(function(self, name, opts) {
};

self._page_size = function() {
var n = self.options_per_page;
if (n !== null) return n;
return self.options_per_page !== null
? self.options_per_page
: self._page_size_from(self.metadata.page_start);
};

var chars = self._chars();
n = self.metadata.page_start - 1;
self._prev_page_size = function() {
return self.options_per_page !== null
? self.options_per_page
: self._page_size_to(self.metadata.page_start - 1);
};

self._page_size_to = function(end) {
var start = 0;
var n = 0;
while ((start += n) < end) n = self._page_size_from(start);
return n;
};

self._page_size_from = function(start) {
var n = start - 1;
var chars = self._chars(n);
var page_choices = 1;

while (++n < self.choices.length) {
chars -= self.format_choice(self.choices[n], n).length;
if (chars < 0) break;
chars -= self.format_choice(self.choices[n], page_choices).length;
page_choices++;

if (chars < 0) {
// last page has no 'more' choice, try fit in the last choice
if (self._is_last(n + 1) && chars + self._len_more() >= 0) n++;
break;
}
}

return n - self.metadata.page_start;
return n - start;
};

self._prev_page_size = function() {
var n = self.options_per_page;
if (n !== null) return n;
self._is_last = function(n) {
return n === self.choices.length;
};

var chars = self._chars();
n = self.metadata.page_start;
self._len_more = function() {
return self.format_choice(self.more, self.choices.length).length;
};

while (n-- > 0) {
chars -= self.format_choice(self.choices[n], n).length;
if (chars < 0) break;
}
self._chars = function(n) {
return n === -1
? self._chars_first()
: self._chars_not_first();
};

return self.metadata.page_start - n - 1;
self._chars_first = function() {
// don't count the 'Back' characters for the first page
return self.characters_per_page - [
self.format_choice(self.more, self.choices.length),
self.question_text + '\n']
.join('')
.length;
};

self._chars = function() {
// TODO this needs to be made less naive, it assumes that the last page
// needs space for a 'more' choice and that the first page needs space
// for a 'back' choice
self._chars_not_first = function() {
return self.characters_per_page - [
self.format_choice(self.back, self.choices.length),
self.format_choice(self.more, self.choices.length),
Expand Down
1 change: 1 addition & 0 deletions lib/states/paginated.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ var PaginatedState = State.extend(function(self, name, opts) {
return self.characters_per_page - _.chain(choices)
.values()
.map(self._choice_text)
.concat('') // account for newline between text and choices
.join('\n')
.value()
.length;
Expand Down
168 changes: 135 additions & 33 deletions test/test_states/test_choices.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,101 @@ describe("states.choice", function() {
});
});

describe("to make additional characters available", function() {
it("shouldn't count chars for .back on 1st pp and .more on last pp", function() {
opts.options_per_page = null;
opts.question = 'Select:'; // 8 chars (7 + \n)
opts.more = 'More'; // 8 chars (4 + 3 + \n)
opts.back = 'Back'; // 8 chars (4 + 3 + \n)

// should allow 2 of 8 char choices on mid
// pages, 3 on first & last page
opts.characters_per_page = 24 + 16;

// 8 chars (4 + 3 + \n)
opts.choices = [
new Choice('frut', 'Frut'),
new Choice('barz', 'Barz'),
new Choice('quux', 'Quux'),
new Choice('corg', 'Corg'),
new Choice('gnab', 'Gnab'),
new Choice('igni', 'Igni'),
new Choice('bolg', 'Bolg'),
new Choice('ganz', 'Ganz')
];

return Q()
.then(function() {
return tester
.start()
.check.reply([
"Select:",
"1. Frut",
"2. Barz",
"3. Quux",
"4. More"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4')
.check.reply([
"Select:",
"1. Corg",
"2. Gnab",
"3. More",
"4. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3')
.check.reply([
"Select:",
"1. Igni",
"2. Bolg",
"3. Ganz",
"4. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3', '4')
.check.reply([
"Select:",
"1. Corg",
"2. Gnab",
"3. More",
"4. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3', '4', '4')
.check.reply([
"Select:",
"1. Frut",
"2. Barz",
"3. Quux",
"4. More"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
});
});
});

describe("when the options per page is not fixed", function() {
it("should dynamically split the choices", function() {
opts.question = 'Hello.',
opts.question = 'Hello.';
opts.options_per_page = null;
opts.characters_per_page = 21 + [
"Hello.",
Expand All @@ -463,16 +555,20 @@ describe("states.choice", function() {
.length;

opts.choices = [
new Choice('na', 'Na'),
new Choice('foo', 'Foo'),
new Choice('bar', 'Bar'),
new Choice('baz', 'Baz'),
new Choice('quux', 'Quux'),
new Choice('corge', 'Corge'),
new Choice('grault', 'Grault'),
new Choice('garply', 'Garply'),
new Choice('cge', 'Cge'),
new Choice('g', 'G'),
new Choice('grlt', 'Grlt'),
new Choice('grply', 'Grpy'),
new Choice('waldo', 'Waldo'),
new Choice('fred', 'Fred'),
new Choice('plugh', 'Plugh')
new Choice('plu', 'Plu'),
new Choice('pli', 'Pli'),
new Choice('plo', 'Plo')
];

return Q()
Expand All @@ -481,34 +577,36 @@ describe("states.choice", function() {
.start()
.check.reply([
"Hello.",
"1. Foo",
"2. Bar",
"3. Baz",
"4. More"
"1. Na",
"2. Foo",
"3. Bar",
"4. Baz",
"5. More"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4')
.inputs(null, '5')
.check.reply([
"Hello.",
"1. Quux",
"2. Corge",
"3. More",
"4. Back"
"2. Cge",
"3. G",
"4. More",
"5. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3')
.inputs(null, '5', '4')
.check.reply([
"Hello.",
"1. Grault",
"2. Garply",
"1. Grlt",
"2. Grpy",
"3. More",
"4. Back"
].join('\n'))
Expand All @@ -517,7 +615,7 @@ describe("states.choice", function() {
})
.then(function() {
return tester
.inputs(null, '4', '3', '3')
.inputs(null, '5', '4', '3')
.check.reply([
"Hello.",
"1. Waldo",
Expand All @@ -530,18 +628,20 @@ describe("states.choice", function() {
})
.then(function() {
return tester
.inputs(null, '4', '3', '3', '3')
.inputs(null, '5', '4', '3', '3')
.check.reply([
"Hello.",
"1. Plugh",
"2. Back"
"1. Plu",
"2. Pli",
"3. Plo",
"4. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3', '3', '3', '2')
.inputs(null, '5', '4', '3', '3', '4')
.check.reply([
"Hello.",
"1. Waldo",
Expand All @@ -554,11 +654,11 @@ describe("states.choice", function() {
})
.then(function() {
return tester
.inputs(null, '4', '3', '3', '3', '2', '4')
.inputs(null, '5', '4', '3', '3', '4', '4')
.check.reply([
"Hello.",
"1. Grault",
"2. Garply",
"1. Grlt",
"2. Grpy",
"3. More",
"4. Back"
].join('\n'))
Expand All @@ -567,26 +667,28 @@ describe("states.choice", function() {
})
.then(function() {
return tester
.inputs(null, '4', '3', '3', '3', '2', '4', '4')
.inputs(null, '5', '4', '3', '3', '4', '4', '4')
.check.reply([
"Hello.",
"1. Quux",
"2. Corge",
"3. More",
"4. Back"
"2. Cge",
"3. G",
"4. More",
"5. Back"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
})
.then(function() {
return tester
.inputs(null, '4', '3', '3', '3', '2', '4', '4', '4')
.inputs(null, '5', '4', '3', '3', '4', '4', '4', '5')
.check.reply([
"Hello.",
"1. Foo",
"2. Bar",
"3. Baz",
"4. More"
"1. Na",
"2. Foo",
"3. Bar",
"4. Baz",
"5. More"
].join('\n'))
.check.reply.char_limit(opts.characters_per_page)
.run();
Expand Down

0 comments on commit 5b8cd8d

Please sign in to comment.