import { h, Component } from 'preact'; import * as style from './style.scss'; import { bind, Fileish } from '../../lib/initial-util'; import { cleanSet, cleanMerge } from '../../lib/clean-modify'; import OptiPNGEncoderOptions from '../../codecs/optipng/options'; import MozJpegEncoderOptions from '../../codecs/mozjpeg/options'; import BrowserJPEGEncoderOptions from '../../codecs/browser-jpeg/options'; import WebPEncoderOptions from '../../codecs/webp/options'; import BrowserWebPEncoderOptions from '../../codecs/browser-webp/options'; import QuantizerOptionsComponent from '../../codecs/imagequant/options'; import ResizeOptionsComponent from '../../codecs/resize/options'; import * as identity from '../../codecs/identity/encoder-meta'; import * as optiPNG from '../../codecs/optipng/encoder-meta'; import * as mozJPEG from '../../codecs/mozjpeg/encoder-meta'; import * as webP from '../../codecs/webp/encoder-meta'; import * as browserPNG from '../../codecs/browser-png/encoder-meta'; import * as browserJPEG from '../../codecs/browser-jpeg/encoder-meta'; import * as browserWebP from '../../codecs/browser-webp/encoder-meta'; import * as browserGIF from '../../codecs/browser-gif/encoder-meta'; import * as browserTIFF from '../../codecs/browser-tiff/encoder-meta'; import * as browserJP2 from '../../codecs/browser-jp2/encoder-meta'; import * as browserBMP from '../../codecs/browser-bmp/encoder-meta'; import * as browserPDF from '../../codecs/browser-pdf/encoder-meta'; import { EncoderState, EncoderType, EncoderOptions, encoders, encodersSupported, EncoderSupportMap, } from '../../codecs/encoders'; import { QuantizeOptions } from '../../codecs/imagequant/processor-meta'; import { ResizeOptions } from '../../codecs/resize/processor-meta'; import { PreprocessorState } from '../../codecs/preprocessors'; import FileSize from './FileSize'; import { DownloadIcon } from '../../lib/icons'; import { SourceImage } from '../App'; import Checkbox from '../checkbox'; import Expander from '../expander'; import Select from '../select'; import '../custom-els/LoadingSpinner'; const encoderOptionsComponentMap = { [identity.type]: undefined, [optiPNG.type]: OptiPNGEncoderOptions, [mozJPEG.type]: MozJpegEncoderOptions, [webP.type]: WebPEncoderOptions, [browserPNG.type]: undefined, [browserJPEG.type]: BrowserJPEGEncoderOptions, [browserWebP.type]: BrowserWebPEncoderOptions, [browserBMP.type]: undefined, // Only Safari supports the rest, and it doesn't support quality settings. [browserGIF.type]: undefined, [browserTIFF.type]: undefined, [browserJP2.type]: undefined, [browserPDF.type]: undefined, }; interface Props { mobileView: boolean; loading: boolean; source?: SourceImage; imageIndex: number; imageFile?: Fileish; downloadUrl?: string; encoderState: EncoderState; preprocessorState: PreprocessorState; onEncoderTypeChange(newType: EncoderType): void; onEncoderOptionsChange(newOptions: EncoderOptions): void; onPreprocessorOptionsChange(newOptions: PreprocessorState): void; onCopyToOtherClick(): void; } interface State { encoderSupportMap?: EncoderSupportMap; showLoadingState: boolean; } const loadingReactionDelay = 500; export default class Options extends Component { state: State = { encoderSupportMap: undefined, showLoadingState: false, }; /** The timeout ID between entering the loading state, and changing UI */ private loadingTimeoutId: number = 0; constructor() { super(); encodersSupported.then(encoderSupportMap => this.setState({ encoderSupportMap })); } componentDidUpdate(prevProps: Props, prevState: State) { if (prevProps.loading && !this.props.loading) { // Just stopped loading clearTimeout(this.loadingTimeoutId); this.setState({ showLoadingState: false }); } else if (!prevProps.loading && this.props.loading) { // Just started loading this.loadingTimeoutId = self.setTimeout( () => this.setState({ showLoadingState: true }), loadingReactionDelay, ); } } @bind onEncoderTypeChange(event: Event) { const el = event.currentTarget as HTMLSelectElement; // The select element only has values matching encoder types, // so 'as' is safe here. const type = el.value as EncoderType; this.props.onEncoderTypeChange(type); } @bind onPreprocessorEnabledChange(event: Event) { const el = event.currentTarget as HTMLInputElement; const preprocessor = el.name.split('.')[0] as keyof PreprocessorState; this.props.onPreprocessorOptionsChange( cleanSet(this.props.preprocessorState, `${preprocessor}.enabled`, el.checked), ); } @bind onQuantizerOptionsChange(opts: QuantizeOptions) { this.props.onPreprocessorOptionsChange( cleanMerge(this.props.preprocessorState, 'quantizer', opts), ); } @bind onResizeOptionsChange(opts: ResizeOptions) { this.props.onPreprocessorOptionsChange( cleanMerge(this.props.preprocessorState, 'resize', opts), ); } @bind onCopyToOtherClick(event: Event) { event.preventDefault(); this.props.onCopyToOtherClick(); } render( { source, imageIndex, imageFile, downloadUrl, encoderState, preprocessorState, onEncoderOptionsChange, }: Props, { encoderSupportMap, showLoadingState }: State, ) { // tslint:disable variable-name const EncoderOptionComponent = encoderOptionsComponentMap[encoderState.type]; return (
{encoderState.type === identity.type ? null :

Edit

{preprocessorState.resize.enabled ? : null} {preprocessorState.quantizer.enabled ? : null}
}

Compress

{encoderSupportMap ? : }
{EncoderOptionComponent ? : null}
{!imageFile || showLoadingState ? 'Working…' : }
{(downloadUrl && imageFile) && ( )} {showLoadingState && }
); } }