widgets/bitstring.js

  1. /*
  2. * This file is part of AUX.
  3. *
  4. * AUX is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 3 of the License, or (at your option) any later version.
  8. *
  9. * AUX is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General
  15. * Public License along with this program; if not, write to the
  16. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301 USA
  18. */
  19. import { addClass } from './../utils/dom.js';
  20. import { Buttons } from './buttons.js';
  21. import { error } from '../utils/log.js';
  22. /**
  23. * The <code>useraction</code> event is emitted when a widget gets modified by user interaction.
  24. * The event is emitted for the option <code>select</code>.
  25. *
  26. * @event Buttons#useraction
  27. * @param {string} name - The name of the option which was changed due to the users action
  28. * @param {mixed} value - The new value of the option
  29. */
  30. /**
  31. * Bitstring is a specialized ({@link Buttons}) widget to display and
  32. * control arrays of bits.
  33. *
  34. * @param {Object} [options={ }] - An object containing initial options.
  35. *
  36. * @property {Function} [options.labels="i => i + 1"] - A function receiving
  37. * the index as argument to format the buttons labels if the buttons
  38. * are set as `options.length` and not as `options.buttons`.
  39. * @property {Function} [options.icons="i => null"] - A function receiving
  40. * the index as argument to format the buttons labels if the buttons
  41. * are set as `options.length` and not as `options.buttons`.
  42. * @property {Number|Boolean} [options.length=false] - The length of the bitstring.
  43. * Use this option to auto-generate the buttons. If you want to have more
  44. * control over the buttons displayed, set them as `options.buttons`
  45. * and set this option to `false`.
  46. *
  47. * @class Bitstring
  48. *
  49. * @extends Buttons
  50. *
  51. */
  52. export class Bitstring extends Buttons {
  53. static get _options() {
  54. return {
  55. labels: 'function',
  56. icons: 'function',
  57. length: 'number|boolean',
  58. bitstring: 'array|number',
  59. };
  60. }
  61. static get options() {
  62. return {
  63. multi_select: 1,
  64. labels: (i) => i + 1,
  65. icons: (i) => null,
  66. length: false,
  67. bitstring: 0,
  68. deselect: true,
  69. };
  70. }
  71. static get static_events() {
  72. return {
  73. set_buttons: function (buttons) {
  74. this.set('bitstring', this.options.bitstring);
  75. },
  76. set_length: function (length) {
  77. if (length !== false) {
  78. const O = this.options;
  79. const B = [];
  80. for (let i = 0, m = length; i < m; ++i) {
  81. B.push({
  82. label: O.labels(i),
  83. icons: O.icons(i),
  84. });
  85. }
  86. this.set('buttons', B);
  87. }
  88. },
  89. set_bitstring: function (bitstring) {
  90. if (typeof bitstring === 'undefined') return;
  91. let select;
  92. if (typeof bitstring === 'number') {
  93. select = this.buttons.list.map((b, i) =>
  94. bitstring & (1 << i) ? i : null
  95. );
  96. } else if (Array.isArray(bitstring)) {
  97. select = this.buttons.list.map((b, i) => (bitstring[i] ? i : null));
  98. } else {
  99. error('Bitstring %O is not of type number or array.', bitstring);
  100. }
  101. if (select) {
  102. select = select.filter((v) => v !== null);
  103. this.set('select', select);
  104. }
  105. },
  106. useraction: function (key, value) {
  107. if (key != 'select') return;
  108. const O = this.options;
  109. if (typeof O.bitstring === 'number') {
  110. let bitstring = 0;
  111. for (let i = 0, m = value.length; i < m; ++i) {
  112. if (value[i] === null) continue;
  113. bitstring |= 1 << value[i];
  114. }
  115. this.userset('bitstring', bitstring);
  116. } else if (Array.isArray(O.bitstring)) {
  117. const bitstring = new Array(this.buttons.list.length).fill(false);
  118. value.map((v, i) => (v === null ? null : (bitstring[v] = true)));
  119. this.userset('bitstring', bitstring);
  120. } else {
  121. error('Bitstring %O is not of type number or array.', O.bitstring);
  122. }
  123. },
  124. };
  125. }
  126. initialize(options) {
  127. super.initialize(options);
  128. /**
  129. * @member {HTMLDivElement} Bitstring#element - The main DIV container.
  130. * Has class <code>.aux-bitstring</code>.
  131. */
  132. }
  133. draw(O, element) {
  134. addClass(element, 'aux-bitstring');
  135. this.set('length', O.length);
  136. this.set('bitstring', O.bitstring);
  137. super.draw(O, element);
  138. }
  139. }