toggle.js

  1. import { Component } from "./component.js";
  2. import { Label } from "./label.js";
  3. import { Style } from "./style.js";
  4. /**
  5. * Creates a clickable toggle that can be switched off and on.
  6. * <div><img src="https://www.minicomps.org/images/toggle.png"/></div>
  7. * @example
  8. * const panel = new Panel(document.body, 20, 20, 200, 200);
  9. * new Toggle(panel, 20, 20, "Toggle", false, event => console.log(event.target.toggled));
  10. * @extends Component
  11. */
  12. export class Toggle extends Component {
  13. /**
  14. * Constructor
  15. * @param {HTMLElement} parent - The element to add this toggle to.
  16. * @param {number} x - The x position of the toggle. Default 0.
  17. * @param {number} y - The y position of the toggle. Default 0.
  18. * @param {string} label - The text for the toggle's label. Default empty string.
  19. * @param {boolean} toggled - The initial toggled state of the toggle. Default false.
  20. * @param {function} defaultHandler - A function that will handle the "click" event.
  21. */
  22. constructor(parent, x, y, label, toggled, defaultHandler) {
  23. super(parent, x, y);
  24. this._label = label;
  25. this._labelPosition = Toggle.labelPosition;
  26. this._onLabel = Toggle.onLabel;
  27. this._offLabel = Toggle.offLabel;
  28. this._createChildren();
  29. this._createStyle();
  30. this._createListeners();
  31. this.setShowStateLabels(Toggle.showStateLabels);
  32. this.setSize(Toggle.width, Toggle.height);
  33. this.setToggled(toggled || false);
  34. this._updateLabel();
  35. this.addEventListener("click", defaultHandler);
  36. this._addToParent();
  37. }
  38. //////////////////////////////////
  39. // Core
  40. //////////////////////////////////
  41. _createChildren() {
  42. this._setWrapperClass("MinimalToggle");
  43. this._wrapper.tabIndex = 0;
  44. this._textLabel = new Label(this._wrapper, 0, -15, this._label);
  45. this._stateLabel = new Label(this._wrapper, 5, 0, this._onLabel)
  46. .setAutosize(false);
  47. this._handle = this._createDiv(this._wrapper, "MinimalToggleHandle");
  48. }
  49. _createStyle() {
  50. const style = document.createElement("style");
  51. style.textContent = Style.toggle;
  52. this.shadowRoot.append(style);
  53. }
  54. _createListeners() {
  55. this._onClick = this._onClick.bind(this);
  56. this._onKeyPress = this._onKeyPress.bind(this);
  57. this._wrapper.addEventListener("click", this._onClick);
  58. this._wrapper.addEventListener("keypress", this._onKeyPress);
  59. }
  60. //////////////////////////////////
  61. // Handlers
  62. //////////////////////////////////
  63. _onClick(event) {
  64. event.stopPropagation();
  65. if (this._enabled) {
  66. this.toggle();
  67. this.dispatchEvent(new CustomEvent("click", { detail: this._toggled }));
  68. }
  69. }
  70. _onKeyPress(event) {
  71. if (event.keyCode === 13 && this._enabled) {
  72. this._wrapper.click();
  73. }
  74. }
  75. //////////////////////////////////
  76. // Private
  77. //////////////////////////////////
  78. _updateLabel() {
  79. if (this._labelPosition === "left") {
  80. this._textLabel.x = -this._textLabel.width - 5;
  81. this._textLabel.y = (this._height - this._textLabel.height) / 2;
  82. } else if (this._labelPosition === "top") {
  83. this._textLabel.x = 0;
  84. this._textLabel.y = -this._textLabel.height - 5;
  85. } else if (this._labelPosition === "right") {
  86. this._textLabel.x = this._width + 5;
  87. this._textLabel.y = (this._height - this._textLabel.height) / 2;
  88. } else {
  89. this._textLabel.x = 0;
  90. this._textLabel.y = this._height + 5;
  91. }
  92. }
  93. _updateToggle() {
  94. this._stateLabel.align = "center";
  95. this._stateLabel.width = this._width / 2;
  96. if (this._toggled) {
  97. this._stateLabel.x = 0;
  98. this._stateLabel.text = this._onLabel;
  99. this._handle.style.left = "50%";
  100. } else {
  101. this._stateLabel.x = this._width / 2;
  102. this._stateLabel.text = this._offLabel;
  103. this._handle.style.left = 0;
  104. }
  105. }
  106. //////////////////////////////////
  107. // Public
  108. //////////////////////////////////
  109. /**
  110. * Adds a handler function for the "click" event on this toggle.
  111. * @param {function} handler - A function that will handle the "click" event.
  112. * @returns This instance, suitable for chaining.
  113. */
  114. addHandler(handler) {
  115. this.addEventListener("click", handler);
  116. return this;
  117. }
  118. /**
  119. * Automatically changes the value of a property on a target object with the main value of this component changes.
  120. * @param {object} target - The target object to change.
  121. * @param {string} prop - The string name of a property on the target object.
  122. * @return This instance, suitable for chaining.
  123. */
  124. bind(target, prop) {
  125. this.addEventListener("click", event => {
  126. target[prop] = event.detail;
  127. });
  128. return this;
  129. }
  130. /**
  131. * @returns the current text of the label.
  132. */
  133. getLabel() {
  134. return this._label;
  135. }
  136. /**
  137. * @returns the position of the text label (left, right, top or bottom);
  138. */
  139. getLabelPosition() {
  140. return this._labelPosition;
  141. }
  142. /**
  143. * @returns the value of the state label when the toggle is toggled off.
  144. */
  145. getOffLabel() {
  146. return this._offLabel;
  147. }
  148. /**
  149. * @returns the value of the state label when the toggle is toggled on.
  150. */
  151. getOnLabel() {
  152. return this._onLabel;
  153. }
  154. /**
  155. * @returns whether or not the state labels will be shown.
  156. */
  157. getShowStateLabels() {
  158. return this._showStateLabels;
  159. }
  160. /**
  161. * @returns whether or not this toggle is toggled on.
  162. */
  163. getToggled() {
  164. return this._toggled;
  165. }
  166. setEnabled(enabled) {
  167. if (this._enabled === enabled) {
  168. return this;
  169. }
  170. super.setEnabled(enabled);
  171. this._textLabel.enable = enabled;
  172. if (this._enabled) {
  173. this._setWrapperClass("MinimalToggle");
  174. this._wrapper.tabIndex = 0;
  175. } else {
  176. this._setWrapperClass("MinimalToggleDisabled");
  177. this._wrapper.tabIndex = -1;
  178. }
  179. return this;
  180. }
  181. setHeight(height) {
  182. super.setHeight(height);
  183. this._stateLabel.height = height;
  184. return this;
  185. }
  186. /**
  187. * Sets the label of this toggle.
  188. * @param {string} label - The label to set on this toggle.
  189. * @returns this instance, suitable for chaining.
  190. */
  191. setLabel(label) {
  192. this._label = label;
  193. this._textLabel.text = label;
  194. this._updateLabel();
  195. return this;
  196. }
  197. /**
  198. * Sets the label position of the text label.
  199. * @param {string} position - The position to place the text lable: "top" (default), "left", "right" or "bottom".
  200. * @returns this instance, suitable for chaining.
  201. */
  202. setLabelPosition(position) {
  203. this._labelPosition = position;
  204. this._updateLabel();
  205. return this;
  206. }
  207. /**
  208. * Sets the value of the state label when the toggle is toggled off.
  209. * @param {string} label - the text of the label.
  210. * @returns This instance.
  211. */
  212. setOffLabel(label) {
  213. this._offLabel = label;
  214. if (!this._toggled) {
  215. this._stateLabel.text = label;
  216. }
  217. return this;
  218. }
  219. /**
  220. * Sets the value of the state label when the toggle is toggled on.
  221. * @param {string} label - the text of the label.
  222. * @returns This instance.
  223. */
  224. setOnLabel(label) {
  225. this._onLabel = label;
  226. if (this._toggled) {
  227. this._stateLabel.text = label;
  228. }
  229. return this;
  230. }
  231. /**
  232. * Sets whether or not the toggle will display state labels showing its on/off state.
  233. * @param {boolean} show - Whether or not to show the state labels.
  234. * @returns This instance.
  235. */
  236. setShowStateLabels(show) {
  237. this._showStateLabels = show;
  238. if (show) {
  239. this._stateLabel.style.visibility = "visible";
  240. } else {
  241. this._stateLabel.style.visibility = "hidden";
  242. }
  243. return this;
  244. }
  245. /**
  246. * Sets whether or not this toggle will be toggled (on).
  247. * @params {boolean} toggle - Whether this toggle will be toggled on or off.
  248. * @returns This instance, suitable for chaining.
  249. */
  250. setToggled(toggled) {
  251. this._toggled = toggled;
  252. this._updateToggle();
  253. return this;
  254. }
  255. setWidth(width) {
  256. super.setWidth(width);
  257. this._stateLabel.width = width - 10;
  258. return this;
  259. }
  260. /**
  261. * Toggles the state of the toggle between toggled and not toggled.
  262. * @returns This instance, suitable for chaining.
  263. */
  264. toggle() {
  265. this.setToggled(!this._toggled);
  266. return this;
  267. }
  268. //////////////////////////////////
  269. // Getters/Setters
  270. // alphabetical. getter first.
  271. //////////////////////////////////
  272. /**
  273. * Gets and sets the text of the toggle's text label.
  274. */
  275. get label() {
  276. return this.getLabel();
  277. }
  278. set label(label) {
  279. this.setLabel(label);
  280. }
  281. /**
  282. * Gets and sets the position of the text label displayed on the toggle. Valid values are "top" (default), "left" and "bottom".
  283. */
  284. get labelPosition() {
  285. return this.getLabelPosition();
  286. }
  287. set labelPosition(pos) {
  288. this.setLabelPosition(pos);
  289. }
  290. /**
  291. * Gets and sets the text of the state label in the off position.
  292. */
  293. get offLabel() {
  294. return this.getOffLabel();
  295. }
  296. set offLabel(label) {
  297. this.setOffLabel(label);
  298. }
  299. /**
  300. * Gets and sets the text of the state label in the on position.
  301. */
  302. get onLabel() {
  303. return this.getOnLabel();
  304. }
  305. set onLabel(label) {
  306. this.setOnLabel(label);
  307. }
  308. /**
  309. * Gets and sets whether or not the state labels will be shown.
  310. */
  311. get showStateLabels() {
  312. return this.getShowStateLabels();
  313. }
  314. set showStateLabels(show) {
  315. this.setShowStateLabels(show);
  316. }
  317. /**
  318. * Sets and gets the toggled state of the toggle.
  319. */
  320. get toggled() {
  321. return this.getToggled();
  322. }
  323. set toggled(toggled) {
  324. this.setToggled(toggled);
  325. }
  326. }
  327. //////////////////////////////////
  328. // DEFAULTS
  329. //////////////////////////////////
  330. /**
  331. * Default labelPosition value for all Toggles.
  332. */
  333. Toggle.labelPosition = "top";
  334. /**
  335. * Default showStateLabels value for all Toggles.
  336. */
  337. Toggle.showStateLabels = true;
  338. /**
  339. * Default onLabel value for all Toggles.
  340. */
  341. Toggle.onLabel = "On";
  342. /**
  343. * Default offLabel value for all Toggles.
  344. */
  345. Toggle.offLabel = "Off";
  346. /**
  347. * Default width for all Toggles.
  348. */
  349. Toggle.width = 50;
  350. /**
  351. * Default height for all Toggles.
  352. */
  353. Toggle.height = 20;
  354. customElements.define("minimal-toggle", Toggle);
  355. JAVASCRIPT
    Copied!