import * as React from "react" import intl from "react-intl-universal" import { Label, DefaultButton, TextField, Stack, PrimaryButton, DetailsList, IColumn, SelectionMode, Selection, IChoiceGroupOption, ChoiceGroup, IDropdownOption, Dropdown, MessageBar, MessageBarType, } from "@fluentui/react" import { SourceState, RSSSource, SourceOpenTarget, } from "../../scripts/models/source" import { urlTest } from "../../scripts/utils" import DangerButton from "../utils/danger-button" type SourcesTabProps = { sources: SourceState serviceOn: boolean sids: number[] acknowledgeSIDs: () => void addSource: (url: string) => void updateSourceName: (source: RSSSource, name: string) => void updateSourceIcon: (source: RSSSource, iconUrl: string) => Promise updateSourceOpenTarget: ( source: RSSSource, target: SourceOpenTarget ) => void updateFetchFrequency: (source: RSSSource, frequency: number) => void deleteSource: (source: RSSSource) => void deleteSources: (sources: RSSSource[]) => void importOPML: () => void exportOPML: () => void } type SourcesTabState = { [formName: string]: string } & { selectedSource: RSSSource selectedSources: RSSSource[] } const enum EditDropdownKeys { Name = "n", Icon = "i", Url = "u", } class SourcesTab extends React.Component { selection: Selection constructor(props) { super(props) this.state = { newUrl: "", newSourceName: "", selectedSource: null, selectedSources: null, } this.selection = new Selection({ getKey: s => (s as RSSSource).sid, onSelectionChanged: () => { let count = this.selection.getSelectedCount() let sources = count ? (this.selection.getSelection() as RSSSource[]) : null this.setState({ selectedSource: count === 1 ? sources[0] : null, selectedSources: count > 1 ? sources : null, newSourceName: count === 1 ? sources[0].name : "", newSourceIcon: count === 1 ? sources[0].iconurl || "" : "", sourceEditOption: EditDropdownKeys.Name, }) }, }) } componentDidMount = () => { if (this.props.sids.length > 0) { for (let sid of this.props.sids) { this.selection.setKeySelected(String(sid), true, false) } this.props.acknowledgeSIDs() } } columns = (): IColumn[] => [ { key: "favicon", name: intl.get("icon"), fieldName: "name", isIconOnly: true, iconName: "ImagePixel", minWidth: 16, maxWidth: 16, onRender: (s: RSSSource) => s.iconurl && , }, { key: "name", name: intl.get("name"), fieldName: "name", minWidth: 200, data: "string", isRowHeader: true, }, { key: "url", name: "URL", fieldName: "url", minWidth: 280, data: "string", }, ] sourceEditOptions = (): IDropdownOption[] => [ { key: EditDropdownKeys.Name, text: intl.get("name") }, { key: EditDropdownKeys.Icon, text: intl.get("icon") }, { key: EditDropdownKeys.Url, text: "URL" }, ] onSourceEditOptionChange = (_, option: IDropdownOption) => { this.setState({ sourceEditOption: option.key as string }) } fetchFrequencyOptions = (): IDropdownOption[] => [ { key: "0", text: intl.get("sources.unlimited") }, { key: "15", text: intl.get("time.minute", { m: 15 }) }, { key: "30", text: intl.get("time.minute", { m: 30 }) }, { key: "60", text: intl.get("time.hour", { h: 1 }) }, { key: "120", text: intl.get("time.hour", { h: 2 }) }, { key: "180", text: intl.get("time.hour", { h: 3 }) }, { key: "360", text: intl.get("time.hour", { h: 6 }) }, { key: "720", text: intl.get("time.hour", { h: 12 }) }, { key: "1440", text: intl.get("time.day", { d: 1 }) }, ] onFetchFrequencyChange = (_, option: IDropdownOption) => { let frequency = parseInt(option.key as string) this.props.updateFetchFrequency(this.state.selectedSource, frequency) this.setState({ selectedSource: { ...this.state.selectedSource, fetchFrequency: frequency, } as RSSSource, }) } sourceOpenTargetChoices = (): IChoiceGroupOption[] => [ { key: String(SourceOpenTarget.Local), text: intl.get("sources.rssText"), }, { key: String(SourceOpenTarget.FullContent), text: intl.get("article.loadFull"), }, { key: String(SourceOpenTarget.Webpage), text: intl.get("sources.loadWebpage"), }, { key: String(SourceOpenTarget.External), text: intl.get("openExternal"), }, ] updateSourceName = () => { let newName = this.state.newSourceName.trim() this.props.updateSourceName(this.state.selectedSource, newName) this.setState({ selectedSource: { ...this.state.selectedSource, name: newName, } as RSSSource, }) } updateSourceIcon = () => { let newIcon = this.state.newSourceIcon.trim() this.props.updateSourceIcon(this.state.selectedSource, newIcon) this.setState({ selectedSource: { ...this.state.selectedSource, iconurl: newIcon }, }) } handleInputChange = event => { const name: string = event.target.name this.setState({ [name]: event.target.value }) } addSource = (event: React.FormEvent) => { event.preventDefault() let trimmed = this.state.newUrl.trim() if (urlTest(trimmed)) this.props.addSource(trimmed) } onOpenTargetChange = (_, option: IChoiceGroupOption) => { let newTarget = parseInt(option.key) as SourceOpenTarget this.props.updateSourceOpenTarget(this.state.selectedSource, newTarget) this.setState({ selectedSource: { ...this.state.selectedSource, openTarget: newTarget, } as RSSSource, }) } render = () => (
{this.props.serviceOn && ( {intl.get("sources.serviceWarning")} )}
urlTest(v.trim()) ? "" : intl.get("sources.badUrl") } validateOnLoad={false} placeholder={intl.get("sources.inputUrl")} value={this.state.newUrl} id="newUrl" name="newUrl" onChange={this.handleInputChange} />
= 10} items={Object.values(this.props.sources)} columns={this.columns()} getKey={s => s.sid} setKey="selected" selection={this.selection} selectionMode={SelectionMode.multiple} /> {this.state.selectedSource && ( <> {this.state.selectedSource.serviceRef && ( {intl.get("sources.serviceManaged")} )} {this.state.sourceEditOption === EditDropdownKeys.Name && ( <> v.trim().length == 0 ? intl.get("emptyName") : "" } validateOnLoad={false} placeholder={intl.get("sources.name")} value={this.state.newSourceName} name="newSourceName" onChange={this.handleInputChange} /> )} {this.state.sourceEditOption === EditDropdownKeys.Icon && ( <> urlTest(v.trim()) ? "" : intl.get("sources.badUrl") } validateOnLoad={false} placeholder={intl.get( "sources.inputUrl" )} value={this.state.newSourceIcon} name="newSourceIcon" onChange={this.handleInputChange} /> )} {this.state.sourceEditOption === EditDropdownKeys.Url && ( <> window.utils.writeClipboard( this.state.selectedSource.url ) } text={intl.get("context.copy")} /> )} {!this.state.selectedSource.serviceRef && ( <> )} {!this.state.selectedSource.serviceRef && ( this.props.deleteSource( this.state.selectedSource ) } key={this.state.selectedSource.sid} text={intl.get("sources.delete")} /> {intl.get("sources.deleteWarning")} )} )} {this.state.selectedSources && (this.state.selectedSources.filter(s => s.serviceRef).length === 0 ? ( <> this.props.deleteSources( this.state.selectedSources ) } text={intl.get("sources.delete")} /> {intl.get("sources.deleteWarning")} ) : ( {intl.get("sources.serviceManaged")} ))}
) } export default SourcesTab