import type Mithril from 'mithril'; import type Stream from 'mithril/stream'; import app from 'flarum/admin/app'; import AdminPage, { CommonSettingsItemOptions } from 'flarum/admin/components/AdminPage'; import SelectOrInput from "../../common/Components/SelectOrInput"; import generateElementId from 'flarum/admin/utils/generateElementId'; // forgive me, but this interface is just what its name implies interface SelectOrInputSettingComponentOptionsWithoutType extends CommonSettingsItemOptions { options: { [value: string]: Mithril.Children }; checkboxDescription: string; default: string; } export interface SelectOrInputSettingComponentOptions extends SelectOrInputSettingComponentOptionsWithoutType { type: 'select-or-input'; } interface StreamWithMark extends Stream { mark?: true; } export default function (this: AdminPage, _entry: CommonSettingsItemOptions) { // do this cast because function signature is restricted const entry = _entry as SelectOrInputSettingComponentOptionsWithoutType; const [inputId, helpTextId] = [generateElementId(), generateElementId()]; const { setting, help, label, ...componentAttrs } = entry; const { default: defaultValue, options, checkboxDescription, ...otherAttrs } = componentAttrs; let settingElement: Mithril.Children; // Trick: add a marker property to the AdminPage's setting stream, // which contructs and destructs with AdminPage so that default is // only loaded when the page is created. // Default should only be loaded once in a page because when checkbox // is checked, SelectOrInput will set its value to empty string so that // it becomes an empty input. If default is loaded every time when value // is falsy, SelectOrInput will not work properly. const settingStream = this.settings[setting] as StreamWithMark; let value = settingStream(); if (!settingStream.mark) { settingStream.mark = true; if (!value) { app.data.settings[setting] = defaultValue; settingStream(defaultValue); value = settingStream(); } } settingElement = ( ); return (
{label && }
{help}
{settingElement}
); }