add SelectOrInput widget to support custom analyzer

This commit is contained in:
TsXor 2023-09-24 23:38:27 +08:00
parent f981c27e00
commit 8e5576db94
8 changed files with 183 additions and 4 deletions

2
js/dist/admin.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,51 @@
import type Mithril from 'mithril';
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';
}
var firstLoadCompletedSet: Set<string> = new Set();
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;
const value = this.setting(setting)();
let settingElement: Mithril.Children;
const firstLoadCompleted = firstLoadCompletedSet.has(entry.setting);
settingElement = (
<SelectOrInput
id={inputId}
aria-describedby={helpTextId}
value={(!firstLoadCompleted && !value) ? defaultValue : value}
options={options}
onchange={this.settings[setting]}
checkboxDescription={checkboxDescription}
{...otherAttrs}
/>
);
if (!firstLoadCompleted) firstLoadCompletedSet.add(entry.setting);
return (
<div className="Form-group">
{label && <label for={inputId}>{label}</label>}
<div id={helpTextId} className="helpText">{help}</div>
{settingElement}
</div>
);
}

View File

@ -0,0 +1,9 @@
import { extend } from 'flarum/common/extend';
import AdminPage, { CommonSettingsItemOptions } from 'flarum/admin/components/AdminPage';
import buildSelectOrInput from './ConfigToComponents/buildSelectOrInput';
export default function() {
extend(AdminPage.prototype, 'customSettingComponents', function (items) {
items.add('select-or-input', buildSelectOrInput.bind(this));
})
}

View File

@ -1,6 +1,9 @@
import app from 'flarum/admin/app';
import extendCustomSettingComponents from './extendCustomSettingComponents';
app.initializers.add('blomstra-search', () => {
extendCustomSettingComponents();
const languages = new Map();
[
'arabic',
@ -69,8 +72,9 @@ app.initializers.add('blomstra-search', () => {
setting: 'blomstra-search.analyzer-language',
label: app.translator.trans('blomstra-search.admin.analyzer.label'),
help: app.translator.trans('blomstra-search.admin.analyzer.help'),
type: 'select',
type: 'select-or-input',
options: Object.fromEntries(languages.entries()),
checkboxDescription: app.translator.trans('blomstra-search.admin.analyzer.custom'),
default: 'english',
})
.registerSetting({

View File

@ -0,0 +1,114 @@
import Mithril from 'mithril';
import classList from 'flarum/common/utils/classList';
import Component, { ComponentAttrs } from 'flarum/common/Component';
import Select from 'flarum/common/components/Select';
import Checkbox, { ICheckboxAttrs } from 'flarum/common/components/Checkbox';
type visibility = 'visible' | 'hidden';
interface ISelectAttrs extends ComponentAttrs {
options: { [k: string]: Mithril.Children };
onchange: (value: string) => void;
value?: string;
disabled?: boolean;
wrapperAttrs?: ComponentAttrs;
}
interface ISubSelectAttrs extends ComponentAttrs {
wrapperAttrs?: ComponentAttrs;
}
export interface ISelectOrInputAttrs<
SelectAttrs extends ISubSelectAttrs = ISubSelectAttrs
> extends ComponentAttrs {
onchange: (value: string) => void;
options: { [k: string]: Mithril.Children };
value?: string;
disabled?: boolean;
checkboxDescription?: string;
selectAttrs?: SelectAttrs;
rawTextInputAttrs?: ComponentAttrs;
}
export default class SelectOrInput<CustomAttrs extends ISelectOrInputAttrs> extends Component<CustomAttrs> {
private onCheckboxChange(checked: boolean, component: Checkbox) {
this.attrs.value = checked ? '' : undefined;
this.attrs.onchange(this.attrs.value!);
m.redraw();
}
private onSelectChange(value: string) {
this.attrs.value = value;
this.attrs.onchange(value);
}
private onInputChange(event: Event) {
const value = (event.target as HTMLInputElement).value;
this.attrs.value = value;
this.attrs.onchange(value);
}
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
const {
class: _class,
className,
onchange,
options,
value: _value,
disabled,
selectAttrs,
rawTextInputAttrs,
...domAttrs
} = this.attrs;
var useinput: boolean; var value: string;
const selectOptionValues = Object.keys(options);
if (typeof _value === 'undefined') {
value = selectOptionValues[0];
this.attrs.value = value;
useinput = false;
} else {
value = _value;
useinput = !(selectOptionValues.indexOf(value!) > -1);
}
const {
class: inputClass,
className: inputClassName,
...otherInputAttrs
} = rawTextInputAttrs ?? {};
return (
<div
className={classList('SelectOrInput', className, _class)}
{...domAttrs}
>
{this.attrs.checkboxDescription ?? ''}
<div style='display: inline-block;'>
<Checkbox
state={useinput}
onchange={this.onCheckboxChange.bind(this)}
/>
</div>
<div style='display: inline-block;'>
{!useinput
? <Select
options={options}
onchange={this.onSelectChange.bind(this)}
disabled={disabled}
value={value}
{...selectAttrs}
/>
: <input
className={classList('FormControl', inputClassName, inputClass)}
type='text'
onchange={this.onInputChange.bind(this)}
disabled={disabled}
value={value}
{...otherInputAttrs}
/>
}
</div>
</div>
);
}
}

View File

@ -9,6 +9,7 @@ blomstra-search:
help: |
The analyzer makes search understand stop words and undertakes language
specific improvements for indexing.
custom: Use custom analyzer
search-discussion-subjects: Search inside discussion titles
search-post-bodies: Search inside comments
match-sentences: Match search term against full sentence