• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../BaseElement';
17
18let colorStr: string | null = '';
19let colorText: string | null = '';
20let css = `
21<style>
22      /*
23       * Outer box style
24       */
25      :host{
26          box-sizing:border-box;
27          display:flex;
28
29      }
30      /*
31       * The mouse is missing
32       */
33      :host([disabled]){
34          opacity:0.8;
35          cursor:not-allowed;
36      }
37      /*
38       * Disable sliding
39       */
40      :host([disabled]) input[type="range"]{
41          pointer-events:none;
42      }
43      /*
44       * Currently the entire sliding vessel is controlled
45       */
46      #slider-con{
47          cursor:pointer;
48          display:flex;
49          align-items:center;
50          width:95%;
51          grid-auto-flow: row dense;
52          position: relative;
53      }
54      /*
55       * Display prompt information
56       */
57      :host([showtips]){
58          pointer-events:all;
59      }
60
61      #slider{
62          background-color: var(--dark-background7,#D8D8D8);
63          z-index: 5;
64      }
65
66      /*
67       * Slider basic style
68       */
69      input[type="range"]{
70          pointer-events:all;
71          margin:0 -5px;
72          width: 100%;
73          -webkit-appearance: none;
74          outline : 0;
75          background: rgba(0,0,0,0.1);
76          height: 10px;
77          border-radius:2px;
78          background: -webkit-linear-gradient(right, ${colorStr}, ${colorText}) no-repeat;
79      }
80
81      /*
82       * Slider-line slidedAble area component
83       */
84      input[type="range"]::-webkit-slider-runnable-track{
85          display: flex;
86          align-items: center;
87          position: relative;
88          height: 10px;
89          border-radius:5px;
90      }
91
92       /*
93       * Slider slider component
94       */
95      input[type="range"]::-webkit-slider-thumb{
96          -webkit-appearance: none;
97          position: relative;
98          width:20px;
99          height:20px;
100          margin-top: -4px;
101          border-radius: 5px;
102          background:#999999;
103          transition:0.2s cubic-bezier(.12, .4, .29, 1.46);
104      }
105
106      input[type="range"]:focus{
107          z-index:2;
108      }
109
110      :host(:focus-within) #slider-con,:host(:hover) #slider-con{
111          z-index:10
112      }
113
114      :host([disabled]) #slider{
115          opacity:0.6;
116      }
117      </style>
118`;
119const initHtmlStyle = (str: string | null, text: string | null) => {
120  colorStr = str;
121  colorText = text;
122  return css;
123};
124
125@element('lit-slider')
126export class LitSlider extends BaseElement {
127  private litSliderStyle: LitSliderStyle | undefined | null;
128  private litSlider: HTMLInputElement | undefined | null;
129  private litSliderCon: HTMLDivElement | undefined | null;
130  private litResult: HTMLInputElement | undefined | null;
131  private slotEl: HTMLSlotElement | undefined | null;
132  private currentValue: number = 0;
133  private defaultTimeText: string | undefined | null;
134
135  static get observedAttributes() {
136    return ['percent', 'disabled-X', 'custom-slider', 'custom-line', 'custom-button', 'disabled'];
137  }
138
139  get sliderStyle(): LitSliderStyle {
140    if (this.litSliderStyle) {
141      return this.litSliderStyle;
142    } else {
143      return {
144        minRange: 0,
145        maxRange: 100,
146        defaultValue: '0',
147        resultUnit: '',
148        stepSize: 1,
149        lineColor: 'var(--dark-color3,#46B1E3)',
150        buttonColor: '#999999',
151      };
152    }
153  }
154
155  set disabled(value) {
156    if (value === null || value === false) {
157      this.removeAttribute('disabled');
158    } else {
159      this.setAttribute('disabled', '');
160    }
161  }
162
163  get disabled() {
164    return this.getAttribute('disabled') !== null;
165  }
166
167  set sliderStyle(value: LitSliderStyle) {
168    this.litSliderStyle = value;
169    this.currentValue = Number(value.defaultValue);
170    this.litSliderStyle.defaultValue = value.defaultValue;
171    if (this.litSliderStyle.resultUnit === 'h:m:s') {
172      let timeData = this.litSliderStyle.defaultValue.split(':');
173      let timeSize = Number(timeData[0]) * 3600 + Number(timeData[1]) * 60 + Number(timeData[2]);
174      this.defaultTimeText = timeSize.toString();
175      let defaultSize =
176        ((timeSize - this.litSliderStyle.minRange) * 100) /
177        (this.litSliderStyle.maxRange - this.litSliderStyle.minRange);
178      this.litSlider!.style.backgroundSize = defaultSize + '%';
179    } else {
180      this.defaultTimeText = this.litSliderStyle.defaultValue;
181      this.litSlider!.style.backgroundSize = '0%';
182      if (Number(this.litSliderStyle.defaultValue)) {
183        let defaultSize =
184          ((Number(this.litSliderStyle.defaultValue) - this.litSliderStyle.minRange) /
185            (this.litSliderStyle.maxRange - this.litSliderStyle.minRange)) *
186          100;
187        this.litSlider!.style.backgroundSize = defaultSize + '%';
188      }
189    }
190    let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement;
191    let attribute = htmlInputElement.getAttribute('type');
192    if (attribute === 'range') {
193      htmlInputElement!.setAttribute('value', this.defaultTimeText!);
194      htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString());
195      htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString());
196      htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString());
197    }
198  }
199
200  get disabledX() {
201    return this.getAttribute('disabled-X') || '';
202  }
203
204  set disabledX(value: string) {
205    if (value) {
206      this.setAttribute('disabled-X', '');
207    } else {
208      this.removeAttribute('disabled-X');
209    }
210  }
211
212  get customSlider() {
213    return this.getAttribute('custom-slider') || '';
214  }
215
216  set customSlider(value: string) {
217    if (value) {
218      this.setAttribute('custom-slider', '');
219    } else {
220      this.removeAttribute('custom-slider');
221    }
222  }
223
224  get customLine() {
225    return this.getAttribute('custom-line') || '';
226  }
227
228  set customLine(value: string) {
229    this.setAttribute('custom-line', value);
230  }
231
232  get customButton() {
233    return this.getAttribute('custom-button') || '';
234  }
235
236  set customButton(value: string) {
237    this.setAttribute('custom-button', value);
238  }
239
240  get percent() {
241    return this.getAttribute('percent') || '';
242  }
243
244  set percent(value: string) {
245    this.setAttribute('percent', value);
246    let resultNumber =
247      ((Number(value) - this.sliderStyle!.minRange) * 100) / (this.sliderStyle!.maxRange - this.sliderStyle!.minRange);
248    this.litSlider!.style.backgroundSize = resultNumber + '%';
249  }
250
251  get resultUnit() {
252    return this.getAttribute('resultUnit') || '';
253  }
254
255  set resultUnit(value: string) {
256    this.setAttribute('resultUnit', value);
257  }
258
259  initElements(): void {
260    this.litSlider = this.shadowRoot?.querySelector('#slider') as HTMLInputElement;
261  }
262
263  initHtml(): string {
264    return `
265        ${initHtmlStyle(
266          this.getAttribute('defaultColor') ? this.getAttribute('defaultColor') : '#46B1E3',
267          this.getAttribute('defaultColor') ? this.getAttribute('defaultColor') : '#46B1E3'
268        )}
269        <slot id="slot"></slot>
270        <div id='slider-con' dir="right">
271            <input id="slider" type="range" max="10000000">
272        </div>
273        `;
274  }
275
276  // It is called when the custom element is first inserted into the document DOM.
277  connectedCallback() {
278    this.slotEl = this.shadowRoot?.querySelector('#slot');
279    this.litSliderCon = this.shadowRoot?.querySelector('#slider-con');
280    // Add a slider for input event listeners
281    this.litSlider?.addEventListener('input', this.inputChangeEvent);
282    this.litSlider?.addEventListener('change', this.inputChangeEvent);
283    this.litSlider?.addEventListener('keydown', this.inputKeyDownEvent);
284    this.litSliderStyle = this.sliderStyle;
285  }
286
287  // @ts-ignore
288  inputKeyDownEvent = (ev) => {
289    if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
290      ev.preventDefault();
291    }
292  };
293
294  inputChangeEvent = (event: any) => {
295    if (this.litSlider) {
296      this.currentValue = parseInt(this.litSlider?.value);
297      let resultNumber =
298        ((this.currentValue - this.litSliderStyle!.minRange) * 100) /
299        (this.litSliderStyle!.maxRange - this.litSliderStyle!.minRange);
300      this.percent = Number(resultNumber) + '%';
301      this.litSliderCon?.style.setProperty('percent', this.currentValue + '%');
302      let parentElement = this.parentNode as Element;
303      parentElement.setAttribute('percent', this.currentValue + '');
304      if (this.sliderStyle.resultUnit === 'h:m:s') {
305        this.litSlider!.style.backgroundSize = this.percent;
306      } else {
307        this.litSlider!.style.backgroundSize = this.percent;
308      }
309      this.parentElement!.setAttribute('percent', this.litSlider?.value);
310    }
311  };
312
313  disconnectedCallback() {
314    this.litSlider?.removeEventListener('input', this.inputChangeEvent);
315    this.litSlider?.removeEventListener('change', this.inputChangeEvent);
316    this.litSlider?.removeEventListener('change', this.inputKeyDownEvent);
317  }
318
319  adoptedCallback() {}
320
321  attributeChangedCallback(name: string, oldValue: string, newValue: string) {
322    switch (name) {
323      case 'percent':
324        if (newValue === null || newValue === '0%') {
325          let parentElement = this.parentNode as Element;
326          parentElement?.removeAttribute('percent');
327        } else {
328          let parentElement = this.parentNode as Element;
329        }
330        break;
331      default:
332        break;
333    }
334  }
335
336  formatSeconds(value: string) {
337    let result = parseInt(value);
338    let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600);
339    let minute =
340      Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60);
341    let second = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60);
342    let resultTime = '';
343    if (hours === '00') {
344      resultTime += `00:`;
345    } else {
346      resultTime += `${hours}:`;
347    }
348    if (minute === '00') {
349      resultTime += `00:`;
350    } else {
351      resultTime += `${minute}:`;
352    }
353    resultTime += `${second}`;
354    return resultTime;
355  }
356}
357
358export interface LitSliderStyle {
359  minRange: number;
360  maxRange: number;
361  defaultValue: string;
362  resultUnit: string;
363  stepSize: number;
364  lineColor?: string;
365  buttonColor?: string;
366}
367
368export interface LitSliderLineStyle {
369  lineWith: number;
370  lineHeight: number;
371  border?: string;
372  borderRadiusValue?: number;
373  lineChangeColor?: string;
374}
375
376export interface LitSliderButtonStyle {
377  buttonWith: number;
378  buttonHeight: number;
379  border?: string;
380  borderRadiusValue?: number;
381  buttonChangeColor?: string;
382}
383