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.js"; 17 18@element('lit-slider') 19export class LitSlider extends BaseElement { 20 private litSliderStyle: LitSliderStyle | undefined | null; 21 private litSlider: HTMLInputElement | undefined | null; 22 private litSliderCon: HTMLDivElement | undefined | null; 23 private litResult: HTMLInputElement | undefined | null; 24 private litSliderButton: HTMLDivElement | undefined | null; 25 private slotEl: HTMLSlotElement | undefined | null; 26 private currentValue: number = 0; 27 private sliderLineHeight: string | undefined; 28 private sliderButtonHeight: string | undefined; 29 private sliderButtonWidth: string | undefined; 30 private defaultTimeText: string | undefined | null; 31 32 static get observedAttributes() { 33 return ['percent', 'disabled-X', 'custom-slider', 'custom-line', 'custom-button'] 34 } 35 36 get sliderStyle() { 37 if (this.hasAttribute('custom-slider')) { 38 this.defaultTimeText = "50"; 39 return { 40 minRange: 0, 41 maxRange: 1024, 42 defaultValue: this.defaultTimeText, 43 resultUnit: "MB", 44 stepSize: 2, 45 lineColor: "var(--dark-color3,#46B1E3)", 46 buttonColor: "#999999" 47 } 48 } else { 49 let defaultTime = "00:00:50"; 50 this.defaultTimeText = defaultTime.split(':')[2]; 51 return { 52 minRange: 0, 53 maxRange: 480, 54 defaultValue: defaultTime, 55 resultUnit: "h:m:s", 56 stepSize: 1, 57 lineColor: "var(--dark-color4,#61CFBE)", 58 buttonColor: "#999999" 59 } 60 } 61 62 } 63 64 set sliderStyle(value) { 65 this.litSliderStyle = value; 66 this.litSliderStyle = this.sliderStyle; 67 this.litSliderStyle.defaultValue = value.defaultValue 68 if (this.hasAttribute('custom-slider')) { 69 this.renderCustomSlider(); 70 } else { 71 this.renderDefaultSlider(); 72 } 73 } 74 75 get disabledX() { 76 return this.getAttribute('disabled-X') || ''; 77 } 78 79 set disabledX(value: string) { 80 if (value) { 81 this.setAttribute('disabled-X', ''); 82 } else { 83 this.removeAttribute('disabled-X'); 84 } 85 } 86 87 get customSlider() { 88 return this.getAttribute('custom-slider') || ''; 89 } 90 91 set customSlider(value: string) { 92 if (value) { 93 this.setAttribute('custom-slider', ''); 94 } else { 95 this.removeAttribute('custom-slider'); 96 } 97 } 98 99 get customLine() { 100 return this.getAttribute('custom-line') || ''; 101 } 102 103 set customLine(value: string) { 104 this.setAttribute('custom-line', value); 105 } 106 107 get customButton() { 108 return this.getAttribute('custom-button') || ''; 109 } 110 111 set customButton(value: string) { 112 this.setAttribute('custom-button', value); 113 } 114 115 get percent() { 116 return this.getAttribute('percent') || ''; 117 } 118 119 set percent(value: string) { 120 this.setAttribute('percent', value); 121 } 122 123 get resultUnit() { 124 return this.getAttribute('resultUnit') || ''; 125 } 126 127 set resultUnit(value: string) { 128 this.setAttribute('resultUnit', value); 129 } 130 131 get sliderSize() { 132 return this.currentValue; 133 } 134 135 initElements(): void { 136 } 137 138 initHtml(): string { 139 this.litSliderStyle = this.sliderStyle; 140 this.currentValue = Number(this.sliderStyle.defaultValue); 141 let parentElement = this.parentNode as Element; 142 if (parentElement) { 143 parentElement.setAttribute('percent', this.defaultTimeText + ""); 144 } 145 return ` 146 <style> 147 :host{ 148 box-sizing:border-box; 149 display:flex; 150 151 } 152 :host([disabled]){ 153 opacity:0.8; 154 cursor:not-allowed; 155 } 156 :host([disabled]) input[type="range"]{ 157 pointer-events:none; 158 } 159 #slider-con{ 160 cursor:pointer; 161 display:flex; 162 align-items:center; 163 padding:5px 0; 164 width:80%; 165 margin: 20px; 166 grid-auto-flow: row dense; 167 position: relative; 168 } 169 :host([showtips]){ 170 pointer-events:all; 171 } 172 173 #slider{ 174 background-color: var(--dark-background7,#D8D8D8); 175 z-index: 5; 176 } 177 178 input[type="range"]{ 179 pointer-events:all; 180 margin:0 -5px; 181 width: 100%; 182 -webkit-appearance: none; 183 outline : 0; 184 background: rgba(0,0,0,0.1); 185 height: 10px; 186 border-radius:2px; 187 background: -webkit-linear-gradient(right, ${this.litSliderStyle?.lineColor},${this.litSliderStyle?.lineColor} ) no-repeat; 188 background-size: ${((Number(this.defaultTimeText) - this.litSliderStyle?.minRange) * 100 / (this.litSliderStyle?.maxRange - this.litSliderStyle?.minRange))}%; 189 } 190 191 input[type="range"]::-webkit-slider-runnable-track{ 192 display: flex; 193 align-items: center; 194 position: relative; 195 height: ${this.sliderLineHeight ? this.sliderLineHeight : "10px"}; 196 border-radius:5px; 197 } 198 199 input[type="range"]::-webkit-slider-thumb{ 200 -webkit-appearance: none; 201 /*border:2px solid #42b983;*/ 202 position: relative; 203 width:${this.sliderButtonHeight ? this.sliderButtonHeight : "20px"}; 204 height:${this.sliderButtonWidth ? this.sliderButtonWidth : "20px"}; 205 margin-top: -4px; 206 border-radius: 5px; 207 background:${this.litSliderStyle?.buttonColor}; 208 transition:0.2s cubic-bezier(.12, .4, .29, 1.46); 209 } 210 211 input[type="range"]:focus{ 212 z-index:2; 213 } 214 215 input[type="range"]::-webkit-slider-thumb:active, 216 input[type="range"]:focus::-webkit-slider-thumb{ 217 transform:scale(1.2); 218 border: 2px solid; 219 box-shadow: 0 0 10px rgba(0,0,0,0.1); 220 background: #fff; 221 } 222 223 :host(:focus-within) #slider-con,:host(:hover) #slider-con{ 224 z-index:10 225 } 226 227 #result{ 228 margin: 10px; 229 width: 196px; 230 height: 40px; 231 background-color: var(--dark-background5,#F2F2F2); 232 -webkit-appearance:none; 233 outline:0; 234 font-size:14px; 235 border-radius:20px; 236 border:1px solid var(--dark-border,#c8cccf); 237 color:var(--dark-color,#6a6f77); 238 text-align: left; 239 } 240 241 #unitSpan{ 242 position: absolute; 243 /*width: min-content;*/ 244 width: 50px; 245 /*top: -50px;*/ 246 right: 0px; 247 color: #adadad; 248 display: table-cell; 249 white-space: nowrap; 250 padding: 7px 10px; 251 font-size:14px; 252 } 253 254 </style> 255 <slot id="slot"></slot> 256 <div id='slider-con' dir="right"> 257 <input id="slider" 258 value=${this.defaultTimeText} 259 min=${this.litSliderStyle?.minRange} 260 max=${this.litSliderStyle?.maxRange} 261 step=${this.litSliderStyle?.stepSize} 262 type="range"> 263 <input id="result" type="text" value=' ${this.litSliderStyle?.defaultValue}'><span id="unitSpan" >${this.litSliderStyle?.resultUnit}</span> 264 </div> 265 ` 266 } 267 268 connectedCallback() { 269 this.slotEl = this.shadowRoot?.querySelector('#slot'); 270 this.litSlider = this.shadowRoot?.querySelector('#slider'); 271 this.litSliderCon = this.shadowRoot?.querySelector('#slider-con'); 272 this.litResult = this.shadowRoot?.querySelector('#result'); 273 this.litSlider?.addEventListener('input', this.inputChangeEvent) 274 this.litSlider?.addEventListener('change', this.inputChangeEvent) 275 this.slotEl?.addEventListener('slotchange', this.slotChangeEvent); 276 this.litSlider?.addEventListener('click', this.sliderClickEvent); 277 this.litSliderButton?.addEventListener('TouchEvent', this.sliderStartTouchEvent); 278 this.litSliderStyle = this.sliderStyle; 279 } 280 281 slotChangeEvent = (event: any) => { 282 } 283 284 sliderClickEvent = (event: any) => { 285 } 286 287 inputChangeEvent = (event: any) => { 288 if (this.litSlider) { 289 this.currentValue = parseInt(this.litSlider?.value) 290 let resultNumber = (this.currentValue - this.litSliderStyle!.minRange) * 100 / (this.litSliderStyle!.maxRange - this.litSliderStyle!.minRange); 291 this.percent = Math.floor(resultNumber) + "%"; 292 this.litSliderCon?.style.setProperty('percent', this.currentValue + "%") 293 let parentElement = this.parentNode as Element; 294 parentElement.setAttribute('percent', this.currentValue + ""); 295 if (this.sliderStyle.resultUnit === 'MB') { 296 this.litSlider!.style.backgroundSize = this.percent; 297 this.litResult!.value = " " + this.currentValue; 298 } else if (this.sliderStyle.resultUnit === 'h:m:s') { 299 this.litSlider!.style.backgroundSize = this.percent; 300 let time = this.formatSeconds(this.litSlider?.value); 301 this.litResult!.value = " " + time; 302 } 303 } 304 } 305 306 sliderStartTouchEvent = (event: any) => { 307 } 308 309 sliderMoveTouchEvent = (event: any) => { 310 } 311 312 sliderEndTouchEvent = (event: any) => { 313 } 314 315 disconnectedCallback() { 316 this.litSlider?.removeEventListener('input', this.inputChangeEvent); 317 this.litSlider?.removeEventListener('change', this.inputChangeEvent) 318 this.litSlider?.removeEventListener('click', this.sliderClickEvent); 319 this.litSliderButton?.removeEventListener('TouchEvent', this.sliderStartTouchEvent); 320 } 321 322 attributeChangedCallback(name: string, oldValue: string, newValue: string) { 323 switch (name) { 324 case "percent": 325 if (newValue === null || newValue === "0%") { 326 let parentElement = this.parentNode as Element; 327 parentElement?.removeAttribute('percent'); 328 } else { 329 let parentElement = this.parentNode as Element; 330 } 331 break; 332 default: 333 break; 334 } 335 } 336 337 renderCustomSlider() { 338 } 339 340 renderDefaultSlider() { 341 if (!this.litSliderStyle) return; 342 } 343 344 formatSeconds(value: string) { 345 let result = parseInt(value) 346 let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600); 347 let minute = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60)); 348 let second = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60)); 349 let resultTime = ''; 350 if (hours === '00') { 351 resultTime += `00:`; 352 } else { 353 resultTime += `${hours}:`; 354 } 355 if (minute === '00') { 356 resultTime += `00:`; 357 } else { 358 resultTime += `${minute}:`; 359 } 360 resultTime += `${second}`; 361 return resultTime; 362 } 363} 364 365export interface LitSliderStyle { 366 minRange: number 367 maxRange: number 368 defaultValue: string 369 resultUnit: string 370 stepSize?: number 371 lineColor?: string 372 buttonColor?: string 373} 374 375export interface LitSliderLineStyle { 376 lineWith: number 377 lineHeight: number 378 border?: string 379 borderRadiusValue?: number 380 lineChangeColor?: string 381} 382 383export interface LitSliderButtonStyle { 384 buttonWith: number 385 buttonHeight: number 386 border?: string 387 borderRadiusValue?: number 388 buttonChangeColor?: string 389} 390