/node_modules/bower/node_modules/inquirer/lib/objects/choices.js

https://gitlab.com/jorgegoes/jointswp-child · JavaScript · 173 lines · 84 code · 39 blank · 50 comment · 7 complexity · 8b5b96ec744cd45a7c480bfafa36bbd2 MD5 · raw file

  1. /**
  2. * Choices object
  3. * Collection of multiple `choice` object
  4. */
  5. var _ = require("lodash");
  6. var clc = require("cli-color");
  7. var Separator = require("./separator");
  8. var Choice = require("./choice");
  9. /**
  10. * Module exports
  11. */
  12. module.exports = Choices;
  13. /**
  14. * Choices collection
  15. * @constructor
  16. * @param {Array} choices All `choice` to keep in the collection
  17. */
  18. function Choices( choices ) {
  19. this.choices = _.map( choices, function( val ) {
  20. if ( val instanceof Separator ) {
  21. return val;
  22. }
  23. return new Choice( val );
  24. });
  25. this.realChoices = this.choices.filter(Separator.exclude);
  26. Object.defineProperty( this, "length", {
  27. get: function() {
  28. return this.choices.length;
  29. },
  30. set: function( val ) {
  31. this.choices.length = val;
  32. }
  33. });
  34. Object.defineProperty( this, "realLength", {
  35. get: function() {
  36. return this.realChoices.length;
  37. },
  38. set: function() {
  39. throw new Error("Cannot set `realLength` of a Choices collection");
  40. }
  41. });
  42. // Set pagination state
  43. this.pointer = 0;
  44. this.lastIndex = 0;
  45. }
  46. /**
  47. * Get a valid choice from the collection
  48. * @param {Number} selector The selected choice index
  49. * @return {Choice|Undefined} Return the matched choice or undefined
  50. */
  51. Choices.prototype.getChoice = function( selector ) {
  52. if ( _.isNumber(selector) ) {
  53. return this.realChoices[ selector ];
  54. }
  55. return undefined;
  56. };
  57. /**
  58. * Get a raw element from the collection
  59. * @param {Number} selector The selected index value
  60. * @return {Choice|Undefined} Return the matched choice or undefined
  61. */
  62. Choices.prototype.get = function( selector ) {
  63. if ( _.isNumber(selector) ) {
  64. return this.choices[ selector ];
  65. }
  66. return undefined;
  67. };
  68. /**
  69. * Match the valid choices against a where clause
  70. * @param {Object} whereClause Lodash `where` clause
  71. * @return {Array} Matching choices or empty array
  72. */
  73. Choices.prototype.where = function( whereClause ) {
  74. return _.where( this.realChoices, whereClause );
  75. };
  76. /**
  77. * Pluck a particular key from the choices
  78. * @param {String} propertyName Property name to select
  79. * @return {Array} Selected properties
  80. */
  81. Choices.prototype.pluck = function( propertyName ) {
  82. return _.pluck( this.realChoices, propertyName );
  83. };
  84. // Propagate usual Array methods
  85. Choices.prototype.forEach = function() {
  86. return this.choices.forEach.apply( this.choices, arguments );
  87. };
  88. Choices.prototype.filter = function() {
  89. return this.choices.filter.apply( this.choices, arguments );
  90. };
  91. Choices.prototype.push = function() {
  92. var objs = _.map( arguments, function( val ) { return new Choice( val ); });
  93. this.choices.push.apply( this.choices, objs );
  94. this.realChoices = this.choices.filter(Separator.exclude);
  95. return this.choices;
  96. };
  97. /**
  98. * Render the choices as formatted string
  99. * @return {String} formatted content
  100. */
  101. Choices.prototype.render = function() {
  102. return this.renderingMethod.apply( this, arguments );
  103. };
  104. /**
  105. * Set the rendering method
  106. * @param {Function} render Function to be use when rendering
  107. */
  108. Choices.prototype.setRender = function( render ) {
  109. this.renderingMethod = (this.choices.length > 9) ? this.paginateOutput(render) : render;
  110. };
  111. /**
  112. * Paginate the output of a render function
  113. * @param {Function} render Render function whose content must be paginated
  114. * @return {Function} Wrapped render function
  115. */
  116. Choices.prototype.paginateOutput = function( render ) {
  117. var pageSize = 7;
  118. return function( active ) {
  119. var output = render.apply( this, arguments );
  120. var lines = output.split("\n");
  121. // Make sure there's enough line to paginate
  122. if ( lines.length <= pageSize ) return output;
  123. // Move the pointer only when the user go down and limit it to 3
  124. if ( this.pointer < 3 && this.lastIndex < active && active - this.lastIndex < 9 ) {
  125. this.pointer = Math.min( 3, this.pointer + active - this.lastIndex);
  126. }
  127. this.lastIndex = active;
  128. // Duplicate the lines so it give an infinite list look
  129. var infinite = _.flatten([ lines, lines, lines ]);
  130. var topIndex = Math.max( 0, active + lines.length - this.pointer );
  131. var section = infinite.splice( topIndex, pageSize ).join("\n");
  132. return section + "\n" + clc.blackBright("(Move up and down to reveal more choices)");
  133. }.bind(this);
  134. };