1 import { myAuthRequired } from "@utils/app";
2 import { capitalizeFirstLetter, validInstanceTLD } from "@utils/helpers";
10 import { Prompt } from "inferno-router";
17 } from "lemmy-js-client";
18 import deepEqual from "lodash.isequal";
19 import { I18NextService } from "../../services";
20 import { Icon, Spinner } from "../common/icon";
21 import { ImageUploadForm } from "../common/image-upload-form";
22 import { LanguageSelect } from "../common/language-select";
23 import { ListingTypeSelect } from "../common/listing-type-select";
24 import { MarkdownTextArea } from "../common/markdown-textarea";
26 interface SiteFormProps {
27 blockedInstances?: Instance[];
28 allowedInstances?: Instance[];
31 onSaveSite(form: EditSite): void;
32 siteRes: GetSiteResponse;
36 interface SiteFormState {
39 allowed_instances: string;
40 blocked_instances: string;
45 type InstanceKey = "allowed_instances" | "blocked_instances";
47 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
48 state: SiteFormState = {
49 siteForm: this.initSiteForm(),
51 allowed_instances: "",
52 blocked_instances: "",
57 initSiteForm(): EditSite {
58 const site = this.props.siteRes.site_view.site;
59 const ls = this.props.siteRes.site_view.local_site;
63 sidebar: site.sidebar,
64 description: site.description,
65 enable_downvotes: ls.enable_downvotes,
66 registration_mode: ls.registration_mode,
67 enable_nsfw: ls.enable_nsfw,
68 community_creation_admin_only: ls.community_creation_admin_only,
71 require_email_verification: ls.require_email_verification,
72 application_question: ls.application_question,
73 private_instance: ls.private_instance,
74 default_theme: ls.default_theme,
75 default_post_listing_type: ls.default_post_listing_type,
76 legal_information: ls.legal_information,
77 application_email_admins: ls.application_email_admins,
78 reports_email_admins: ls.reports_email_admins,
79 hide_modlog_mod_names: ls.hide_modlog_mod_names,
80 discussion_languages: this.props.siteRes.discussion_languages,
81 slur_filter_regex: ls.slur_filter_regex,
82 actor_name_max_length: ls.actor_name_max_length,
83 federation_enabled: ls.federation_enabled,
84 captcha_enabled: ls.captcha_enabled,
85 captcha_difficulty: ls.captcha_difficulty,
86 allowed_instances: this.props.allowedInstances?.map(i => i.domain),
87 blocked_instances: this.props.blockedInstances?.map(i => i.domain),
92 constructor(props: any, context: any) {
93 super(props, context);
95 this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
96 this.handleSiteLegalInfoChange = this.handleSiteLegalInfoChange.bind(this);
97 this.handleSiteApplicationQuestionChange =
98 this.handleSiteApplicationQuestionChange.bind(this);
100 this.handleIconUpload = this.handleIconUpload.bind(this);
101 this.handleIconRemove = this.handleIconRemove.bind(this);
103 this.handleBannerUpload = this.handleBannerUpload.bind(this);
104 this.handleBannerRemove = this.handleBannerRemove.bind(this);
106 this.handleDefaultPostListingTypeChange =
107 this.handleDefaultPostListingTypeChange.bind(this);
109 this.handleDiscussionLanguageChange =
110 this.handleDiscussionLanguageChange.bind(this);
112 this.handleAddInstance = this.handleAddInstance.bind(this);
113 this.handleRemoveInstance = this.handleRemoveInstance.bind(this);
115 this.handleInstanceEnterPress = this.handleInstanceEnterPress.bind(this);
116 this.handleInstanceTextChange = this.handleInstanceTextChange.bind(this);
120 const siteSetup = this.props.siteRes.site_view.local_site.site_setup;
123 className="site-form"
124 onSubmit={linkEvent(this, this.handleSaveSiteSubmit)}
127 message={I18NextService.i18n.t("block_leaving")}
129 !this.props.loading &&
132 this.state.siteForm.name ||
133 this.state.siteForm.sidebar ||
134 this.state.siteForm.application_question ||
135 this.state.siteForm.description
137 !this.state.submitted
140 <h2 className="h5">{`${
142 ? capitalizeFirstLetter(I18NextService.i18n.t("edit"))
143 : capitalizeFirstLetter(I18NextService.i18n.t("setup"))
144 } ${I18NextService.i18n.t("your_site")}`}</h2>
145 <div className="mb-3 row">
146 <label className="col-12 col-form-label" htmlFor="create-site-name">
147 {I18NextService.i18n.t("name")}
149 <div className="col-12">
152 id="create-site-name"
153 className="form-control"
154 value={this.state.siteForm.name}
155 onInput={linkEvent(this, this.handleSiteNameChange)}
162 <div className="row mb-3">
163 <label className="col-sm-2 col-form-label">
164 {I18NextService.i18n.t("icon")}
166 <div className="col-sm-10">
168 uploadTitle={I18NextService.i18n.t("upload_icon")}
169 imageSrc={this.state.siteForm.icon}
170 onUpload={this.handleIconUpload}
171 onRemove={this.handleIconRemove}
176 <div className="row mb-3">
177 <label className="col-sm-2 col-form-label">
178 {I18NextService.i18n.t("banner")}
180 <div className="col-sm-10">
182 uploadTitle={I18NextService.i18n.t("upload_banner")}
183 imageSrc={this.state.siteForm.banner}
184 onUpload={this.handleBannerUpload}
185 onRemove={this.handleBannerRemove}
189 <div className="mb-3 row">
190 <label className="col-12 col-form-label" htmlFor="site-desc">
191 {I18NextService.i18n.t("description")}
193 <div className="col-12">
196 className="form-control"
198 value={this.state.siteForm.description}
199 onInput={linkEvent(this, this.handleSiteDescChange)}
204 <div className="mb-3 row">
205 <label className="col-12 col-form-label">
206 {I18NextService.i18n.t("sidebar")}
208 <div className="col-12">
210 initialContent={this.state.siteForm.sidebar}
211 onContentChange={this.handleSiteSidebarChange}
212 hideNavigationWarnings
218 <div className="mb-3 row">
219 <label className="col-12 col-form-label">
220 {I18NextService.i18n.t("legal_information")}
222 <div className="col-12">
224 initialContent={this.state.siteForm.legal_information}
225 onContentChange={this.handleSiteLegalInfoChange}
226 hideNavigationWarnings
232 <div className="mb-3 row">
233 <div className="col-12">
234 <div className="form-check">
236 className="form-check-input"
237 id="create-site-downvotes"
239 checked={this.state.siteForm.enable_downvotes}
240 onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)}
243 className="form-check-label"
244 htmlFor="create-site-downvotes"
246 {I18NextService.i18n.t("enable_downvotes")}
251 <div className="mb-3 row">
252 <div className="col-12">
253 <div className="form-check">
255 className="form-check-input"
256 id="create-site-enable-nsfw"
258 checked={this.state.siteForm.enable_nsfw}
259 onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
262 className="form-check-label"
263 htmlFor="create-site-enable-nsfw"
265 {I18NextService.i18n.t("enable_nsfw")}
270 <div className="mb-3 row">
271 <div className="col-12">
273 className="form-check-label me-2"
274 htmlFor="create-site-registration-mode"
276 {I18NextService.i18n.t("registration_mode")}
279 id="create-site-registration-mode"
280 value={this.state.siteForm.registration_mode}
281 onChange={linkEvent(this, this.handleSiteRegistrationModeChange)}
282 className="form-select d-inline-block w-auto"
284 <option value={"RequireApplication"}>
285 {I18NextService.i18n.t("require_registration_application")}
287 <option value={"Open"}>
288 {I18NextService.i18n.t("open_registration")}
290 <option value={"Closed"}>
291 {I18NextService.i18n.t("close_registration")}
296 {this.state.siteForm.registration_mode === "RequireApplication" && (
297 <div className="mb-3 row">
298 <label className="col-12 col-form-label">
299 {I18NextService.i18n.t("application_questionnaire")}
301 <div className="col-12">
303 initialContent={this.state.siteForm.application_question}
304 onContentChange={this.handleSiteApplicationQuestionChange}
305 hideNavigationWarnings
312 <div className="mb-3 row">
313 <div className="col-12">
314 <div className="form-check">
316 className="form-check-input"
317 id="create-site-community-creation-admin-only"
319 checked={this.state.siteForm.community_creation_admin_only}
322 this.handleSiteCommunityCreationAdminOnly,
326 className="form-check-label"
327 htmlFor="create-site-community-creation-admin-only"
329 {I18NextService.i18n.t("community_creation_admin_only")}
334 <div className="mb-3 row">
335 <div className="col-12">
336 <div className="form-check">
338 className="form-check-input"
339 id="create-site-require-email-verification"
341 checked={this.state.siteForm.require_email_verification}
344 this.handleSiteRequireEmailVerification,
348 className="form-check-label"
349 htmlFor="create-site-require-email-verification"
351 {I18NextService.i18n.t("require_email_verification")}
356 <div className="mb-3 row">
357 <div className="col-12">
358 <div className="form-check">
360 className="form-check-input"
361 id="create-site-application-email-admins"
363 checked={this.state.siteForm.application_email_admins}
366 this.handleSiteApplicationEmailAdmins,
370 className="form-check-label"
371 htmlFor="create-site-email-admins"
373 {I18NextService.i18n.t("application_email_admins")}
378 <div className="mb-3 row">
379 <div className="col-12">
380 <div className="form-check">
382 className="form-check-input"
383 id="create-site-reports-email-admins"
385 checked={this.state.siteForm.reports_email_admins}
386 onChange={linkEvent(this, this.handleSiteReportsEmailAdmins)}
389 className="form-check-label"
390 htmlFor="create-site-reports-email-admins"
392 {I18NextService.i18n.t("reports_email_admins")}
397 <div className="mb-3 row">
398 <div className="col-12">
400 className="form-check-label me-2"
401 htmlFor="create-site-default-theme"
403 {I18NextService.i18n.t("theme")}
406 id="create-site-default-theme"
407 value={this.state.siteForm.default_theme}
408 onChange={linkEvent(this, this.handleSiteDefaultTheme)}
409 className="form-select d-inline-block w-auto"
411 <option value="browser">
412 {I18NextService.i18n.t("browser_default")}
414 <option value="browser-compact">
415 {I18NextService.i18n.t("browser_default_compact")}
417 {this.props.themeList?.map(theme => (
418 <option key={theme} value={theme}>
425 {this.props.showLocal && (
426 <form className="mb-3 row">
427 <label className="col-sm-3 col-form-label">
428 {I18NextService.i18n.t("listing_type")}
430 <div className="col-sm-9">
432 type_={this.state.siteForm.default_post_listing_type ?? "Local"}
434 showSubscribed={false}
435 onChange={this.handleDefaultPostListingTypeChange}
440 <div className="mb-3 row">
441 <div className="col-12">
442 <div className="form-check">
444 className="form-check-input"
445 id="create-site-private-instance"
447 checked={this.state.siteForm.private_instance}
448 onChange={linkEvent(this, this.handleSitePrivateInstance)}
451 className="form-check-label"
452 htmlFor="create-site-private-instance"
454 {I18NextService.i18n.t("private_instance")}
459 <div className="mb-3 row">
460 <div className="col-12">
461 <div className="form-check">
463 className="form-check-input"
464 id="create-site-hide-modlog-mod-names"
466 checked={this.state.siteForm.hide_modlog_mod_names}
467 onChange={linkEvent(this, this.handleSiteHideModlogModNames)}
470 className="form-check-label"
471 htmlFor="create-site-hide-modlog-mod-names"
473 {I18NextService.i18n.t("hide_modlog_mod_names")}
478 <div className="mb-3 row">
480 className="col-12 col-form-label"
481 htmlFor="create-site-slur-filter-regex"
483 {I18NextService.i18n.t("slur_filter_regex")}
485 <div className="col-12">
488 id="create-site-slur-filter-regex"
489 placeholder="(word1|word2)"
490 className="form-control"
491 value={this.state.siteForm.slur_filter_regex}
492 onInput={linkEvent(this, this.handleSiteSlurFilterRegex)}
498 allLanguages={this.props.siteRes.all_languages}
499 siteLanguages={this.props.siteRes.discussion_languages}
500 selectedLanguageIds={this.state.siteForm.discussion_languages}
502 onChange={this.handleDiscussionLanguageChange}
505 <div className="mb-3 row">
507 className="col-12 col-form-label"
508 htmlFor="create-site-actor-name"
510 {I18NextService.i18n.t("actor_name_max_length")}
512 <div className="col-12">
515 id="create-site-actor-name"
516 className="form-control"
518 value={this.state.siteForm.actor_name_max_length}
519 onInput={linkEvent(this, this.handleSiteActorNameMaxLength)}
523 <div className="mb-3 row">
524 <div className="col-12">
525 <div className="form-check">
527 className="form-check-input"
528 id="create-site-federation-enabled"
530 checked={this.state.siteForm.federation_enabled}
531 onChange={linkEvent(this, this.handleSiteFederationEnabled)}
534 className="form-check-label"
535 htmlFor="create-site-federation-enabled"
537 {I18NextService.i18n.t("federation_enabled")}
542 {this.state.siteForm.federation_enabled && (
544 <div className="mb-3 row">
545 {this.federatedInstanceSelect("allowed_instances")}
546 {this.federatedInstanceSelect("blocked_instances")}
548 <div className="mb-3 row">
549 <div className="col-12">
550 <div className="form-check">
552 className="form-check-input"
553 id="create-site-federation-debug"
555 checked={this.state.siteForm.federation_debug}
556 onChange={linkEvent(this, this.handleSiteFederationDebug)}
559 className="form-check-label"
560 htmlFor="create-site-federation-debug"
562 {I18NextService.i18n.t("federation_debug")}
569 <div className="mb-3 row">
570 <div className="col-12">
571 <div className="form-check">
573 className="form-check-input"
574 id="create-site-captcha-enabled"
576 checked={this.state.siteForm.captcha_enabled}
577 onChange={linkEvent(this, this.handleSiteCaptchaEnabled)}
580 className="form-check-label"
581 htmlFor="create-site-captcha-enabled"
583 {I18NextService.i18n.t("captcha_enabled")}
588 {this.state.siteForm.captcha_enabled && (
589 <div className="mb-3 row">
590 <div className="col-12">
592 className="form-check-label me-2"
593 htmlFor="create-site-captcha-difficulty"
595 {I18NextService.i18n.t("captcha_difficulty")}
598 id="create-site-captcha-difficulty"
599 value={this.state.siteForm.captcha_difficulty}
600 onChange={linkEvent(this, this.handleSiteCaptchaDifficulty)}
601 className="form-select d-inline-block w-auto"
603 <option value="easy">{I18NextService.i18n.t("easy")}</option>
604 <option value="medium">
605 {I18NextService.i18n.t("medium")}
607 <option value="hard">{I18NextService.i18n.t("hard")}</option>
612 <div className="mb-3 row">
613 <div className="col-12">
616 className="btn btn-secondary me-2"
617 disabled={this.props.loading}
619 {this.props.loading ? (
622 capitalizeFirstLetter(I18NextService.i18n.t("save"))
624 capitalizeFirstLetter(I18NextService.i18n.t("create"))
634 prevProps: Readonly<{ children?: InfernoNode } & SiteFormProps>,
638 deepEqual(prevProps.allowedInstances, this.props.allowedInstances) ||
639 deepEqual(prevProps.blockedInstances, this.props.blockedInstances)
642 this.setState({ siteForm: this.initSiteForm() });
646 federatedInstanceSelect(key: InstanceKey) {
647 const id = `create_site_${key}`;
648 const value = this.state.instance_select[key];
649 const selectedInstances = this.state.siteForm[key];
651 <div className="col-12 col-md-6">
652 <label className="col-form-label" htmlFor={id}>
653 {I18NextService.i18n.t(key)}
655 <div className="d-flex justify-content-between align-items-center">
658 placeholder="instance.tld"
660 className="form-control"
662 onInput={linkEvent(key, this.handleInstanceTextChange)}
663 onKeyUp={linkEvent(key, this.handleInstanceEnterPress)}
667 className="btn btn-sm bg-success ms-2"
668 onClick={linkEvent(key, this.handleAddInstance)}
669 style={"width: 2rem; height: 2rem;"}
671 -1 /* Making this untabble because handling enter key in text input makes keyboard support for this button redundant */
676 classes="icon-inline text-light m-auto d-block position-static"
680 {selectedInstances && selectedInstances.length > 0 && (
681 <ul className="mt-3 list-unstyled w-100 d-flex flex-column justify-content-around align-items-center">
682 {selectedInstances.map(instance => (
685 className="my-1 w-100 w-md-75 d-flex align-items-center justify-content-between"
687 <label className="d-block m-0 w-100 " htmlFor={instance}>
688 <strong>{instance}</strong>
693 style={"width: 2rem; height: 2rem;"}
694 className="btn btn-sm bg-danger"
697 this.handleRemoveInstance,
702 classes="icon-inline text-light m-auto d-block position-static"
713 handleInstanceTextChange(type: InstanceKey, event: any) {
714 this.setState(s => ({
717 ...s.instance_select,
718 [type]: event.target.value,
723 handleInstanceEnterPress(
725 event: InfernoKeyboardEvent<HTMLInputElement>,
727 if (event.code.toLowerCase() === "enter") {
728 event.preventDefault();
730 this.handleAddInstance(key);
734 handleSaveSiteSubmit(i: SiteForm, event: any) {
735 event.preventDefault();
736 const auth = myAuthRequired();
737 i.setState(s => ((s.siteForm.auth = auth), s));
738 i.setState({ submitted: true });
740 const stateSiteForm = i.state.siteForm;
742 let form: EditSite | CreateSite;
744 if (i.props.siteRes.site_view.local_site.site_setup) {
745 form = stateSiteForm;
748 name: stateSiteForm.name ?? "My site",
749 sidebar: stateSiteForm.sidebar,
750 description: stateSiteForm.description,
751 icon: stateSiteForm.icon,
752 banner: stateSiteForm.banner,
753 community_creation_admin_only:
754 stateSiteForm.community_creation_admin_only,
755 enable_nsfw: stateSiteForm.enable_nsfw,
756 enable_downvotes: stateSiteForm.enable_downvotes,
757 application_question: stateSiteForm.application_question,
758 registration_mode: stateSiteForm.registration_mode,
759 require_email_verification: stateSiteForm.require_email_verification,
760 private_instance: stateSiteForm.private_instance,
761 default_theme: stateSiteForm.default_theme,
762 default_post_listing_type: stateSiteForm.default_post_listing_type,
763 application_email_admins: stateSiteForm.application_email_admins,
764 hide_modlog_mod_names: stateSiteForm.hide_modlog_mod_names,
765 legal_information: stateSiteForm.legal_information,
766 slur_filter_regex: stateSiteForm.slur_filter_regex,
767 actor_name_max_length: stateSiteForm.actor_name_max_length,
768 rate_limit_message: stateSiteForm.rate_limit_message,
769 rate_limit_message_per_second:
770 stateSiteForm.rate_limit_message_per_second,
771 rate_limit_comment: stateSiteForm.rate_limit_comment,
772 rate_limit_comment_per_second:
773 stateSiteForm.rate_limit_comment_per_second,
774 rate_limit_image: stateSiteForm.rate_limit_image,
775 rate_limit_image_per_second: stateSiteForm.rate_limit_image_per_second,
776 rate_limit_post: stateSiteForm.rate_limit_post,
777 rate_limit_post_per_second: stateSiteForm.rate_limit_post_per_second,
778 rate_limit_register: stateSiteForm.rate_limit_register,
779 rate_limit_register_per_second:
780 stateSiteForm.rate_limit_register_per_second,
781 rate_limit_search: stateSiteForm.rate_limit_search,
782 rate_limit_search_per_second:
783 stateSiteForm.rate_limit_search_per_second,
784 federation_enabled: stateSiteForm.federation_enabled,
785 federation_debug: stateSiteForm.federation_debug,
786 captcha_enabled: stateSiteForm.captcha_enabled,
787 captcha_difficulty: stateSiteForm.captcha_difficulty,
788 allowed_instances: stateSiteForm.allowed_instances,
789 blocked_instances: stateSiteForm.blocked_instances,
790 discussion_languages: stateSiteForm.discussion_languages,
795 i.props.onSaveSite(form);
798 handleAddInstance(key: InstanceKey) {
799 const instance = this.state.instance_select[key].trim();
801 if (!validInstanceTLD(instance)) {
805 if (!this.state.siteForm[key]?.includes(instance)) {
806 this.setState(s => ({
810 [key]: [...(s.siteForm[key] ?? []), instance],
813 ...s.instance_select,
818 const oppositeKey: InstanceKey =
819 key === "allowed_instances" ? "blocked_instances" : "allowed_instances";
820 if (this.state.siteForm[oppositeKey]?.includes(instance)) {
821 this.handleRemoveInstance({ key: oppositeKey, instance });
826 handleRemoveInstance({
833 this.setState(s => ({
837 [key]: s.siteForm[key]?.filter(i => i !== instance),
842 handleSiteNameChange(i: SiteForm, event: any) {
843 i.state.siteForm.name = event.target.value;
847 handleSiteSidebarChange(val: string) {
848 this.setState(s => ((s.siteForm.sidebar = val), s));
851 handleSiteLegalInfoChange(val: string) {
852 this.setState(s => ((s.siteForm.legal_information = val), s));
855 handleTaglineChange(i: SiteForm, index: number, val: string) {
856 const taglines = i.state.siteForm.taglines;
858 taglines[index] = val;
863 handleDeleteTaglineClick(
866 event: InfernoMouseEvent<HTMLButtonElement>,
868 event.preventDefault();
869 const taglines = i.state.siteForm.taglines;
871 taglines.splice(index, 1);
872 i.state.siteForm.taglines = undefined;
874 i.state.siteForm.taglines = taglines;
879 handleAddTaglineClick(
881 event: InfernoMouseEvent<HTMLButtonElement>,
883 event.preventDefault();
884 if (!i.state.siteForm.taglines) {
885 i.state.siteForm.taglines = [];
887 i.state.siteForm.taglines.push("");
891 handleSiteApplicationQuestionChange(val: string) {
892 this.setState(s => ((s.siteForm.application_question = val), s));
895 handleSiteDescChange(i: SiteForm, event: any) {
896 i.state.siteForm.description = event.target.value;
900 handleSiteEnableNsfwChange(i: SiteForm, event: any) {
901 i.state.siteForm.enable_nsfw = event.target.checked;
905 handleSiteRegistrationModeChange(i: SiteForm, event: any) {
906 i.state.siteForm.registration_mode = event.target.value;
910 handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
911 i.state.siteForm.community_creation_admin_only = event.target.checked;
915 handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
916 i.state.siteForm.enable_downvotes = event.target.checked;
920 handleSiteRequireEmailVerification(i: SiteForm, event: any) {
921 i.state.siteForm.require_email_verification = event.target.checked;
925 handleSiteApplicationEmailAdmins(i: SiteForm, event: any) {
926 i.state.siteForm.application_email_admins = event.target.checked;
930 handleSiteReportsEmailAdmins(i: SiteForm, event: any) {
931 i.state.siteForm.reports_email_admins = event.target.checked;
935 handleSitePrivateInstance(i: SiteForm, event: any) {
936 i.state.siteForm.private_instance = event.target.checked;
940 handleSiteHideModlogModNames(i: SiteForm, event: any) {
941 i.state.siteForm.hide_modlog_mod_names = event.target.checked;
945 handleSiteDefaultTheme(i: SiteForm, event: any) {
946 i.state.siteForm.default_theme = event.target.value;
950 handleIconUpload(url: string) {
951 this.setState(s => ((s.siteForm.icon = url), s));
955 this.setState(s => ((s.siteForm.icon = ""), s));
958 handleBannerUpload(url: string) {
959 this.setState(s => ((s.siteForm.banner = url), s));
962 handleBannerRemove() {
963 this.setState(s => ((s.siteForm.banner = ""), s));
966 handleSiteSlurFilterRegex(i: SiteForm, event: any) {
967 i.setState(s => ((s.siteForm.slur_filter_regex = event.target.value), s));
970 handleSiteActorNameMaxLength(i: SiteForm, event: any) {
972 s => ((s.siteForm.actor_name_max_length = Number(event.target.value)), s),
976 handleSiteFederationEnabled(i: SiteForm, event: any) {
977 i.state.siteForm.federation_enabled = event.target.checked;
981 handleSiteFederationDebug(i: SiteForm, event: any) {
982 i.state.siteForm.federation_debug = event.target.checked;
986 handleSiteCaptchaEnabled(i: SiteForm, event: any) {
987 i.state.siteForm.captcha_enabled = event.target.checked;
991 handleSiteCaptchaDifficulty(i: SiteForm, event: any) {
992 i.setState(s => ((s.siteForm.captcha_difficulty = event.target.value), s));
995 handleDiscussionLanguageChange(val: number[]) {
996 this.setState(s => ((s.siteForm.discussion_languages = val), s));
999 handleDefaultPostListingTypeChange(val: ListingType) {
1000 this.setState(s => ((s.siteForm.default_post_listing_type = val), s));