summaryrefslogtreecommitdiffstats
path: root/toolkit/components/reader/moz-slider.mjs
blob: 057738f2ccf8b57d2b4759e9edda6542b617b55e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { html } from "chrome://global/content/vendor/lit.all.mjs";
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";

/**
 * A range slider component that can be used to select a value.
 *
 * @tagname moz-slider
 * @property {number} min - The minimum value of the slider.
 * @property {number} max - The maximum value of the slider.
 * @property {number} value - The initial value of the slider.
 * @property {number} ticks - The number of tick marks to display under the slider.
 * @property {Array<string>} tickLabels - A list containing the tick label strings.
 * @property {string} label - The label text for the slider.
 * @property {string} sliderIcon  - The url of the slider icon.
 */

export default class MozSlider extends MozLitElement {
  static properties = {
    min: { type: Number },
    max: { type: Number },
    value: { type: Number },
    ticks: { type: Number },
    tickLabels: { type: Array, attribute: "tick-labels" },
    label: { type: String },
    sliderIcon: { type: String, attribute: "slider-icon" },
  };

  static get queries() {
    return {
      tickMarks: "datalist",
      sliderTrack: "#inputSlider",
    };
  }

  constructor() {
    super();
    this.ticks = 0;
    this.tickLabels = [];
    this.sliderIcon = "";
  }

  getStepSize() {
    const stepSize = (this.max - this.min) / (this.ticks - 1);
    return stepSize;
  }

  setupIcon() {
    if (this.sliderIcon) {
      return html`<div class="icon-container">
        <img class="icon" role="presentation" src=${this.sliderIcon} />
      </div> `;
    }
    return "";
  }

  ticksTemplate() {
    if (this.ticks > 0) {
      let tickList = [];
      let value = this.min;
      let stepSize = this.getStepSize();
      for (let i = 0; i < this.ticks; i++) {
        let optionId = "";
        let label = "";
        if (this.tickLabels.length) {
          if (i == 0) {
            optionId = "inline-start-label";
            label = this.tickLabels[0];
          } else if (i == this.ticks - 1) {
            optionId = "inline-end-label";
            label = this.tickLabels[1];
          }
        }
        tickList.push(
          html`<option
            id=${optionId}
            value=${parseFloat(value).toFixed(2)}
            label=${label}
          ></option>`
        );
        value += stepSize;
      }
      return html` <datalist id="slider-ticks">${tickList}</datalist> `;
    }
    return "";
  }

  handleChange(event) {
    this.value = event.target.value;
    this.dispatchEvent(
      new CustomEvent("slider-changed", {
        detail: this.value,
      })
    );
  }

  render() {
    return html`
      <link
        rel="stylesheet"
        href="chrome://global/content/reader/moz-slider.css"
      />
      <div class="container">
        ${this.setupIcon()}
        <div class="slider-container">
          <label class="slider-label" for="inputSlider">${this.label}</label>
          <input
            id="inputSlider"
            max=${this.max}
            min=${this.min}
            step=${this.getStepSize()}
            type="range"
            .value=${this.value}
            list="slider-ticks"
            @change=${this.handleChange}
          />
          ${this.ticksTemplate()}
        </div>
      </div>
    `;
  }
}
customElements.define("moz-slider", MozSlider);