<commit_before>import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import * as dialog from './dialog';
import { prop, Prop } from 'common';
import { bind, bindSubmit } from '../util';
import { StudyData } from './interfaces';
import { MaybeVNodes } from '../interfaces';
import RelayCtrl from './relay/relayCtrl';

export interface StudyFormCtrl {
  open: Prop<boolean>;
  openIfNew(): void;
  save(data: FormData, isNew: boolean): void;
  getData(): StudyData;
  isNew(): boolean;
  redraw(): void;
  relay?: RelayCtrl;
}

interface FormData {
  [key: string]: string;
}

interface Select {
  key: string;
  name: string;
  choices: Choice[];
  selected: string;
}
type Choice = [string, string];

const visibilityChoices: Choice[] = [
  ['public', 'Public'],
  ['unlisted', 'Unlisted'],
  ['private', 'Invite only']
];
const userSelectionChoices: Choice[] = [
  ['nobody', 'Nobody'],
  ['owner', 'Only me'],
  ['contributor', 'Contributors'],
  ['member', 'Members'],
  ['everyone', 'Everyone']
];

function select(s: Select): MaybeVNodes {
  return [
    h('select#study-' + s.key, s.choices.map(function(o) {
      return h('option', {
        attrs: {
          value: o[0],
          selected: s.selected === o[0]
        }
      }, o[1]);
    })),
    h('label.control-label', {
      attrs: { for: 'study-' + s.key }
    }, s.name),
    h('i.bar')
  ];
};

export function ctrl(save: (data: FormData, isNew: boolean) => void, getData: () => StudyData, redraw: () => void, relay?: RelayCtrl): StudyFormCtrl {

  const initAt = Date.now();

  function isNew(): boolean {
    const d = getData();
    return d.from === 'scratch' && !!d.isNew && Date.now() - initAt < 9000;
  }

  const open = prop(false);

  return {
    open,
    openIfNew() {
      if (isNew()) open(true);
    },
    save(data: FormData, isNew: boolean) {
      save(data, isNew);
      open(false);
    },
    getData,
    isNew,
    redraw,
    relay
  };
}

export function view(ctrl: StudyFormCtrl): VNode {
  const data = ctrl.getData();
  const isNew = ctrl.isNew();
  const updateName = function(vnode, isUpdate) {
    const el = vnode.elm as HTMLInputElement;
    if (!isUpdate && !el.value) {
      el.value = data.name;
      if (isNew) el.select();
      el.focus();
    }
  }
  return dialog.form({
    class: 'study-edit',
    onClose: function() {
      ctrl.open(false);
      ctrl.redraw();
    },
    content: [
      h('h2', ctrl.relay ? 'Configure live broadcast' : (isNew ? 'Create' : 'Edit') + ' study'),
      h('form.material.form.align-left', {
        hook: bindSubmit(e => {
          const obj: FormData = {};
          'name visibility computer explorer cloneable chat sticky'.split(' ').forEach(n => {
            const el = ((e.target as HTMLElement).querySelector('#study-' + n) as HTMLInputElement);
            if (el) obj[n] = el.value;
          });
          ctrl.save(obj, isNew);
        }, ctrl.redraw)
      }, [
        h('div.form-group', [
          h('input#study-name', {
            attrs: {
              minlength: 3,
              maxlength: 100,
              type: ctrl.relay ? 'hidden' : 'text'
            },
            hook: {
              insert: vnode => updateName(vnode, false),
              postpatch: (_, vnode) => updateName(vnode, true)
            }
          }),
          h('label.control-label', { attrs: { 'for': 'study-name' } }, 'Name'),
          h('i.bar')
        ]),
        h('div', [
          h('div.form-group.half', select({
            key: 'visibility',
            name: 'Visibility',
            choices: visibilityChoices,
            selected: data.visibility<commit_msg>disallow study name edition in relay mode<commit_after>import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import * as dialog from './dialog';
import { prop, Prop } from 'common';
import { bind, bindSubmit } from '../util';
import { StudyData } from './interfaces';
import { MaybeVNodes } from '../interfaces';
import RelayCtrl from './relay/relayCtrl';

export interface StudyFormCtrl {
  open: Prop<boolean>;
  openIfNew(): void;
  save(data: FormData, isNew: boolean): void;
  getData(): StudyData;
  isNew(): boolean;
  redraw(): void;
  relay?: RelayCtrl;
}

interface FormData {
  [key: string]: string;
}

interface Select {
  key: string;
  name: string;
  choices: Choice[];
  selected: string;
}
type Choice = [string, string];

const visibilityChoices: Choice[] = [
  ['public', 'Public'],
  ['unlisted', 'Unlisted'],
  ['private', 'Invite only']
];
const userSelectionChoices: Choice[] = [
  ['nobody', 'Nobody'],
  ['owner', 'Only me'],
  ['contributor', 'Contributors'],
  ['member', 'Members'],
  ['everyone', 'Everyone']
];

function select(s: Select): MaybeVNodes {
  return [
    h('select#study-' + s.key, s.choices.map(function(o) {
      return h('option', {
        attrs: {
          value: o[0],
          selected: s.selected === o[0]
        }
      }, o[1]);
    })),
    h('label.control-label', {
      attrs: { for: 'study-' + s.key }
    }, s.name),
    h('i.bar')
  ];
};

export function ctrl(save: (data: FormData, isNew: boolean) => void, getData: () => StudyData, redraw: () => void, relay?: RelayCtrl): StudyFormCtrl {

  const initAt = Date.now();

  function isNew(): boolean {
    const d = getData();
    return d.from === 'scratch' && !!d.isNew && Date.now() - initAt < 9000;
  }

  const open = prop(false);

  return {
    open,
    openIfNew() {
      if (isNew()) open(true);
    },
    save(data: FormData, isNew: boolean) {
      save(data, isNew);
      open(false);
    },
    getData,
    isNew,
    redraw,
    relay
  };
}

export function view(ctrl: StudyFormCtrl): VNode {
  const data = ctrl.getData();
  const isNew = ctrl.isNew();
  const updateName = function(vnode, isUpdate) {
    const el = vnode.elm as HTMLInputElement;
    if (!isUpdate && !el.value) {
      el.value = data.name;
      if (isNew) el.select();
      el.focus();
    }
  }
  return dialog.form({
    class: 'study-edit',
    onClose: function() {
      ctrl.open(false);
      ctrl.redraw();
    },
    content: [
      h('h2', ctrl.relay ? 'Configure live broadcast' : (isNew ? 'Create' : 'Edit') + ' study'),
      h('form.material.form.align-left', {
        hook: bindSubmit(e => {
          const obj: FormData = {};
          'name visibility computer explorer cloneable chat sticky'.split(' ').forEach(n => {
            const el = ((e.target as HTMLElement).querySelector('#study-' + n) as HTMLInputElement);
            if (el) obj[n] = el.value;
          });
          ctrl.save(obj, isNew);
        }, ctrl.redraw)
      }, [
        h('div.form-group' + (ctrl.relay ? '.none' : ''), [
          h('input#study-name', {
            attrs: {
              minlength: 3,
              maxlength: 100
            },
            hook: {
              insert: vnode => updateName(vnode, false),
              postpatch: (_, vnode) => updateName(vnode, true)
            }
          }),
          h('label.control-label', { attrs: { 'for': 'study-name' } }, 'Name'),
          h('i.bar')
        ]),
        h('div', [
          h('div.form-group.half', select({
            key: 'visibility',
            name: 'Visibility',
            choices: visibilityChoices,
            selected: data.visibility
{'fraction_non_alphanumeric': 0.17355598138516287, 'fraction_numerical': 0.0032849712565015056, 'mean_word_length': 2.395446096654275, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6254882', 'n_tokens_mistral': 2410, 'n_tokens_neox': 2361, 'n_words': 575}