morethanwords
4 years ago
9 changed files with 347 additions and 188 deletions
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
import { isTouchSupported } from "../helpers/touchSupport"; |
||||
import { clamp } from "../helpers/number"; |
||||
|
||||
type SUPEREVENT = MouseEvent | TouchEvent; |
||||
|
||||
export default class RangeSelector { |
||||
public container: HTMLDivElement; |
||||
protected filled: HTMLDivElement; |
||||
protected seek: HTMLInputElement; |
||||
|
||||
public mousedown = false; |
||||
|
||||
private events: Partial<{ |
||||
//onMouseMove: ProgressLine['onMouseMove'],
|
||||
onMouseDown: RangeSelector['onMouseDown'], |
||||
onMouseUp: RangeSelector['onMouseUp'], |
||||
onScrub: (scrubTime: number) => void |
||||
}> = {}; |
||||
|
||||
protected decimals: number; |
||||
|
||||
constructor(protected step: number, protected value: number, protected min: number, protected max: number) { |
||||
this.container = document.createElement('div'); |
||||
this.container.classList.add('progress-line'); |
||||
|
||||
this.filled = document.createElement('div'); |
||||
this.filled.classList.add('progress-line__filled'); |
||||
|
||||
const seek = this.seek = document.createElement('input'); |
||||
seek.classList.add('progress-line__seek'); |
||||
//seek.setAttribute('max', '0');
|
||||
seek.type = 'range'; |
||||
seek.step = '' + step; |
||||
seek.min = '' + this.min; |
||||
seek.max = '' + this.max; |
||||
seek.value = '' + value; |
||||
|
||||
/* this.seek.addEventListener('change', (e) => { |
||||
console.log('seek change', e); |
||||
}); */ |
||||
|
||||
if(value) { |
||||
this.setProgress(value); |
||||
} |
||||
|
||||
const stepStr = '' + this.step; |
||||
const index = stepStr.indexOf('.'); |
||||
this.decimals = index === -1 ? 0 : stepStr.length - index - 1; |
||||
|
||||
//this.setListeners();
|
||||
|
||||
this.container.append(this.filled, seek); |
||||
} |
||||
|
||||
public setHandlers(events: RangeSelector['events']) { |
||||
this.events = events; |
||||
} |
||||
|
||||
onMouseMove = (e: SUPEREVENT) => { |
||||
this.mousedown && this.scrub(e); |
||||
}; |
||||
|
||||
onMouseDown = (e: SUPEREVENT) => { |
||||
this.scrub(e); |
||||
this.mousedown = true; |
||||
this.events?.onMouseDown && this.events.onMouseDown(e); |
||||
}; |
||||
|
||||
onMouseUp = (e: SUPEREVENT) => { |
||||
this.mousedown = false; |
||||
this.events?.onMouseUp && this.events.onMouseUp(e); |
||||
}; |
||||
|
||||
public setListeners() { |
||||
this.container.addEventListener('mousemove', this.onMouseMove); |
||||
this.container.addEventListener('mousedown', this.onMouseDown); |
||||
this.container.addEventListener('mouseup', this.onMouseUp); |
||||
|
||||
if(isTouchSupported) { |
||||
this.container.addEventListener('touchmove', this.onMouseMove, {passive: true}); |
||||
this.container.addEventListener('touchstart', this.onMouseDown, {passive: true}); |
||||
this.container.addEventListener('touchend', this.onMouseUp, {passive: true}); |
||||
} |
||||
} |
||||
|
||||
public setProgress(value: number) { |
||||
this.setFilled(value); |
||||
this.seek.value = '' + value; |
||||
} |
||||
|
||||
public setFilled(value: number) { |
||||
let percents = (value - this.min) / (this.max - this.min); |
||||
percents = clamp(percents, 0, 1); |
||||
//console.log('setFilled', percents, value);
|
||||
this.filled.style.width = (percents * 100) + '%'; |
||||
//this.filled.style.transform = 'scaleX(' + scaleX + ')';
|
||||
} |
||||
|
||||
protected scrub(e: SUPEREVENT) { |
||||
let offsetX: number; |
||||
const rect = (e.target as HTMLElement).getBoundingClientRect(); |
||||
if(e instanceof MouseEvent) { |
||||
offsetX = e.pageX - Math.round(rect.left); |
||||
} else { // touch
|
||||
offsetX = e.targetTouches[0].pageX - Math.round(rect.left); |
||||
} |
||||
|
||||
let value = this.min + (offsetX / Math.round(rect.width) * (this.max - this.min)); |
||||
|
||||
if((value - this.min) < ((this.max - this.min) / 2)) { |
||||
value -= this.step / 10; |
||||
} |
||||
|
||||
//console.log('scrub value:', value, this.decimals, offsetX, rect.width, e);
|
||||
value = +value.toFixed(this.decimals); |
||||
//const dotIndex = ('' + value).indexOf('.');
|
||||
//value = +('' + value).slice(0, this.decimals ? dotIndex + this.decimals : dotIndex);
|
||||
|
||||
value = clamp(value, this.min, this.max); |
||||
|
||||
this.setFilled(value); |
||||
|
||||
this.events?.onScrub && this.events.onScrub(value); |
||||
return value; |
||||
} |
||||
|
||||
public removeListeners() { |
||||
this.container.removeEventListener('mousemove', this.onMouseMove); |
||||
this.container.removeEventListener('mousedown', this.onMouseDown); |
||||
this.container.removeEventListener('mouseup', this.onMouseUp); |
||||
|
||||
if(isTouchSupported) { |
||||
this.container.removeEventListener('touchmove', this.onMouseMove); |
||||
this.container.removeEventListener('touchstart', this.onMouseDown); |
||||
this.container.removeEventListener('touchend', this.onMouseUp); |
||||
} |
||||
|
||||
this.events = {}; |
||||
} |
||||
} |
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
import { SliderSuperTab } from "../../slider" |
||||
import { AppSidebarLeft } from ".."; |
||||
import RangeSelector from "../../rangeSelector"; |
||||
import { clamp } from "../../../helpers/number"; |
||||
|
||||
export class RangeSettingSelector { |
||||
public container: HTMLDivElement; |
||||
private range: RangeSelector; |
||||
|
||||
constructor(name: string, step: number, initialValue: number, minValue: number, maxValue: number) { |
||||
const BASE_CLASS = 'range-setting-selector'; |
||||
this.container = document.createElement('div'); |
||||
this.container.classList.add(BASE_CLASS); |
||||
|
||||
const details = document.createElement('div'); |
||||
details.classList.add(BASE_CLASS + '-details'); |
||||
|
||||
const nameDiv = document.createElement('div'); |
||||
nameDiv.classList.add(BASE_CLASS + '-name'); |
||||
nameDiv.innerHTML = name; |
||||
|
||||
const valueDiv = document.createElement('div'); |
||||
valueDiv.classList.add(BASE_CLASS + '-value'); |
||||
valueDiv.innerHTML = '' + initialValue; |
||||
|
||||
details.append(nameDiv, valueDiv); |
||||
|
||||
this.range = new RangeSelector(step, initialValue, minValue, maxValue); |
||||
this.range.setListeners(); |
||||
this.range.setHandlers({ |
||||
onScrub: value => { |
||||
//console.log('font size scrub:', value);
|
||||
valueDiv.innerText = '' + value; |
||||
} |
||||
}); |
||||
|
||||
this.container.append(details, this.range.container); |
||||
} |
||||
} |
||||
|
||||
export default class AppGeneralSettingsTab extends SliderSuperTab { |
||||
constructor(appSidebarLeft: AppSidebarLeft) { |
||||
super(appSidebarLeft); |
||||
} |
||||
|
||||
init() { |
||||
this.container.classList.add('general-settings-container'); |
||||
this.title.innerText = 'General'; |
||||
|
||||
const generateSection = (name: string) => { |
||||
const container = document.createElement('div'); |
||||
container.classList.add('sidebar-left-section'); |
||||
|
||||
const hr = document.createElement('hr'); |
||||
const h2 = document.createElement('div'); |
||||
h2.classList.add('sidebar-left-section-name'); |
||||
h2.innerHTML = name; |
||||
|
||||
const content = document.createElement('div'); |
||||
content.classList.add('sidebar-left-section-content'); |
||||
content.append(h2); |
||||
|
||||
container.append(hr, content); |
||||
|
||||
this.scrollable.append(container); |
||||
|
||||
return content; |
||||
}; |
||||
|
||||
{ |
||||
const container = generateSection('Settings'); |
||||
|
||||
const range = new RangeSettingSelector('Message Text Size', 1, 16, 12, 20); |
||||
|
||||
container.append(range.container); |
||||
} |
||||
|
||||
generateSection('Keyboard'); |
||||
generateSection('Auto-Download Media'); |
||||
generateSection('Auto-Play Media'); |
||||
generateSection('Stickers'); |
||||
} |
||||
|
||||
onOpen() { |
||||
if(this.init) { |
||||
this.init(); |
||||
this.init = null; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue