aboutsummaryrefslogblamecommitdiff
path: root/src/settings/components/index.tsx
blob: 2e2ff522de7dd68336c45e65deecacd137973a78 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                      
                                       
                                     




                                                                 
                     






                                                          
 




















                                 
                               
                                                         
 
                                                     
                                  
 



                         
                                                        
                       
                                               
   
                                        
            
                                      



                                                      

                                         



                                                     

                                    



                                                        

                                            



                                                        

                                     




                                                         
                   
            
   
                                                           
            
                 








                                                  
   
            
                      
                                                 
                                       
                                                       
                                              
                                                                         
     
            
                 
                                    







                                                    
 








                                                    

      
                                       
                                  





                                                                      
                                  
                                                              
                                  


                                                  
                                           
                                  
                                
                                                                            



                                                  
                                  
                                
                                                                  
                                  
                                                  
   
                                          
                                  
                                
                                             
                                                  
   
 
                                            
                                   


                                                                    
                  
                                                     
                                                        
               
                           
               
                          
                                                                        
                  
     
   
 
          
                                                               

                                                                  
   
 
                                                            
                                                           
import React from "react";
import { connect } from "react-redux";
import styled from "styled-components";
import TextArea from "./ui/TextArea";
import Radio from "./ui/Radio";
import SearchForm from "./form/SearchForm";
import KeymapsForm from "./form/KeymapsForm";
import BlacklistForm from "./form/BlacklistForm";
import PropertiesForm from "./form/PropertiesForm";
import PartialBlacklistForm from "./form/PartialBlacklistForm";
import * as settingActions from "../../settings/actions/setting";
import SettingData, {
  FormKeymaps,
  FormSearch,
  FormSettings,
  JSONTextSettings,
} from "../../shared/SettingData";
import { State as AppState } from "../reducers/setting";
import Properties from "../../shared/settings/Properties";
import Blacklist from "../../shared/settings/Blacklist";

const Container = styled.form`
  padding: 2px;
  font-family: system-ui;
`;

const Fieldset = styled.fieldset`
  margin: 0;
  padding: 0;
  border: none;
  margin-top: 1rem;

  &:first-of-type {
    margin-top: 1rem;
  }
`;

const Legend = styled.legend`
  font-size: 1.5rem;
  padding: 0.5rem 0;
  font-weight: bold;
`;

const DO_YOU_WANT_TO_CONTINUE =
  "Some settings in JSON can be lost when migrating.  " +
  "Do you want to continue?";

type StateProps = ReturnType<typeof mapStateToProps>;
interface DispatchProps {
  dispatch: (action: any) => void;
}
type Props = StateProps &
  DispatchProps & {
    // FIXME
    store: any;
  };

class SettingsComponent extends React.Component<Props> {
  componentDidMount() {
    this.props.dispatch(settingActions.load());
  }

  renderFormFields(form: FormSettings) {
    return (
      <div>
        <Fieldset>
          <Legend>Keybindings</Legend>
          <KeymapsForm
            value={form.keymaps}
            onChange={this.bindKeymapsForm.bind(this)}
            onBlur={this.save.bind(this)}
          />
        </Fieldset>
        <Fieldset>
          <Legend>Search Engines</Legend>
          <SearchForm
            value={form.search}
            onChange={this.bindSearchForm.bind(this)}
            onBlur={this.save.bind(this)}
          />
        </Fieldset>
        <Fieldset>
          <Legend>Blacklist</Legend>
          <BlacklistForm
            value={form.blacklist}
            onChange={this.bindBlacklistForm.bind(this)}
            onBlur={this.save.bind(this)}
          />
        </Fieldset>
        <Fieldset>
          <Legend>Partial blacklist</Legend>
          <PartialBlacklistForm
            value={form.blacklist}
            onChange={this.bindBlacklistForm.bind(this)}
            onBlur={this.save.bind(this)}
          />
        </Fieldset>
        <Fieldset>
          <Legend>Properties</Legend>
          <PropertiesForm
            types={Properties.types()}
            value={form.properties.toJSON()}
            onChange={this.bindPropertiesForm.bind(this)}
            onBlur={this.save.bind(this)}
          />
        </Fieldset>
      </div>
    );
  }

  renderJsonFields(json: JSONTextSettings, error: string) {
    return (
      <div>
        <TextArea
          name="json"
          label="Plain JSON"
          spellCheck={false}
          error={error}
          onValueChange={this.bindJson.bind(this)}
          onBlur={this.save.bind(this)}
          value={json.toJSONText()}
        />
      </div>
    );
  }

  render() {
    let fields = null;
    const disabled = this.props.error.length > 0;
    if (this.props.source === "form") {
      fields = this.renderFormFields(this.props.form!);
    } else if (this.props.source === "json") {
      fields = this.renderJsonFields(this.props.json!, this.props.error);
    }
    return (
      <Container>
        <h1>Configure Vim-Vixen</h1>
        <Radio
          id="setting-source-form"
          name="source"
          label="Use form"
          checked={this.props.source === "form"}
          value="form"
          onValueChange={this.bindSource.bind(this)}
          disabled={disabled}
        />

        <Radio
          name="source"
          label="Use plain JSON"
          checked={this.props.source === "json"}
          value="json"
          onValueChange={this.bindSource.bind(this)}
          disabled={disabled}
        />
        {fields}
      </Container>
    );
  }

  bindKeymapsForm(value: FormKeymaps) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithKeymaps(value),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindSearchForm(value: any) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithSearch(
        FormSearch.fromJSON(value)
      ),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindBlacklistForm(blacklist: Blacklist) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithBlacklist(blacklist),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindPropertiesForm(value: any) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithProperties(
        Properties.fromJSON(value)
      ),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindJson(_name: string, value: string) {
    const data = new SettingData({
      source: this.props.source,
      json: JSONTextSettings.fromText(value),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindSource(_name: string, value: string) {
    const from = this.props.source;
    if (from === "form" && value === "json") {
      this.props.dispatch(
        settingActions.switchToJson(this.props.form as FormSettings)
      );
      this.save();
    } else if (from === "json" && value === "form") {
      const b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
      if (!b) {
        this.forceUpdate();
        return;
      }
      this.props.dispatch(
        settingActions.switchToForm(this.props.json as JSONTextSettings)
      );
      this.save();
    }
  }

  save() {
    const { source, json, form } = this.props.store.getState();
    this.props.dispatch(
      settingActions.save(new SettingData({ source, json, form }))
    );
  }
}

const mapStateToProps = (state: AppState) => ({ ...state });

export default connect(mapStateToProps)(SettingsComponent);