editable.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. 'use strict';
  2. const Select = require('./select');
  3. const Form = require('./form');
  4. const form = Form.prototype;
  5. class Editable extends Select {
  6. constructor(options) {
  7. super({ ...options, multiple: true });
  8. this.align = [this.options.align, 'left'].find(v => v != null);
  9. this.emptyError = '';
  10. this.values = {};
  11. }
  12. dispatch(char, key) {
  13. let choice = this.focused;
  14. let parent = choice.parent || {};
  15. if (!choice.editable && !parent.editable) {
  16. if (char === 'a' || char === 'i') return super[char]();
  17. }
  18. return form.dispatch.call(this, char, key);
  19. }
  20. append(char, key) {
  21. return form.append.call(this, char, key);
  22. }
  23. delete(char, key) {
  24. return form.delete.call(this, char, key);
  25. }
  26. space(char) {
  27. return this.focused.editable ? this.append(char) : super.space();
  28. }
  29. number(char) {
  30. return this.focused.editable ? this.append(char) : super.number(char);
  31. }
  32. next() {
  33. return this.focused.editable ? form.next.call(this) : super.next();
  34. }
  35. prev() {
  36. return this.focused.editable ? form.prev.call(this) : super.prev();
  37. }
  38. async indicator(choice, i) {
  39. let symbol = choice.indicator || '';
  40. let value = choice.editable ? symbol : super.indicator(choice, i);
  41. return await this.resolve(value, this.state, choice, i) || '';
  42. }
  43. indent(choice) {
  44. return choice.role === 'heading' ? '' : (choice.editable ? ' ' : ' ');
  45. }
  46. async renderChoice(choice, i) {
  47. choice.indent = '';
  48. if (choice.editable) return form.renderChoice.call(this, choice, i);
  49. return super.renderChoice(choice, i);
  50. }
  51. error() {
  52. return '';
  53. }
  54. footer() {
  55. return this.state.error;
  56. }
  57. async validate() {
  58. let result = true;
  59. for (let choice of this.choices) {
  60. if (typeof choice.validate !== 'function') {
  61. continue;
  62. }
  63. if (choice.role === 'heading') {
  64. continue;
  65. }
  66. let val = choice.parent ? this.value[choice.parent.name] : this.value;
  67. if (choice.editable) {
  68. val = choice.value === choice.name ? choice.initial || '' : choice.value;
  69. } else if (!this.isDisabled(choice)) {
  70. val = choice.enabled === true;
  71. }
  72. result = await choice.validate(val, this.state);
  73. if (result !== true) {
  74. break;
  75. }
  76. }
  77. if (result !== true) {
  78. this.state.error = typeof result === 'string' ? result : 'Invalid Input';
  79. }
  80. return result;
  81. }
  82. submit() {
  83. if (this.focused.newChoice === true) return super.submit();
  84. if (this.choices.some(ch => ch.newChoice)) {
  85. return this.alert();
  86. }
  87. this.value = {};
  88. for (let choice of this.choices) {
  89. let val = choice.parent ? this.value[choice.parent.name] : this.value;
  90. if (choice.role === 'heading') {
  91. this.value[choice.name] = {};
  92. continue;
  93. }
  94. if (choice.editable) {
  95. val[choice.name] = choice.value === choice.name
  96. ? (choice.initial || '')
  97. : choice.value;
  98. } else if (!this.isDisabled(choice)) {
  99. val[choice.name] = choice.enabled === true;
  100. }
  101. }
  102. return this.base.submit.call(this);
  103. }
  104. }
  105. module.exports = Editable;