<commit_before>/* @flow */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import { stopPropagation } from '../../../utils/common';
import { getFirstIcon } from '../../../utils/toolbar';
import Option from '../../../components/Option';
import { Dropdown, DropdownOption } from '../../../components/Dropdown';
import './styles.css';

class LayoutComponent extends Component {
  static propTypes = {
    expanded: PropTypes.bool,
    doExpand: PropTypes.func,
    doCollapse: PropTypes.func,
    onExpandEvent: PropTypes.func,
    config: PropTypes.object,
    onChange: PropTypes.func,
    currentState: PropTypes.object,
    translations: PropTypes.object,
  };

  state: Object = {
    showModal: false,
    linkTarget: '',
    linkTitle: '',
    linkTargetOption: this.props.config.defaultTargetOption,
  };

  componentWillReceiveProps(props) {
    if (this.props.expanded && !props.expanded) {
      this.setState({
        showModal: false,
        linkTarget: '',
        linkTitle: '',
        linkTargetOption: this.props.config.defaultTargetOption,
      });
    }
  }

  removeLink: Function = (): void => {
    const { onChange } = this.props;
    onChange('unlink');
  };

  addLink: Function = (): void => {
    const { onChange } = this.props;
    const { linkTitle, linkTarget, linkTargetOption } = this.state;
    onChange('link', linkTitle, linkTarget, linkTargetOption);
  };

  updateValue: Function = (event: Object): void => {
    this.setState({
      [`${event.target.name}`]: event.target.value,
    });
  };

  updateTargetOption: Function = (event: Object): void => {
    this.setState({
      linkTargetOption: event.target.checked ? '_blank' : '_self',
    });
  };

  hideModal: Function = (): void => {
    this.setState({
      showModal: false,
    });
  };

  signalExpandShowModal = () => {
    const { onExpandEvent, currentState: { link, selectionText } } = this.props;
    const { linkTargetOption } = this.state;
    onExpandEvent();
    this.setState({
      showModal: true,
      linkTarget: link && link.target,
      linkTargetOption: (link && link.targetOption) || linkTargetOption,
      linkTitle: (link && link.title) || selectionText,
    });
  }

  forceExpandAndShowModal: Function = (): void => {
    const { doExpand, currentState: { link, selectionText } } = this.props;
    const { linkTargetOption } = this.state;
    doExpand();
    this.setState({
      showModal: true,
      linkTarget: link && link.target,
      linkTargetOption: (link && link.targetOption) || linkTargetOption,
      linkTitle: (link && link.title) || selectionText,
    });
  }

  renderAddLinkModal() {
    const { config: { popupClassName }, doCollapse, translations } = this.props;
    const { linkTitle, linkTarget, linkTargetOption } = this.state;
    return (

          {translations['components.controls.link.linkTitle']}

        <input
          id="linkTitle"
          className="rdw-link-modal-input"
          onChange={this.updateValue}
          onBlur={this.updateValue}
          name="linkTitle"
          value={linkTitle}
        />

          {translations['components.controls.link.linkTarget']}

        <input
          id="linkTarget"
          className="rdw-link-modal-input"
          onChange={this.updateValue}
          onBlur={this.updateValue}
          name="linkTarget"
          value={linkTarget}
        />

          <input
            id="openLinkInNewWindow"
            type="checkbox"
            defaultChecked={linkTargetOption === '_blank'}
            value="_blank"
            onChange={this.updateTargetOption}
          />
          {translations['components.controls.link.linkTargetOption']}

          <button
            className="rdw-link-modal-btn"
            onClick={this.addLink}
            disabled={!linkTarget || !linkTitle}
          >
            {translations['generic.add']}
          </button>
          <button
            className="rdw-link-modal-btn"
            onClick={doCollapse}
          >
            {translations['generic.cancel']}
          </button>

    );
  }

  renderInFlatList(): Object {
    const {
      config: { options, link, unlink, className },
      currentState,
      expanded,
      translations,
    } = this.props;
    const { showModal } = this.state;
    return (

        {options.indexOf('link') >= 0 && <Option
          value="unordered-list-item"
          className={classNames(link.className)}
          onClick={this.signalExpandShowModal}
          aria-haspopup="true"
          aria-expanded={showModal}
          title={link.title || translations['components.controls.link.link']}
        >

        </Option>}
        {options.indexOf('unlink') >= 0 && <Option
          disabled={!currentState.link}
          value="ordered-list-item"
          className={classNames(unlink.className)}
          onClick={this.removeLink}
          title={unlink.title || translations['components.controls.link.unlink']}
        >

        </Option>}
        {expanded && showModal ? this.renderAddLinkModal() : undefined}

    );
  }

  renderInDropDown(): Object {
    const {
      expanded,
      onExpandEvent,
      doCollapse,
      doExpand,
      onChange,
      config,
      currentState,
      translations,
    } = this.props;
    const { options, link, unlink, className, dropdownClassName, title } = config;
    const { showModal } = this.state;
    return (

        <Dropdown
          className={classNames('rdw-link-dropdown', className)}
          optionWrapperClassName={classNames(dropdownClassName)}
          onChange={onChange}
          expanded={expanded && !showModal}
          doExpand={doExpand}
          doCollapse={doCollapse}
          onExpandEvent={onExpandEvent}
        >

          {options.indexOf('link') >= 0 && <DropdownOption
            onClick={this.forceExpandAndShowModal}
            className={classNames('rdw-link-dropdownoption', link.className)}
            title={link.title || translations['components.controls.link.link']}
          >

          </DropdownOption>}
          {options.indexOf('unlink') >= 0 && <DropdownOption
            onClick={this.removeLink}
            disabled={!currentState.link}
            className={classNames('rdw-link-dropdownoption', unlink.className)}
            title={unlink.title || translations['components.controls.link.unlink']}
          >

          </DropdownOption>}
        </Dropdown>
        {expanded && showModal ? this.renderAddLinkModal() : undefined}

    );
  }

  render(): Object {
    const { config: { inDropdown } } = this.props;
    if (inDropdown) {
      return this.renderInDropDown();
    }
    return this.renderInFlatList();
  }
}

export default LayoutComponent;
<commit_msg>Fix warning that comes when changing link target<commit_after>/* @flow */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import { stopPropagation } from '../../../utils/common';
import { getFirstIcon } from '../../../utils/toolbar';
import Option from '../../../components/Option';
import { Dropdown, DropdownOption } from '../../../components/Dropdown';
import './styles.css';

class LayoutComponent extends Component {
  static propTypes = {
    expanded: PropTypes.bool,
    doExpand: PropTypes.func,
    doCollapse: PropTypes.func,
    onExpandEvent: PropTypes.func,
    config: PropTypes.object,
    onChange: PropTypes.func,
    currentState: PropTypes.object,
    translations: PropTypes.object,
  };

  state: Object = {
    showModal: false,
    linkTarget: '',
    linkTitle: '',
    linkTargetOption: this.props.config.defaultTargetOption,
  };

  componentWillReceiveProps(props) {
    if (this.props.expanded && !props.expanded) {
      this.setState({
        showModal: false,
        linkTarget: '',
        linkTitle: '',
        linkTargetOption: this.props.config.defaultTargetOption,
      });
    }
  }

  removeLink: Function = (): void => {
    const { onChange } = this.props;
    onChange('unlink');
  };

  addLink: Function = (): void => {
    const { onChange } = this.props;
    const { linkTitle, linkTarget, linkTargetOption } = this.state;
    onChange('link', linkTitle, linkTarget, linkTargetOption);
  };

  updateValue: Function = (event: Object): void => {
    this.setState({
      [`${event.target.name}`]: event.target.value,
    });
  };

  updateTargetOption: Function = (event: Object): void => {
    this.setState({
      linkTargetOption: event.target.checked ? '_blank' : '_self',
    });
  };

  hideModal: Function = (): void => {
    this.setState({
      showModal: false,
    });
  };

  signalExpandShowModal = () => {
    const { onExpandEvent, currentState: { link, selectionText } } = this.props;
    const { linkTargetOption } = this.state;
    onExpandEvent();
    this.setState({
      showModal: true,
      linkTarget: (link && link.target) || '',
      linkTargetOption: (link && link.targetOption) || linkTargetOption,
      linkTitle: (link && link.title) || selectionText,
    });
  }

  forceExpandAndShowModal: Function = (): void => {
    const { doExpand, currentState: { link, selectionText } } = this.props;
    const { linkTargetOption } = this.state;
    doExpand();
    this.setState({
      showModal: true,
      linkTarget: link && link.target,
      linkTargetOption: (link && link.targetOption) || linkTargetOption,
      linkTitle: (link && link.title) || selectionText,
    });
  }

  renderAddLinkModal() {
    const { config: { popupClassName }, doCollapse, translations } = this.props;
    const { linkTitle, linkTarget, linkTargetOption } = this.state;
    return (

          {translations['components.controls.link.linkTitle']}

        <input
          id="linkTitle"
          className="rdw-link-modal-input"
          onChange={this.updateValue}
          onBlur={this.updateValue}
          name="linkTitle"
          value={linkTitle}
        />

          {translations['components.controls.link.linkTarget']}

        <input
          id="linkTarget"
          className="rdw-link-modal-input"
          onChange={this.updateValue}
          onBlur={this.updateValue}
          name="linkTarget"
          value={linkTarget}
        />

          <input
            id="openLinkInNewWindow"
            type="checkbox"
            defaultChecked={linkTargetOption === '_blank'}
            value="_blank"
            onChange={this.updateTargetOption}
          />
          {translations['components.controls.link.linkTargetOption']}

          <button
            className="rdw-link-modal-btn"
            onClick={this.addLink}
            disabled={!linkTarget || !linkTitle}
          >
            {translations['generic.add']}
          </button>
          <button
            className="rdw-link-modal-btn"
            onClick={doCollapse}
          >
            {translations['generic.cancel']}
          </button>

    );
  }

  renderInFlatList(): Object {
    const {
      config: { options, link, unlink, className },
      currentState,
      expanded,
      translations,
    } = this.props;
    const { showModal } = this.state;
    return (

        {options.indexOf('link') >= 0 && <Option
          value="unordered-list-item"
          className={classNames(link.className)}
          onClick={this.signalExpandShowModal}
          aria-haspopup="true"
          aria-expanded={showModal}
          title={link.title || translations['components.controls.link.link']}
        >

        </Option>}
        {options.indexOf('unlink') >= 0 && <Option
          disabled={!currentState.link}
          value="ordered-list-item"
          className={classNames(unlink.className)}
          onClick={this.removeLink}
          title={unlink.title || translations['components.controls.link.unlink']}
        >

        </Option>}
        {expanded && showModal ? this.renderAddLinkModal() : undefined}

    );
  }

  renderInDropDown(): Object {
    const {
      expanded,
      onExpandEvent,
      doCollapse,
      doExpand,
      onChange,
      config,
      currentState,
      translations,
    } = this.props;
    const { options, link, unlink, className, dropdownClassName, title } = config;
    const { showModal } = this.state;
    return (

        <Dropdown
          className={classNames('rdw-link-dropdown', className)}
          optionWrapperClassName={classNames(dropdownClassName)}
          onChange={onChange}
          expanded={expanded && !showModal}
          doExpand={doExpand}
          doCollapse={doCollapse}
          onExpandEvent={onExpandEvent}
        >

          {options.indexOf('link') >= 0 && <DropdownOption
            onClick={this.forceExpandAndShowModal}
            className={classNames('rdw-link-dropdownoption', link.className)}
            title={link.title || translations['components.controls.link.link']}
          >

          </DropdownOption>}
          {options.indexOf('unlink') >= 0 && <DropdownOption
            onClick={this.removeLink}
            disabled={!currentState.link}
            className={classNames('rdw-link-dropdownoption', unlink.className)}
            title={unlink.title || translations['components.controls.link.unlink']}
          >

          </DropdownOption>}
        </Dropdown>
        {expanded && showModal ? this.renderAddLinkModal() : undefined}

    );
  }

  render(): Object {
    const { config: { inDropdown } } = this.props;
    if (inDropdown) {
      return this.renderInDropDown();
    }
    return this.renderInFlatList();
  }
}

export default LayoutComponent;
<|endoftext|>


<commit_before>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const cropBtn = document.querySelector('#crop');
  const cropBtnImg = document.querySelector('#crop-btn-img');
  const fps = document.querySelector('#fps');
  const fpsInputWrapper = document.querySelector('.fps-input-wrapper');
  const options = document.querySelector('#options');
  const recordBtn = document.querySelector('#record');
  const settingsTitleWrapper = document.querySelector('.settings-title-wrapper');
  const size = document.querySelector('#size');
  const time = document.querySelector('#time');
  const title = document.querySelector('.title');

  const spinnerFrames = ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'];
  let currentSpinnerFrame = 0;

  let recording = false;

  let monitoringIntervalId;
  let spinnerIntervalId;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        size.innerText = fileSize(stats.size).human('si');
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startSpinner() {
    spinnerIntervalId = setInterval(() => {
      const frame = spinnerFrames[currentSpinnerFrame];
      currentSpinnerFrame = ++currentSpinnerFrame % spinnerFrames.length;

      title.innerText = `Starting ${frame}`;
    }, 100);
  }

  function stopSpinner() {
    clearInterval(spinnerIntervalId);
  }

  function startRecording() {
    const past = Date.now();
    startSpinner();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed
    aperture.startRecording({fps: fps.value})
      .then(filePath => {
        stopSpinner();
        title.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        recording = false;
        console.error(err);
        stopSpinner();
        title.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        stopMonitoring();
        title.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  recordBtn.onclick = () => {
    if (recording) {
      stopRecording();
    } else {
      startRecording();
    }
  };

  settingsTitleWrapper.onclick = function () {
    const arrow = this.children[1];
    const settings = document.querySelector('.settings');

    arrow.classList.toggle('up');
    arrow.classList.toggle('down');

    settings.classList.toggle('hidden');
    setWindowSize();

    window.arrow = arrow;
  };

  fps.onkeyup = function () {
    if (!/^[0-9]{1,2}$/.test(this.value) && this.value.trim() !== '') {
      this.value = 30;
    } else if (this.value < 0) {
      this.value = 0;
    } else if (this.value > 60) {
      this.value = 60;
    }
  };

  fps.onblur = function () {
    if (this.value.trim() === '' || this.value === '0') {
      this.value = 30;
    }
  };

  options.onclick = () => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
  };

  fpsInputWrapper.onclick = () => {
    fps.focus();
    fps.value = fps.value; // move the carret to the end
  };

  cropBtn.onclick = function () {
    if (this.classList.contains('active')) { // is active (green)
      cropBtnImg.src = '../static/crop.png';
      cropBtnImg.srcset = '../static/crop.png 1x, ../static/crop@2x.png 2x';
    } else { // is not active (gray)
      cropBtnImg.src = '../static/crop-active.png';
      cropBtnImg.srcset = '../static/crop-active.png 1x, ../static/crop-active@2x.png 2x';
    }
    this.classList.toggle('active');
  };
});

window.addEventListener('load', setWindowSize);
<commit_msg>Open the cropper window when the crop icon is clicked<commit_after>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const cropBtn = document.querySelector('#crop');
  const cropBtnImg = document.querySelector('#crop-btn-img');
  const fps = document.querySelector('#fps');
  const fpsInputWrapper = document.querySelector('.fps-input-wrapper');
  const options = document.querySelector('#options');
  const recordBtn = document.querySelector('#record');
  const settingsTitleWrapper = document.querySelector('.settings-title-wrapper');
  const size = document.querySelector('#size');
  const time = document.querySelector('#time');
  const title = document.querySelector('.title');

  const spinnerFrames = ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'];
  let currentSpinnerFrame = 0;

  let recording = false;

  let monitoringIntervalId;
  let spinnerIntervalId;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        size.innerText = fileSize(stats.size).human('si');
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startSpinner() {
    spinnerIntervalId = setInterval(() => {
      const frame = spinnerFrames[currentSpinnerFrame];
      currentSpinnerFrame = ++currentSpinnerFrame % spinnerFrames.length;

      title.innerText = `Starting ${frame}`;
    }, 100);
  }

  function stopSpinner() {
    clearInterval(spinnerIntervalId);
  }

  function startRecording() {
    const past = Date.now();
    startSpinner();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed
    aperture.startRecording({fps: fps.value})
      .then(filePath => {
        stopSpinner();
        title.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        recording = false;
        console.error(err);
        stopSpinner();
        title.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        stopMonitoring();
        title.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  recordBtn.onclick = () => {
    if (recording) {
      stopRecording();
    } else {
      startRecording();
    }
  };

  settingsTitleWrapper.onclick = function () {
    const arrow = this.children[1];
    const settings = document.querySelector('.settings');

    arrow.classList.toggle('up');
    arrow.classList.toggle('down');

    settings.classList.toggle('hidden');
    setWindowSize();

    window.arrow = arrow;
  };

  fps.onkeyup = function () {
    if (!/^[0-9]{1,2}$/.test(this.value) && this.value.trim() !== '') {
      this.value = 30;
    } else if (this.value < 0) {
      this.value = 0;
    } else if (this.value > 60) {
      this.value = 60;
    }
  };

  fps.onblur = function () {
    if (this.value.trim() === '' || this.value === '0') {
      this.value = 30;
    }
  };

  options.onclick = () => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
  };

  fpsInputWrapper.onclick = () => {
    fps.focus();
    fps.value = fps.value; // move the carret to the end
  };

  cropBtn.onclick = function () {
    if (this.classList.contains('active')) { // is active (green)
      cropBtnImg.src = '../static/crop.png';
      cropBtnImg.srcset = '../static/crop.png 1x, ../static/crop@2x.png 2x';
    } else { // is not active (gray)
      cropBtnImg.src = '../static/crop-active.png';
      cropBtnImg.srcset = '../static/crop-active.png 1x, ../static/crop-active@2x.png 2x';
    }
    ipcRenderer.send('open-cropper-window');
    this.classList.toggle('active');
  };
});

window.addEventListener('load', setWindowSize);
<|endoftext|>


<commit_before>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const cropBtn = document.querySelector('#crop');
  const cropBtnImg = document.querySelector('#crop-btn-img');
  const fps = document.querySelector('#fps');
  const fpsInputWrapper = document.querySelector('.fps-input-wrapper');
  const options = document.querySelector('#options');
  const recordBtn = document.querySelector('#record');
  const settingsTitleWrapper = document.querySelector('.settings-title-wrapper');
  const size = document.querySelector('#size');
  const time = document.querySelector('#time');
  const title = document.querySelector('.title');

  const spinnerFrames = ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'];
  let currentSpinnerFrame = 0;

  let recording = false;

  let monitoringIntervalId;
  let spinnerIntervalId;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        size.innerText = fileSize(stats.size).human('si');
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startSpinner() {
    spinnerIntervalId = setInterval(() => {
      const frame = spinnerFrames[currentSpinnerFrame];
      currentSpinnerFrame = ++currentSpinnerFrame % spinnerFrames.length;

      title.innerText = `Starting ${frame}`;
    }, 100);
  }

  function stopSpinner() {
    clearInterval(spinnerIntervalId);
  }

  function startRecording() {
    const past = Date.now();
    startSpinner();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed
    aperture.startRecording({fps: fps.value})
      .then(filePath => {
        stopSpinner();
        title.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        recording = false;
        console.error(err);
        stopSpinner();
        title.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        stopMonitoring();
        title.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  recordBtn.onclick = () => {
    if (recording) {
      stopRecording();
    } else {
      startRecording();
    }
  };

  settingsTitleWrapper.onclick = function () {
    const arrow = this.children[1];
    const settings = document.querySelector('.settings');

    arrow.classList.toggle('up');
    arrow.classList.toggle('down');

    settings.classList.toggle('hidden');
    setWindowSize();

    window.arrow = arrow;
  };

  fps.onkeyup = function () {
    if (!/^[0-9]{1,2}$/.test(this.value) && this.value.trim() !== '') {
      this.value = 30;
    } else if (this.value < 0) {
      this.value = 0;
    } else if (this.value > 60) {
      this.value = 60;
    }
  };

  fps.onblur = function () {
    if (this.value.trim() === '' || this.value === '0') {
      this.value = 30;
    }
  };

  options.onclick = () => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
  };

  fpsInputWrapper.onclick = () => {
    fps.focus();
    fps.value = fps.value; // move the carret to the end
  };

  cropBtn.onclick = function () {
    ipcRenderer.send('open-cropper-window');
  };
});

window.addEventListener('load', setWindowSize);
<commit_msg>Remove useless var<commit_after>const fs = require('fs');

const aperture = require('aperture.js')();
const fileSize = require('file-size');
const {ipcRenderer} = require('electron');
const moment = require('moment');

function setWindowSize() {
  const width = document.documentElement.scrollWidth;
  const height = document.documentElement.scrollHeight;
  ipcRenderer.send('set-window-size', {width, height});
}

document.addEventListener('DOMContentLoaded', () => {
  const cropBtn = document.querySelector('#crop');
  const fps = document.querySelector('#fps');
  const fpsInputWrapper = document.querySelector('.fps-input-wrapper');
  const options = document.querySelector('#options');
  const recordBtn = document.querySelector('#record');
  const settingsTitleWrapper = document.querySelector('.settings-title-wrapper');
  const size = document.querySelector('#size');
  const time = document.querySelector('#time');
  const title = document.querySelector('.title');

  const spinnerFrames = ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'];
  let currentSpinnerFrame = 0;

  let recording = false;

  let monitoringIntervalId;
  let spinnerIntervalId;

  function startMonitoringElapsedTimeAndSize(filePath) {
    const startedAt = moment();

    monitoringIntervalId = setInterval(() => {
      // TODO: split this into two intervals: one for time (1000ms)
      // and one for size (500ms)
      const now = moment();

      const elapsed = moment.utc(now.diff(startedAt)).format('mm:ss');
      time.innerText = elapsed;

      fs.stat(filePath, (err, stats) => {
        size.innerText = fileSize(stats.size).human('si');
      });
    }, 500);
  }

  function stopMonitoring() {
    clearInterval(monitoringIntervalId);
  }

  function startSpinner() {
    spinnerIntervalId = setInterval(() => {
      const frame = spinnerFrames[currentSpinnerFrame];
      currentSpinnerFrame = ++currentSpinnerFrame % spinnerFrames.length;

      title.innerText = `Starting ${frame}`;
    }, 100);
  }

  function stopSpinner() {
    clearInterval(spinnerIntervalId);
  }

  function startRecording() {
    const past = Date.now();
    startSpinner();
    recording = true;
    document.activeElement.blur(); // make sure the fps `onblur` validations are executed
    aperture.startRecording({fps: fps.value})
      .then(filePath => {
        stopSpinner();
        title.innerText = 'Recording ✅';
        startMonitoringElapsedTimeAndSize(filePath);
        console.log(`Started recording after ${(Date.now() - past) / 1000}s`);
      })
      .catch(err => {
        recording = false;
        console.error(err);
        stopSpinner();
        title.innerText = 'Error 😔';
      });
  }

  function askUserToSaveFile(opts) {
    if (!opts.filePath || !opts.fileName) {
      throw new Error('askUserToSaveFile must be called with {filePath, fileName}');
    }

    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = opts.filePath;
    a.download = opts.fileName;
    document.body.appendChild(a);
    a.click();
  }

  function stopRecording() {
    aperture.stopRecording()
      .then(filePath => {
        recording = false;
        stopMonitoring();
        title.innerText = 'Focus';
        time.innerText = '00:00';
        size.innerText = '0 kB';
        const fileName = `Screen record ${Date()}.mp4`;
        askUserToSaveFile({fileName, filePath});
      });
  }

  recordBtn.onclick = () => {
    if (recording) {
      stopRecording();
    } else {
      startRecording();
    }
  };

  settingsTitleWrapper.onclick = function () {
    const arrow = this.children[1];
    const settings = document.querySelector('.settings');

    arrow.classList.toggle('up');
    arrow.classList.toggle('down');

    settings.classList.toggle('hidden');
    setWindowSize();

    window.arrow = arrow;
  };

  fps.onkeyup = function () {
    if (!/^[0-9]{1,2}$/.test(this.value) && this.value.trim() !== '') {
      this.value = 30;
    } else if (this.value < 0) {
      this.value = 0;
    } else if (this.value > 60) {
      this.value = 60;
    }
  };

  fps.onblur = function () {
    if (this.value.trim() === '' || this.value === '0') {
      this.value = 30;
    }
  };

  options.onclick = () => {
    const {bottom, left} = options.getBoundingClientRect();
    ipcRenderer.send('show-options-menu', {x: left, y: bottom});
  };

  fpsInputWrapper.onclick = () => {
    fps.focus();
    fps.value = fps.value; // move the carret to the end
  };

  cropBtn.onclick = function () {
    ipcRenderer.send('open-cropper-window');
  };
});

window.addEventListener('load', setWindowSize);
<|endoftext|>


<commit_before>import $ from 'dom7';
import Template7 from 'template7';
import { window, document } from 'ssr-window';
import Utils from '../../utils/utils';
import Device from '../../utils/device';
import Framework7Class from '../../utils/class';
import EventsClass from '../../utils/events-class';
import ConstructorMethods from '../../utils/constructor-methods';
import ModalMethods from '../../utils/modal-methods';
import loadModule from './load-module';

class Framework7 extends Framework7Class {
  constructor(params) {
    super(params);
    if (Framework7.instance) {
      throw new Error('Framework7 is already initialized and can\'t be initialized more than once');
    }

    const passedParams = Utils.extend({}, params);

    // App Instance
    const app = this;

    Framework7.instance = app;

    // Default
    const defaults = {
      version: '1.0.0',
      id: 'io.framework7.testapp',
      root: 'body',
      theme: 'auto',
      language: window.navigator.language,
      routes: [],
      name: 'Framework7',
      lazyModulesPath: null,
      initOnDeviceReady: true,
      init: true,
      autoDarkTheme: false,
      iosTranslucentBars: true,
      iosTranslucentModals: true,
      component: undefined,
      componentUrl: undefined,
    };

    // Extend defaults with modules params
    app.useModulesParams(defaults);

    // Extend defaults with passed params
    app.params = Utils.extend(defaults, params);

    const $rootEl = $(app.params.root);

    Utils.extend(app, {
      // App Id
      id: app.params.id,
      // App Name
      name: app.params.name,
      // App version
      version: app.params.version,
      // Routes
      routes: app.params.routes,
      // Lang
      language: app.params.language,
      // Root
      root: $rootEl,
      // RTL
      rtl: $rootEl.css('direction') === 'rtl',
      // Theme
      theme: (function getTheme() {
        if (app.params.theme === 'auto') {
          if (Device.ios) return 'ios';
          if (Device.desktop && Device.electron) return 'aurora';
          return 'md';
        }
        return app.params.theme;
      }()),
      // Initially passed parameters
      passedParams,
      online: window.navigator.onLine,
    });

    // Save Root
    if (app.root && app.root[0]) {
      app.root[0].f7 = app;
    }

    // Install Modules
    app.useModules();

    // Init Data & Methods
    app.initData();

    // Auto Dark Theme
    const DARK = '(prefers-color-scheme: dark)';
    const LIGHT = '(prefers-color-scheme: light)';
    app.mq = {};
    if (window.matchMedia) {
      app.mq.dark = window.matchMedia(DARK);
      app.mq.light = window.matchMedia(LIGHT);
    }
    app.colorSchemeListener = function colorSchemeListener({ matches, media }) {
      if (!matches) {
        return;
      }
      const html = document.querySelector('html');
      if (media === DARK) {
        html.classList.add('theme-dark');
      } else if (media === LIGHT) {
        html.classList.remove('theme-dark');
      }
    };

    // Init
    if (params.init) {
      if (Device.cordova && app.params.initOnDeviceReady) {
        $(document).on('deviceready', () => {
          app.init();
        });
      } else {
        app.init();
      }
    }

    // Return app instance
    return app;
  }

  initData() {
    const app = this;

    // Data
    app.data = {};
    if (app.params.data && typeof app.params.data === 'function') {
      Utils.extend(app.data, app.params.data.bind(app)());
    } else if (app.params.data) {
      Utils.extend(app.data, app.params.data);
    }
    // Methods
    app.methods = {};
    if (app.params.methods) {
      Object.keys(app.params.methods).forEach((methodName) => {
        if (typeof app.params.methods[methodName] === 'function') {
          app.methods[methodName] = app.params.methods[methodName].bind(app);
        } else {
          app.methods[methodName] = app.params.methods[methodName];
        }
      });
    }
  }

  enableAutoDarkTheme() {
    if (!window.matchMedia) return;
    const app = this;
    const html = document.querySelector('html');
    if (app.mq.dark && app.mq.light) {
      app.mq.dark.addListener(app.colorSchemeListener);
      app.mq.light.addListener(app.colorSchemeListener);
    }
    if (app.mq.dark && app.mq.dark.matches) {
      html.classList.add('theme-dark');
    } else if (app.mq.light && app.mq.light.matches) {
      html.classList.remove('theme-dark');
    }
  }

  disableAutoDarkTheme() {
    if (!window.matchMedia) return;
    const app = this;
    if (app.mq.dark) app.mq.dark.removeListener(app.colorSchemeListener);
    if (app.mq.light) app.mq.light.removeListener(app.colorSchemeListener);
  }

  initAppComponent(callback) {
    const app = this;
    app.router.componentLoader(
      app.params.component,
      app.params.componentUrl,
      { componentOptions: { el: app.root[0] } },
      (el) => {
        app.root = $(el);
        app.root[0].f7 = app;
        app.rootComponent = el.f7Component;
        if (callback) callback();
      },
      () => {}
    );
  }

  // eslint-disable-next-line
  _init() {
    const app = this;
    if (app.initialized) return app;

    app.root.addClass('framework7-initializing');

    // RTL attr
    if (app.rtl) {
      $('html').attr('dir', 'rtl');
    }

    // Auto Dark Theme
    if (app.params.autoDarkTheme) {
      app.enableAutoDarkTheme();
    }

    // Watch for online/offline state
    window.addEventListener('offline', () => {
      app.online = false;
      app.emit('offline');
      app.emit('connection', false);
    });
    window.addEventListener('online', () => {
      app.online = true;
      app.emit('online');
      app.emit('connection', true);
    });

    // Root class
    app.root.addClass('framework7-root');

    // Theme class
    $('html').removeClass('ios md aurora').addClass(app.theme);

    // iOS Translucent
    if (app.params.iosTranslucentBars && app.theme === 'ios' && Device.ios) {
      $('html').addClass('ios-translucent-bars');
    }
    if (app.params.iosTranslucentModals && app.theme === 'ios' && Device.ios) {
      $('html').addClass('ios-translucent-modals');
    }

    // Init class
    Utils.nextFrame(() => {
      app.root.removeClass('framework7-initializing');
    });
    // Emit, init other modules
    app.initialized = true;
    app.emit('init');

    return app;
  }

  init() {
    const app = this;
    if (app.params.component || app.params.componentUrl) {
      app.initAppComponent(() => {
        app._init(); // eslint-disable-line
      });
    } else {
      app._init(); // eslint-disable-line
    }
  }

  // eslint-disable-next-line
  loadModule(...args) {
    return Framework7.loadModule(...args);
  }

  // eslint-disable-next-line
  loadModules(...args) {
    return Framework7.loadModules(...args);
  }

  getVnodeHooks(hook, id) {
    const app = this;
    if (!app.vnodeHooks || !app.vnodeHooks[hook]) return [];
    return app.vnodeHooks[hook][id] || [];
  }

  // eslint-disable-next-line
  get $() {
    return $;
  }
  // eslint-disable-next-line
  get t7() {
    return Template7;
  }

  static get Dom7() {
    return $;
  }

  static get $() {
    return $;
  }

  static get Template7() {
    return Template7;
  }

  static get Class() {
    return Framework7Class;
  }

  static get Events() {
    return EventsClass;
  }
}

Framework7.ModalMethods = ModalMethods;
Framework7.ConstructorMethods = ConstructorMethods;

Framework7.loadModule = loadModule;
Framework7.loadModules = function loadModules(modules) {
  return Promise.all(modules.map(module => Framework7.loadModule(module)));
};

export default Framework7;
<commit_msg>Core: Fix checking params.init<commit_after>import $ from 'dom7';
import Template7 from 'template7';
import { window, document } from 'ssr-window';
import Utils from '../../utils/utils';
import Device from '../../utils/device';
import Framework7Class from '../../utils/class';
import EventsClass from '../../utils/events-class';
import ConstructorMethods from '../../utils/constructor-methods';
import ModalMethods from '../../utils/modal-methods';
import loadModule from './load-module';

class Framework7 extends Framework7Class {
  constructor(params) {
    super(params);
    if (Framework7.instance) {
      throw new Error('Framework7 is already initialized and can\'t be initialized more than once');
    }

    const passedParams = Utils.extend({}, params);

    // App Instance
    const app = this;

    Framework7.instance = app;

    // Default
    const defaults = {
      version: '1.0.0',
      id: 'io.framework7.testapp',
      root: 'body',
      theme: 'auto',
      language: window.navigator.language,
      routes: [],
      name: 'Framework7',
      lazyModulesPath: null,
      initOnDeviceReady: true,
      init: true,
      autoDarkTheme: false,
      iosTranslucentBars: true,
      iosTranslucentModals: true,
      component: undefined,
      componentUrl: undefined,
    };

    // Extend defaults with modules params
    app.useModulesParams(defaults);

    // Extend defaults with passed params
    app.params = Utils.extend(defaults, params);

    const $rootEl = $(app.params.root);

    Utils.extend(app, {
      // App Id
      id: app.params.id,
      // App Name
      name: app.params.name,
      // App version
      version: app.params.version,
      // Routes
      routes: app.params.routes,
      // Lang
      language: app.params.language,
      // Root
      root: $rootEl,
      // RTL
      rtl: $rootEl.css('direction') === 'rtl',
      // Theme
      theme: (function getTheme() {
        if (app.params.theme === 'auto') {
          if (Device.ios) return 'ios';
          if (Device.desktop && Device.electron) return 'aurora';
          return 'md';
        }
        return app.params.theme;
      }()),
      // Initially passed parameters
      passedParams,
      online: window.navigator.onLine,
    });

    // Save Root
    if (app.root && app.root[0]) {
      app.root[0].f7 = app;
    }

    // Install Modules
    app.useModules();

    // Init Data & Methods
    app.initData();

    // Auto Dark Theme
    const DARK = '(prefers-color-scheme: dark)';
    const LIGHT = '(prefers-color-scheme: light)';
    app.mq = {};
    if (window.matchMedia) {
      app.mq.dark = window.matchMedia(DARK);
      app.mq.light = window.matchMedia(LIGHT);
    }
    app.colorSchemeListener = function colorSchemeListener({ matches, media }) {
      if (!matches) {
        return;
      }
      const html = document.querySelector('html');
      if (media === DARK) {
        html.classList.add('theme-dark');
      } else if (media === LIGHT) {
        html.classList.remove('theme-dark');
      }
    };

    // Init
    if (app.params.init) {
      if (Device.cordova && app.params.initOnDeviceReady) {
        $(document).on('deviceready', () => {
          app.init();
        });
      } else {
        app.init();
      }
    }

    // Return app instance
    return app;
  }

  initData() {
    const app = this;

    // Data
    app.data = {};
    if (app.params.data && typeof app.params.data === 'function') {
      Utils.extend(app.data, app.params.data.bind(app)());
    } else if (app.params.data) {
      Utils.extend(app.data, app.params.data);
    }
    // Methods
    app.methods = {};
    if (app.params.methods) {
      Object.keys(app.params.methods).forEach((methodName) => {
        if (typeof app.params.methods[methodName] === 'function') {
          app.methods[methodName] = app.params.methods[methodName].bind(app);
        } else {
          app.methods[methodName] = app.params.methods[methodName];
        }
      });
    }
  }

  enableAutoDarkTheme() {
    if (!window.matchMedia) return;
    const app = this;
    const html = document.querySelector('html');
    if (app.mq.dark && app.mq.light) {
      app.mq.dark.addListener(app.colorSchemeListener);
      app.mq.light.addListener(app.colorSchemeListener);
    }
    if (app.mq.dark && app.mq.dark.matches) {
      html.classList.add('theme-dark');
    } else if (app.mq.light && app.mq.light.matches) {
      html.classList.remove('theme-dark');
    }
  }

  disableAutoDarkTheme() {
    if (!window.matchMedia) return;
    const app = this;
    if (app.mq.dark) app.mq.dark.removeListener(app.colorSchemeListener);
    if (app.mq.light) app.mq.light.removeListener(app.colorSchemeListener);
  }

  initAppComponent(callback) {
    const app = this;
    app.router.componentLoader(
      app.params.component,
      app.params.componentUrl,
      { componentOptions: { el: app.root[0] } },
      (el) => {
        app.root = $(el);
        app.root[0].f7 = app;
        app.rootComponent = el.f7Component;
        if (callback) callback();
      },
      () => {}
    );
  }

  // eslint-disable-next-line
  _init() {
    const app = this;
    if (app.initialized) return app;

    app.root.addClass('framework7-initializing');

    // RTL attr
    if (app.rtl) {
      $('html').attr('dir', 'rtl');
    }

    // Auto Dark Theme
    if (app.params.autoDarkTheme) {
      app.enableAutoDarkTheme();
    }

    // Watch for online/offline state
    window.addEventListener('offline', () => {
      app.online = false;
      app.emit('offline');
      app.emit('connection', false);
    });
    window.addEventListener('online', () => {
      app.online = true;
      app.emit('online');
      app.emit('connection', true);
    });

    // Root class
    app.root.addClass('framework7-root');

    // Theme class
    $('html').removeClass('ios md aurora').addClass(app.theme);

    // iOS Translucent
    if (app.params.iosTranslucentBars && app.theme === 'ios' && Device.ios) {
      $('html').addClass('ios-translucent-bars');
    }
    if (app.params.iosTranslucentModals && app.theme === 'ios' && Device.ios) {
      $('html').addClass('ios-translucent-modals');
    }

    // Init class
    Utils.nextFrame(() => {
      app.root.removeClass('framework7-initializing');
    });
    // Emit, init other modules
    app.initialized = true;
    app.emit('init');

    return app;
  }

  init() {
    const app = this;
    if (app.params.component || app.params.componentUrl) {
      app.initAppComponent(() => {
        app._init(); // eslint-disable-line
      });
    } else {
      app._init(); // eslint-disable-line
    }
  }

  // eslint-disable-next-line
  loadModule(...args) {
    return Framework7.loadModule(...args);
  }

  // eslint-disable-next-line
  loadModules(...args) {
    return Framework7.loadModules(...args);
  }

  getVnodeHooks(hook, id) {
    const app = this;
    if (!app.vnodeHooks || !app.vnodeHooks[hook]) return [];
    return app.vnodeHooks[hook][id] || [];
  }

  // eslint-disable-next-line
  get $() {
    return $;
  }
  // eslint-disable-next-line
  get t7() {
    return Template7;
  }

  static get Dom7() {
    return $;
  }

  static get $() {
    return $;
  }

  static get Template7() {
    return Template7;
  }

  static get Class() {
    return Framework7Class;
  }

  static get Events() {
    return EventsClass;
  }
}

Framework7.ModalMethods = ModalMethods;
Framework7.ConstructorMethods = ConstructorMethods;

Framework7.loadModule = loadModule;
Framework7.loadModules = function loadModules(modules) {
  return Promise.all(modules.map(module => Framework7.loadModule(module)));
};

export default Framework7;
<|endoftext|>


<commit_before>
// @require ../init.js

//SOURCE: jQuery UI

(function ( $ ) {

  /* SELECTION */

  $.fn.disableSelection = (function () {

    let event = ( 'onselectstart' in document.createElement ( 'div' ) ) ? 'selectstart' : 'mousedown';

    return function () {

      return this.on ( event + '.svelto-disable-selection', event => event.preventDefault () );

    };

  })();

  $.fn.enableSelection = function () {

    return this.off ( '.svelto-disable-selection' );

  };

}( window.__svelto_jquery ));
<commit_msg>$.fn.disableSelection|enableSelection: implemented without namespaces<commit_after>
// @require ../init.js

//SOURCE: jQuery UI

(function ( $ ) {

  /* SELECTION */

  const preventer = event => event.preventDefault ();

  $.fn.disableSelection = function () {

    return this.on ( 'selectstart', preventer );

  };

  $.fn.enableSelection = function () {

    return this.off ( 'selectstart', preventer );

  };

}( window.$ ));
<|endoftext|>


<commit_before>export { Params, ParamsInfo };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as ValueDesc from "../ValueDesc.js";
import * as ParamDesc from "../ParamDesc.js";
import { Base } from "./Weights_Base.js";

/**
 * Used by Weights.Params' constructor internally before calling parent (i.e. Weights.Base) class's constructor.
 *
 * @member {ParamDesc.SequenceArray} paramDescSequenceArray
 *   An array describes how many and what kinds of parameters should be extracted. It will be referenced (i.e. kept without cloned)
 * and will not be released by this ParamsInfo object.
 *
 * @member {number[]} initValueArray
 *   An number array records the parameter values which is specified by ...restArgs of constructor. If a parameter value is null,
 * it means the parameter should be extracted from inputWeightArray (i.e. by evolution). Otherwise, the parameter value is by
 * specifying (from constructor). This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number[]} inputWeightArrayIndexArray
 *   A number array records where to extract parameters which is null in .initValueArray[]. Every element is the array index into
 * inputWeightArray[]. This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number[]} finalValueArray
 *   An number array records the parameter values which combined both by specifying (from constructor) and by evolution (from
 * inputWeightArray[]) and adjusted by ParamDesc.valueDesc.range.adjust(). This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number} parameterCountExtracted
 *   How many parameters are extracted from inputWeightArray[]. Only meaningful if Params.init() successfully.
 *
 * @member {number} parameterCount
 *   Always ( aParamDescSequenceArray.length ). This is the total parameter count provided by this object if Params.init()
 * successfully.
 *
 */
class ParamsInfo extends Recyclable.Root {

  /**
   * Used as default Weights.Params provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Weights.ParamsInfo.Pool", ParamsInfo, ParamsInfo.setAsConstructor );

  /**
   *
   * @param {any[]} restArgs
   *   Describe the specified parameters value. They should be arranged as the order of paramDescSequenceArray. For every element:
   *
   *     - If ( null != value ), the returned value of paramDesc.range.adjust( value ) will be used as the parameter's
   *         value. (i.e. by specifying)
   *
   *     - If ( null == value ), the parameter will be extracted from inputWeightArray. The returned value of
   *         paramDesc.valueDesc.range.adjust( extractedValue ) will be used as the parameter's value. (i.e. by evolution)
   *
   */
  constructor( elementOffsetBegin, paramDescSequenceArray, ...restArgs ) {
    super();
    ParamsInfo.setAsConstructor_self.call( this, elementOffsetBegin, paramDescSequenceArray, ...restArgs );
   }

  /** @override */
  static setAsConstructor( elementOffsetBegin, paramDescSequenceArray, ...restArgs ) {
    super.setAsConstructor();
    ParamsInfo.setAsConstructor_self.call( this, elementOffsetBegin, paramDescSequenceArray, ...restArgs );
    return this;
  }

  /** @override */
  static setAsConstructor_self( elementOffsetBegin, paramDescSequenceArray, ...restArgs ) {
    this.paramDescSequenceArray = paramDescSequenceArray;
    this.parameterCount = paramDescSequenceArray.array.length;

    this.initValueArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );
    this.inputWeightArrayIndexArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );
    this.finalValueArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );

    this.parameterCountExtracted = 0;
    for ( let i = 0; i < this.parameterCount; ++i ) {
      let paramDesc = paramDescSequenceArray.array[ i ];
      let initValue = this.initValueArray[ i ] = restArgs[ i ]; // Collect all parameters.

      // Collect what parameters should be extracted from input array (rather than use values in the .initValueArray).
      // At the same time, its array index (into inputWeightArray) will also be recorded for extracting its value in the future.
      {
        // A null value means it should be extracted from inputWeightArray. (i.e. by evolution)
        //
        // Note: This is different from ( !value ). If value is 0, ( !value ) is true but ( null == value ) is false.
        //
        if ( null == initValue ) {
          // Record the index (into inputWeightArray[]).
          this.inputWeightArrayIndexArray[ i ] = elementOffsetBegin + this.parameterCountExtracted;
          this.finalValueArray[ i ] = undefined;
          ++this.parameterCountExtracted;

        } else {  // A non-null value means it is the parameter's value (which should also be adjusted).
          this.inputWeightArrayIndexArray[ i ] = undefined; // Indicates this parameter needs not be extracted from inputWeightArray.
          let adjustedValue = paramDesc.valueDesc.range.adjust( initValue );
          this.finalValueArray[ i ] = adjustedValue;
        }
      }
    }
  }

  /** @override */
  disposeResources() {
    this.parameterCountExtracted = undefined;

    if ( this.finalValueArray ) {
      this.finalValueArray.disposeResources_and_recycleToPool();
      this.finalValueArray = null;
    }

    if ( this.inputWeightArrayIndexArray ) {
      this.inputWeightArrayIndexArray.disposeResources_and_recycleToPool();
      this.inputWeightArrayIndexArray = null;
    }

    if ( this.initValueArray ) {
      this.initValueArray.disposeResources_and_recycleToPool();
      this.initValueArray = null;
    }

    this.parameterCount = undefined;
    this.paramDescSequenceArray = null; // Do not release it. Just un-reference it.

    super.disposeResources();
  }

}

/**
 * The parameters for the weights of a neural network layer.
 *
 * @member {Weights.ParamsInfo} paramsInfo
 *   The ParamsDesc list with their specified or extracted values.
 *
 * @member {number} parameterCountExtracted
 *   The count of the parameters extracted from inputWeightArray (i.e. by evolution). It should be the same as .elementExtractedCount.
 * Only meaningful if Params.init() successfully.
 *
 * @member {number} parameterCount
 *   The count of the all parameters (both directly given (i.e. by specifying) and extracted from inputWeightArray (i.e. by evolution) ).
 * It should be always the same as ( aParamDescSequenceArray.length ). This is the total parameter count provided by this object if
 * Params.init() successfully.
 *
 * @see Weights.Base
 */
class Params extends Base {

  /**
   * Used as default Weights.Params provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Weights.Params.Pool", Params, Params.setAsConstructor );

  /**
   */
  constructor( elementOffsetBegin, aParamDescSequenceArray, ...restArgs ) {
    let info = ParamsInfo.Pool.get_or_create_by( elementOffsetBegin, aParamDescSequenceArray, ...restArgs );
    super( elementOffsetBegin, info.parameterCountExtracted );
    Params.setAsConstructor_self.call( this, info );
  }

  /** @override */
  static setAsConstructor( elementOffsetBegin, aParamDescSequenceArray, ...restArgs ) {
    let info = ParamsInfo.Pool.get_or_create_by( elementOffsetBegin, aParamDescSequenceArray, ...restArgs );
    super.setAsConstructor( elementOffsetBegin, info.parameterCountExtracted );
    Params.setAsConstructor_self.call( this, info );
    return this;
  }

  /** @override */
  static setAsConstructor_self( aParamsInfo ) {
    this.info = aParamsInfo;
  }

  /** @override */
  disposeResources() {
    if ( this.info ) {
      this.info.disposeResources_and_recycleToPool();
      this.info = null;
    }
    super.disposeResources();
  }

  /**
   * Extract parameters from inputWeightArray.
   *
   * @return {boolean} Return false, if extraction failed.
   *
   * @override
   */
  init( inputWeightArray ) {

    let bBaseInitOk = super.init(); // Determine and check input weight array bounds.
    if ( !bBaseInitOk )
      return false;

    // Copy the adjusted extracted weights.
    //
    // Do not modify the original array data, because the original data is necessary when backtracking (to try
    // another neural network layer configuration.

    // Extract (by evolution) values from array, convert them, and put back into copied array and copied map.
    for ( let i = 0; i < this.info.parameterCount; ++i ) {
      let inputWeightArrayIndex = this.info.inputWeightArrayIndexArray[ i ];
      if ( inputWeightArrayIndex == undefined )
        continue; // This parameter has a specified value. No need to be extracted from inputWeightArray. (i.e. not by evolution)

      let paramDesc = this.info.paramDescSequenceArray.array[ i ];
      let extractedValue = inputWeightArray[ inputWeightArrayIndex ];
      let adjustedValue = paramDesc.valueDesc.range.adjust( extractedValue );
      this.info.finalValueArray[ i ] = adjustedValue;
    }

    this.bInitOk = true;
    return true;
  }

  get parameterCountExtracted() { return this.info.parameterCountExtracted; }

  get parameterCount()          { return this.info.parameterCount; }

  /**
   * @param {ParamDesc.Base} aParamDesc
   *   The aParamDesc.seqId will be used to access .info.finalValueArray[].
   *
   * @return {number}
   *   Return the specific ParamDesc's value (no matter by specified or by evolution).
   */
  getParamValue_byParamDesc( aParamDesc ) {
    let value = this.info.finalValueArray[ aParamDesc.seqId ];
    return value;
  }

}
<commit_msg>Update Weights_Params.js<commit_after>export { Params, ParamsInfo };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as ValueDesc from "../ValueDesc.js";
import * as ParamDesc from "../ParamDesc.js";
import { Base } from "./Weights_Base.js";

/**
 * Used by Weights.Params' constructor internally before calling parent (i.e. Weights.Base) class's constructor.
 *
 * @member {ParamDesc.SequenceArray} paramDescSequenceArray
 *   An array describes how many and what kinds of parameters should be extracted. It will be referenced (i.e. kept without cloned)
 * and will not be released by this ParamsInfo object.
 *
 * @member {number[]} initValueArray
 *   An number array records the parameter values which is specified by ...restArgs of constructor. If a parameter value is null,
 * it means the parameter should be extracted from inputWeightArray (i.e. by evolution). Otherwise, the parameter value is by
 * specifying (from constructor). This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number[]} inputWeightArrayIndexArray
 *   A number array records where to extract parameters which is null in .initValueArray[]. Every element is the relative
 * array index into inputWeightArray[ elementOffsetBegin ]. This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number[]} finalValueArray
 *   An number array records the parameter values which combined both by specifying (from constructor) and by evolution (from
 * inputWeightArray[]) and adjusted by ParamDesc.valueDesc.range.adjust(). This array itself is indexed by ParamDesc.Xxx.seqId.
 *
 * @member {number} parameterCountExtracted
 *   How many parameters are extracted from inputWeightArray[]. Only meaningful if Params.init() successfully.
 *
 * @member {number} parameterCount
 *   Always ( aParamDescSequenceArray.length ). This is the total parameter count provided by this object if Params.init()
 * successfully.
 *
 */
class ParamsInfo extends Recyclable.Root {

  /**
   * Used as default Weights.Params provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Weights.ParamsInfo.Pool", ParamsInfo, ParamsInfo.setAsConstructor );

  /**
   *
   * @param {any[]} restArgs
   *   Describe the specified parameters value. They should be arranged as the order of paramDescSequenceArray. For every element:
   *
   *     - If ( null != value ), the returned value of paramDesc.range.adjust( value ) will be used as the parameter's
   *         value. (i.e. by specifying)
   *
   *     - If ( null == value ), the parameter will be extracted from inputWeightArray. The returned value of
   *         paramDesc.valueDesc.range.adjust( extractedValue ) will be used as the parameter's value. (i.e. by evolution)
   *
   */
  constructor( paramDescSequenceArray, ...restArgs ) {
    super();
    ParamsInfo.setAsConstructor_self.call( this, paramDescSequenceArray, ...restArgs );
   }

  /** @override */
  static setAsConstructor( paramDescSequenceArray, ...restArgs ) {
    super.setAsConstructor();
    ParamsInfo.setAsConstructor_self.call( this, paramDescSequenceArray, ...restArgs );
    return this;
  }

  /** @override */
  static setAsConstructor_self( paramDescSequenceArray, ...restArgs ) {
    this.paramDescSequenceArray = paramDescSequenceArray;
    this.parameterCount = paramDescSequenceArray.array.length;

    this.initValueArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );
    this.inputWeightArrayIndexArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );
    this.finalValueArray = Recyclable.Array.Pool.get_or_create_by( this.parameterCount );

    this.parameterCountExtracted = 0;
    for ( let i = 0; i < this.parameterCount; ++i ) {
      let paramDesc = paramDescSequenceArray.array[ i ];
      let initValue = this.initValueArray[ i ] = restArgs[ i ]; // Collect all parameters.

      // Collect what parameters should be extracted from input array (rather than use values in the .initValueArray).
      // At the same time, its array index (into inputWeightArray) will also be recorded for extracting its value in the future.
      {
        // A null value means it should be extracted from inputWeightArray. (i.e. by evolution)
        //
        // Note: This is different from ( !value ). If value is 0, ( !value ) is true but ( null == value ) is false.
        //
        if ( null == initValue ) {
          // Record the index (into inputWeightArray[]).
          this.inputWeightArrayIndexArray[ i ] = this.parameterCountExtracted;
          this.finalValueArray[ i ] = undefined;
          ++this.parameterCountExtracted;

        } else {  // A non-null value means it is the parameter's value (which should also be adjusted).
          this.inputWeightArrayIndexArray[ i ] = undefined; // Indicates this parameter needs not be extracted from inputWeightArray.
          let adjustedValue = paramDesc.valueDesc.range.adjust( initValue );
          this.finalValueArray[ i ] = adjustedValue;
        }
      }
    }
  }

  /** @override */
  disposeResources() {
    this.parameterCountExtracted = undefined;

    if ( this.finalValueArray ) {
      this.finalValueArray.disposeResources_and_recycleToPool();
      this.finalValueArray = null;
    }

    if ( this.inputWeightArrayIndexArray ) {
      this.inputWeightArrayIndexArray.disposeResources_and_recycleToPool();
      this.inputWeightArrayIndexArray = null;
    }

    if ( this.initValueArray ) {
      this.initValueArray.disposeResources_and_recycleToPool();
      this.initValueArray = null;
    }

    this.parameterCount = undefined;
    this.paramDescSequenceArray = null; // Do not release it. Just un-reference it.

    super.disposeResources();
  }

}

/**
 * The parameters for the weights of a neural network layer.
 *
 * @member {Weights.ParamsInfo} paramsInfo
 *   The ParamsDesc list with their specified or extracted values.
 *
 * @member {number} parameterCountExtracted
 *   The count of the parameters extracted from inputWeightArray (i.e. by evolution). It should be the same as .elementExtractedCount.
 * Only meaningful if Params.init() successfully.
 *
 * @member {number} parameterCount
 *   The count of the all parameters (both directly given (i.e. by specifying) and extracted from inputWeightArray (i.e. by evolution) ).
 * It should be always the same as ( aParamDescSequenceArray.length ). This is the total parameter count provided by this object if
 * Params.init() successfully.
 *
 * @see Weights.Base
 */
class Params extends Base {

  /**
   * Used as default Weights.Params provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Weights.Params.Pool", Params, Params.setAsConstructor );

  /**
   */
  constructor( aParamDescSequenceArray, ...restArgs ) {
    super();
    Params.setAsConstructor_self.call( this, aParamDescSequenceArray, ...restArgs );
  }

  /** @override */
  static setAsConstructor( aParamDescSequenceArray, ...restArgs ) {
    super.setAsConstructor();
    Params.setAsConstructor_self.call( this, aParamDescSequenceArray, ...restArgs );
    return this;
  }

  /** @override */
  static setAsConstructor_self( aParamDescSequenceArray, ...restArgs ) {
    this.info = ParamsInfo.Pool.get_or_create_by( aParamDescSequenceArray, ...restArgs );
  }

  /** @override */
  disposeResources() {
    if ( this.info ) {
      this.info.disposeResources_and_recycleToPool();
      this.info = null;
    }
    super.disposeResources();
  }

  /**
   * Extract parameters from inputWeightArray.
   *
   * @return {boolean} Return false, if extraction failed.
   *
   * @override
   */
  init( inputWeightArray, elementOffsetBegin ) {

    // Determine and check input weight array bounds.
    let bBaseInitOk = super.init( inputWeightArray, elementOffsetBegin, this.info.parameterCountExtracted );
    if ( !bBaseInitOk )
      return false;

    // Copy the adjusted extracted weights.
    //
    // Do not modify the original array data, because the original data is necessary when backtracking (to try
    // another neural network layer configuration.

    // Extract (by evolution) values from array, convert them, and put back into copied array and copied map.
    for ( let i = 0; i < this.info.parameterCount; ++i ) {
      let inputWeightArrayIndex = this.info.inputWeightArrayIndexArray[ i ];
      if ( inputWeightArrayIndex == undefined )
        continue; // This parameter has a specified value. No need to be extracted from inputWeightArray. (i.e. not by evolution)

      let absoluteArrayIndex = elementOffsetBegin + inputWeightArrayIndex;
      let extractedValue = inputWeightArray[ absoluteArrayIndex ];

      let paramDesc = this.info.paramDescSequenceArray.array[ i ];
      let adjustedValue = paramDesc.valueDesc.range.adjust( extractedValue );
      this.info.finalValueArray[ i ] = adjustedValue;
    }

    this.bInitOk = true;
    return true;
  }

  get parameterCountExtracted() { return this.info.parameterCountExtracted; }

  get parameterCount()          { return this.info.parameterCount; }

  /**
   * @param {ParamDesc.Base} aParamDesc
   *   The aParamDesc.seqId will be used to access .info.finalValueArray[].
   *
   * @return {number}
   *   Return the specific ParamDesc's value (no matter by specified or by evolution).
   */
  getParamValue_byParamDesc( aParamDesc ) {
    let value = this.info.finalValueArray[ aParamDesc.seqId ];
    return value;
  }

}
<|endoftext|>


<commit_before>import View from '../view/view';
import Command from 'core/infrastructure/command';
import stateFactory from './state/selection.state.factory';
import rangeBuilder from './range.build';
import Shortcut from 'core/infrastructure/shortcut';
import {GRID_PREFIX} from 'core/definition';

export default class SelectionView extends View {
	constructor(model, table, apply) {
		super(model);

		this.table = table;
		const markup = table.markup;
		this.markup = markup;
		this.apply = apply;

		this.selectionState = stateFactory(model);
		this.buildRange = rangeBuilder(model);

		const shortcut = new Shortcut(markup.document, markup.table, apply);
		const commands = this.commands;
		this.shortcutOff = shortcut.register('selectionNavigation', commands);
		this.toggleRow = commands.get('toggleRow');
		this.toggleColumn = commands.get('toggleColumn');
		this.toggleCell = commands.get('toggleCell');

		this.reset = commands.get('reset');

		model.sortChanged.watch(() => {
			this.selectionState = stateFactory(model);

			model.selection({items: this.selectionState.view});
		});

		model.navigationChanged.watch(e => {
			if (e.hasChanges('active') && e.tag.source !== 'selection') {
				const selectionState = model.selection();
				if (selectionState.unit === 'cell' && selectionState.mode === 'single') {
					if (e.state.active.cell) {
						this.select(e.state.active.cell, true);
					}
				}
			}
		});

		model.selectionChanged.watch(e => {
			if (e.hasChanges('mode')) {
				apply(() => {
					const newClassName = `${GRID_PREFIX}-select-${model.selection().mode}`;
					this.markup.view.classList.add(newClassName);

					if (e.changes.mode.oldValue != e.changes.mode.newValue) {
						const oldClassName = `${GRID_PREFIX}-select-${e.changes.mode.oldValue}`;
						this.markup.view.classList.remove(oldClassName);
					}
				});
			}

			if (e.hasChanges('unit') || e.hasChanges('mode')) {
				this.selectionState = stateFactory(model);

				model.navigation({column: -1, row: -1}, {source: 'selection'});
				const entries = this.selectionState.entries();
				model.selection({
					entries: entries,
					items: this.selectionState.view(entries)
				});
			}

			if (e.tag.source !== 'toggle' && e.hasChanges('entries')) {
				this.select(model.selection().entries, true);
			}
		});
	}

	get commands() {
		const model = this.model;
		const commands = {
			toggleRow: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleColumn: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleCell: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleActiveRow: new Command({
				shortcut: 'shift+space',
				execute: () => {
					const itemIndex = model.navigation().row;

					let item;
					if (itemIndex >= 0) {
						item = model.view().rows[itemIndex];
					} else {
						item = model.view().rows[itemIndex + 1];
						model.navigation({row: itemIndex + 1}, {source: 'selection'});
					}

					this.select(item);
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			togglePrevRow: new Command({
				shortcut: 'shift+up',
				execute: () => {
					const itemIndex = model.navigation().row;

					if (itemIndex > 0) {
						const item = model.view().rows[itemIndex - 1];
						this.select(item);
						model.navigation({row: itemIndex - 1}, {source: 'selection'});
					}
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			toggleNextRow: new Command({
				shortcut: 'shift+down',
				execute: () => {

					const itemIndex = model.navigation().row;
					if (itemIndex < model.view().rows.length - 1) {
						const item = model.view().rows[itemIndex + 1];
						this.select(item);
						model.navigation({row: itemIndex + 1});
					}
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			toggleActiveColumn: new Command({
				shortcut: 'ctrl+space',
				execute: () => {
					const index = model.navigation().column;
					const entries = Array.from(model.selection().entries);
					const columns = this.table.data.columns();
					const column = columns[index].key;
					this.select([...entries, column]);
				},
				canExecute: () => model.selection().unit === 'column'
			}),
			toggleNextColumn: new Command({
				shortcut: 'shift+right',
				execute: () => {
					const columns = this.table.data.columns();
					const index = model.navigation().column + 1;
					const column = columns[index].key;

					this.select(column);

					model.navigation({column: index}, {source: 'selection'});
				},
				canExecute: () => model.selection().unit === 'column' && model.navigation().column < this.table.data.columns().length - 1
			}),
			togglePrevColumn: new Command({
				shortcut: 'shift+left',
				execute: () => {
					const columns = this.table.data.columns();
					const index = model.navigation().column - 1;
					const column = columns[index].key;

					this.select(column);

					model.navigation({column: index}, {source: 'selection'});
				},
				canExecute: () => model.selection().unit === 'column' && model.navigation().column > 0
			}),
			selectAll: new Command({
				shortcut: 'ctrl+a',
				execute: () => this.select(),
				canExecute: () => model.selection().mode === 'multiple'
			}),
			reset: new Command({
				execute: () => {
					this.reset();
				}
			})
		};

		return new Map(
			Object.entries(commands)
		);
	}

	selectRange(startCell, endCell) {
		const range = this.buildRange(startCell, endCell);
		this.select(range);
	}

	select(items) {
		if (this.selection.mode === 'range') {
			this.selectionState.clear();
			this.selectionState.toggle(items, true);
		} else {
			this.selectionState.toggle(items);
		}

		const entries = this.selectionState.entries();
		this.model.selection({
			items: this.selectionState.view(entries),
			entries: entries,
		}, {source: 'toggle'});
	}

	state(item) {
		if (!arguments.length) {
			item = this.model.view().rows;
		}

		return this.selectionState.state(item) === true;
	}

	isIndeterminate(item) {
		if (!arguments.length) {
			item = this.model.view().rows;
		}

		return this.selectionState.state(item) === null;
	}

	destroy() {
		this.shortcutOff();
	}

	get selection() {
		return this.model.selection();
	}
}<commit_msg>Fixed select all<commit_after>import View from '../view/view';
import Command from 'core/infrastructure/command';
import stateFactory from './state/selection.state.factory';
import rangeBuilder from './range.build';
import Shortcut from 'core/infrastructure/shortcut';
import {GRID_PREFIX} from 'core/definition';
import {isUndefined} from 'core/services/utility';

export default class SelectionView extends View {
	constructor(model, table, apply) {
		super(model);

		this.table = table;
		const markup = table.markup;
		this.markup = markup;
		this.apply = apply;

		this.selectionState = stateFactory(model);
		this.buildRange = rangeBuilder(model);

		const shortcut = new Shortcut(markup.document, markup.table, apply);
		const commands = this.commands;
		this.shortcutOff = shortcut.register('selectionNavigation', commands);
		this.toggleRow = commands.get('toggleRow');
		this.toggleColumn = commands.get('toggleColumn');
		this.toggleCell = commands.get('toggleCell');

		this.reset = commands.get('reset');

		model.sortChanged.watch(() => {
			this.selectionState = stateFactory(model);

			model.selection({items: this.selectionState.view});
		});

		model.navigationChanged.watch(e => {
			if (e.hasChanges('active') && e.tag.source !== 'selection') {
				const selectionState = model.selection();
				if (selectionState.unit === 'cell' && selectionState.mode === 'single') {
					if (e.state.active.cell) {
						this.select(e.state.active.cell, true);
					}
				}
			}
		});

		model.selectionChanged.watch(e => {
			if (e.hasChanges('mode')) {
				apply(() => {
					const newClassName = `${GRID_PREFIX}-select-${model.selection().mode}`;
					this.markup.view.classList.add(newClassName);

					if (e.changes.mode.oldValue != e.changes.mode.newValue) {
						const oldClassName = `${GRID_PREFIX}-select-${e.changes.mode.oldValue}`;
						this.markup.view.classList.remove(oldClassName);
					}
				});
			}

			if (e.hasChanges('unit') || e.hasChanges('mode')) {
				this.selectionState = stateFactory(model);

				model.navigation({column: -1, row: -1}, {source: 'selection'});
				const entries = this.selectionState.entries();
				model.selection({
					entries: entries,
					items: this.selectionState.view(entries)
				});
			}

			if (e.tag.source !== 'toggle' && e.hasChanges('entries')) {
				this.select(model.selection().entries, true);
			}
		});
	}

	get commands() {
		const model = this.model;
		const commands = {
			toggleRow: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleColumn: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleCell: new Command({
				execute: (item, state) => {
					this.select(item, state);
				}
			}),
			toggleActiveRow: new Command({
				shortcut: 'shift+space',
				execute: () => {
					const itemIndex = model.navigation().row;

					let item;
					if (itemIndex >= 0) {
						item = model.view().rows[itemIndex];
					} else {
						item = model.view().rows[itemIndex + 1];
						model.navigation({row: itemIndex + 1}, {source: 'selection'});
					}

					this.select(item);
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			togglePrevRow: new Command({
				shortcut: 'shift+up',
				execute: () => {
					const itemIndex = model.navigation().row;

					if (itemIndex > 0) {
						const item = model.view().rows[itemIndex - 1];
						this.select(item);
						model.navigation({row: itemIndex - 1}, {source: 'selection'});
					}
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			toggleNextRow: new Command({
				shortcut: 'shift+down',
				execute: () => {

					const itemIndex = model.navigation().row;
					if (itemIndex < model.view().rows.length - 1) {
						const item = model.view().rows[itemIndex + 1];
						this.select(item);
						model.navigation({row: itemIndex + 1});
					}
				},
				canExecute: () => model.selection().unit === 'row'
			}),
			toggleActiveColumn: new Command({
				shortcut: 'ctrl+space',
				execute: () => {
					const index = model.navigation().column;
					const entries = Array.from(model.selection().entries);
					const columns = this.table.data.columns();
					const column = columns[index].key;
					this.select([...entries, column]);
				},
				canExecute: () => model.selection().unit === 'column'
			}),
			toggleNextColumn: new Command({
				shortcut: 'shift+right',
				execute: () => {
					const columns = this.table.data.columns();
					const index = model.navigation().column + 1;
					const column = columns[index].key;

					this.select(column);

					model.navigation({column: index}, {source: 'selection'});
				},
				canExecute: () => model.selection().unit === 'column' && model.navigation().column < this.table.data.columns().length - 1
			}),
			togglePrevColumn: new Command({
				shortcut: 'shift+left',
				execute: () => {
					const columns = this.table.data.columns();
					const index = model.navigation().column - 1;
					const column = columns[index].key;

					this.select(column);

					model.navigation({column: index}, {source: 'selection'});
				},
				canExecute: () => model.selection().unit === 'column' && model.navigation().column > 0
			}),
			selectAll: new Command({
				shortcut: 'ctrl+a',
				execute: () => this.select(),
				canExecute: () => model.selection().mode === 'multiple'
			}),
			reset: new Command({
				execute: () => {
					this.reset();
				}
			})
		};

		return new Map(
			Object.entries(commands)
		);
	}

	selectRange(startCell, endCell) {
		const range = this.buildRange(startCell, endCell);
		this.select(range);
	}

	select(items) {
		if (arguments.length && !isUndefined(items)) {
			if (this.selection.mode === 'range') {
				this.selectionState.clear();
				this.selectionState.toggle(items, true);
			} else {
				this.selectionState.toggle(items);
			}
		}
		else {
			if (this.state() || this.model.selection().mode === 'single') {
				this.selectionState.clear();
			}
			else{
				this.selectionState.select(this.model.view().rows, true);
			}
		}

		const entries = this.selectionState.entries();
		this.model.selection({
			items: this.selectionState.view(entries),
			entries: entries,
		}, {source: 'toggle'});
	}

	state(item) {
		if (!arguments.length) {
			item = this.model.view().rows;
		}

		return this.selectionState.state(item) === true;
	}

	isIndeterminate(item) {
		if (!arguments.length) {
			item = this.model.view().rows;
		}

		return this.selectionState.state(item) === null;
	}

	destroy() {
		this.shortcutOff();
	}

	get selection() {
		return this.model.selection();
	}
}<|endoftext|>


<commit_before>'use strict';
import ExtendableError from 'es6-error';

export class ProjectNotFoundError extends ExtendableError {
  constructor (message = 'Project not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class ScenarioNotFoundError extends ExtendableError {
  constructor (message = 'Scenario not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class FileNotFoundError extends ExtendableError {
  constructor (message = 'File not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class FileExistsError extends ExtendableError {
  constructor (message = 'File already exists', extra) {
    super(message);
    this.extra = extra;
  }
}

export class ProjectStatusError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class DataConflictError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class MasterScenarioError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class DataValidationError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}
<commit_msg>Add new error handling system for try catch blocks<commit_after>'use strict';
import ExtendableError from 'es6-error';
import Boom from 'boom';

export class ProjectNotFoundError extends ExtendableError {
  constructor (message = 'Project not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class ScenarioNotFoundError extends ExtendableError {
  constructor (message = 'Scenario not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class FileNotFoundError extends ExtendableError {
  constructor (message = 'File not found', extra) {
    super(message);
    this.extra = extra;
  }
}

export class FileExistsError extends ExtendableError {
  constructor (message = 'File already exists', extra) {
    super(message);
    this.extra = extra;
  }
}

export class ProjectStatusError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class DataConflictError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class MasterScenarioError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class DataValidationError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

export class DisabledServiceError extends ExtendableError {
  constructor (message, extra) {
    super(message);
    this.extra = extra;
  }
}

/**
 * Gets the appropriate Boom response for the given error. Can be passed
 * directly to the reply interface.
 * This function is specially useful when workin with try/catch blocks that can
 * throw multiple errors.
 *
 * @param {Error} error Error object
 *
 * @returns Boom response
 */
export function getBoomResponseForError (error) {
  // Check for known error types.
  if (error instanceof FileNotFoundError) return Boom.notFound(error.message);
  if (error instanceof ProjectNotFoundError) return Boom.notFound(error.message);
  if (error instanceof ScenarioNotFoundError) return Boom.notFound(error.message);
  if (error instanceof DataConflictError) return Boom.conflict(error.message);

  // Check for known error codes.
  if (error.code === 'NoSuchKey') return Boom.notFound('File not found in storage bucket');

  // Default handling.
  console.log('error', error);
  return Boom.badImplementation(error);
}
<|endoftext|>