You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.3 KiB
163 lines
4.3 KiB
'use strict'; |
|
|
|
const ArrayPrompt = require('../types/array'); |
|
|
|
class Survey extends ArrayPrompt { |
|
constructor(options = {}) { |
|
super(options); |
|
this.emptyError = options.emptyError || 'No items were selected'; |
|
this.term = process.env.TERM_PROGRAM; |
|
|
|
if (!this.options.header) { |
|
let header = ['', '4 - Strongly Agree', '3 - Agree', '2 - Neutral', '1 - Disagree', '0 - Strongly Disagree', '']; |
|
header = header.map(ele => this.styles.muted(ele)); |
|
this.state.header = header.join('\n '); |
|
} |
|
} |
|
|
|
async toChoices(...args) { |
|
if (this.createdScales) return false; |
|
this.createdScales = true; |
|
let choices = await super.toChoices(...args); |
|
for (let choice of choices) { |
|
choice.scale = createScale(5, this.options); |
|
choice.scaleIdx = 2; |
|
} |
|
return choices; |
|
} |
|
|
|
dispatch() { |
|
this.alert(); |
|
} |
|
|
|
space() { |
|
let choice = this.focused; |
|
let ele = choice.scale[choice.scaleIdx]; |
|
let selected = ele.selected; |
|
choice.scale.forEach(e => (e.selected = false)); |
|
ele.selected = !selected; |
|
return this.render(); |
|
} |
|
|
|
indicator() { |
|
return ''; |
|
} |
|
|
|
pointer() { |
|
return ''; |
|
} |
|
|
|
separator() { |
|
return this.styles.muted(this.symbols.ellipsis); |
|
} |
|
|
|
right() { |
|
let choice = this.focused; |
|
if (choice.scaleIdx >= choice.scale.length - 1) return this.alert(); |
|
choice.scaleIdx++; |
|
return this.render(); |
|
} |
|
|
|
left() { |
|
let choice = this.focused; |
|
if (choice.scaleIdx <= 0) return this.alert(); |
|
choice.scaleIdx--; |
|
return this.render(); |
|
} |
|
|
|
indent() { |
|
return ' '; |
|
} |
|
|
|
async renderChoice(item, i) { |
|
await this.onChoice(item, i); |
|
let focused = this.index === i; |
|
let isHyper = this.term === 'Hyper'; |
|
let n = !isHyper ? 8 : 9; |
|
let s = !isHyper ? ' ' : ''; |
|
let ln = this.symbols.line.repeat(n); |
|
let sp = ' '.repeat(n + (isHyper ? 0 : 1)); |
|
let dot = enabled => (enabled ? this.styles.success('◉') : '◯') + s; |
|
|
|
let num = i + 1 + '.'; |
|
let color = focused ? this.styles.heading : this.styles.noop; |
|
let msg = await this.resolve(item.message, this.state, item, i); |
|
let indent = this.indent(item); |
|
let scale = indent + item.scale.map((e, i) => dot(i === item.scaleIdx)).join(ln); |
|
let val = i => i === item.scaleIdx ? color(i) : i; |
|
let next = indent + item.scale.map((e, i) => val(i)).join(sp); |
|
|
|
let line = () => [num, msg].filter(Boolean).join(' '); |
|
let lines = () => [line(), scale, next, ' '].filter(Boolean).join('\n'); |
|
|
|
if (focused) { |
|
scale = this.styles.cyan(scale); |
|
next = this.styles.cyan(next); |
|
} |
|
|
|
return lines(); |
|
} |
|
|
|
async renderChoices() { |
|
if (this.state.submitted) return ''; |
|
let choices = this.visible.map(async(ch, i) => await this.renderChoice(ch, i)); |
|
let visible = await Promise.all(choices); |
|
if (!visible.length) visible.push(this.styles.danger('No matching choices')); |
|
return visible.join('\n'); |
|
} |
|
|
|
format() { |
|
if (this.state.submitted) { |
|
let values = this.choices.map(ch => this.styles.info(ch.scaleIdx)); |
|
return values.join(', '); |
|
} |
|
return ''; |
|
} |
|
|
|
async render() { |
|
let { submitted, size } = this.state; |
|
|
|
let prefix = await this.prefix(); |
|
let separator = await this.separator(); |
|
let message = await this.message(); |
|
|
|
let prompt = [prefix, message, separator].filter(Boolean).join(' '); |
|
this.state.prompt = prompt; |
|
|
|
let header = await this.header(); |
|
let output = await this.format(); |
|
let help = await this.error() || await this.hint(); |
|
let body = await this.renderChoices(); |
|
let footer = await this.footer(); |
|
|
|
if (output || !help) prompt += ' ' + output; |
|
if (help && !prompt.includes(help)) prompt += ' ' + help; |
|
|
|
if (submitted && !output && !body && this.multiple && this.type !== 'form') { |
|
prompt += this.styles.danger(this.emptyError); |
|
} |
|
|
|
this.clear(size); |
|
this.write([prompt, header, body, footer].filter(Boolean).join('\n')); |
|
this.restore(); |
|
} |
|
|
|
submit() { |
|
this.value = {}; |
|
for (let choice of this.choices) { |
|
this.value[choice.name] = choice.scaleIdx; |
|
} |
|
return this.base.submit.call(this); |
|
} |
|
} |
|
|
|
function createScale(n, options = {}) { |
|
if (Array.isArray(options.scale)) { |
|
return options.scale.map(ele => ({ ...ele })); |
|
} |
|
let scale = []; |
|
for (let i = 1; i < n + 1; i++) scale.push({ i, selected: false }); |
|
return scale; |
|
} |
|
|
|
module.exports = Survey;
|
|
|