<commit_before>/* eslint-disable no-return-assign */
/* @flow */
import React from 'react';
import ReactDOM from 'react-dom';
import { shouldComponentUpdate } from 'react-addons-pure-render-mixin';
import { DragDropContext as dragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { connect } from 'react-redux';

import { List as ImmutableList, Map as ImmutableMap } from 'immutable';

import './cell/editor/codemirror-ipython';

import {
  displayOrder,
  transforms,
} from './transforms';

import Cell from './cell/cell';
import DraggableCell from './cell/draggable-cell';
import CellCreator from './cell/cell-creator';
import StatusBar from './status-bar';
import {
  focusNextCell,
  moveCell,
} from '../actions';
import { executeCell } from '../epics/execute';

import type { CellProps } from './cell/cell';

// Always set up the markdown mode
require('codemirror/mode/markdown/markdown');

type Props = {
  displayOrder: ImmutableList<any>,
  notebook: any,
  transforms: ImmutableMap<string, any>,
  cellPagers: ImmutableMap<string, any>,
  stickyCells: ImmutableMap<string, any>,
  focusedCell: string,
  theme: string,
  lastSaved: Date,
  kernelSpecName: string,
  CellComponent: any,
  executionState: string,
};

export function getLanguageMode(notebook: any): string {
  // The syntax highlighting language should be set in the language info
  // object.  First try codemirror_mode, then name, and fallback on 'null'.
  const language =
    notebook.getIn(['metadata', 'language_info', 'codemirror_mode', 'name'],
    notebook.getIn(['metadata', 'language_info', 'codemirror_mode'],
    notebook.getIn(['metadata', 'language_info', 'name'],
    'text')));

  if (language !== 'ipython' && language !== 'text') {
    // HACK: This should give you the heeby-jeebies
    // Mostly because language could be ../../../../whatever
    // This is the notebook though, so hands off
    // We'll want to check for this existing later
    // and any other validation
    try {
      /* eslint-disable */
      require(`codemirror/mode/${language}/${language}`);
      /* eslint-enable */
    } catch (err) {
      /* istanbul ignore next */
      console.error(err);
    }
  }
  return language;
}

const mapStateToProps = (state) => ({
  theme: state.config.theme,
  lastSaved: state.app.get('lastSaved'),
  kernelSpecName: state.app.get('kernelSpecName'),
  notebook: state.document.get('notebook'),
  cellPagers: state.document.get('cellPagers'),
  focusedCell: state.document.get('focusedCell'),
  stickyCells: state.document.get('stickyCells'),
  executionState: state.app.get('executionState'),
});

export class Notebook extends React.Component {
  props: Props;
  shouldComponentUpdate: (p: Props, s: any) => boolean;
  createCellElement: (s: string) => ?React.Element<any>;
  createStickyCellElement: (s: string) => ?React.Element<any>;
  keyDown: (e: KeyboardEvent) => void;
  moveCell: (source: string, dest: string, above: string) => void;
  stickyCellsPlaceholder: HTMLElement;
  stickyCellContainer: HTMLElement;
  cellElements: ImmutableMap<string, any>;

  static defaultProps = {
    displayOrder,
    transforms,
    CellComponent: DraggableCell,
  };

  static contextTypes = {
    store: React.PropTypes.object,
  };

  constructor(): void {
    super();
    this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
    this.createCellElement = this.createCellElement.bind(this);
    this.createStickyCellElement = this.createStickyCellElement.bind(this);
    this.keyDown = this.keyDown.bind(this);
    this.moveCell = this.moveCell.bind(this);
    this.cellElements = new ImmutableMap();
  }

  componentDidMount(): void {
    document.addEventListener('keydown', this.keyDown);
  }

  componentWillReceiveProps(nextProps: Props): void {
    if (nextProps.focusedCell !== this.props.focusedCell) {
      this.resolveScrollPosition(nextProps.focusedCell);
    }
  }

  componentDidUpdate(): void {
    // Make sure the document is vertically shifted so the top non-stickied
    // cell is always visible.
    this.stickyCellsPlaceholder.style.height =
      `${this.stickyCellContainer.clientHeight}px`;
  }

  componentWillUnmount(): void {
    document.removeEventListener('keydown', this.keyDown);
  }

  moveCell(sourceId: string, destinationId: string, above: string): void {
    this.context.store.dispatch(moveCell(sourceId, destinationId, above));
  }

  keyDown(e: KeyboardEvent): void {
    if (e.keyCode !== 13) {
      return;
    }

    const shiftXORctrl = (e.shiftKey || e.ctrlKey) && !(e.shiftKey && e.ctrlKey);
    if (!shiftXORctrl) {
      return;
    }

    if (!this.props.focusedCell) {
      return;
    }

    e.preventDefault();

    const cellMap = this.props.notebook.get('cellMap');
    const id = this.props.focusedCell;
    const cell = cellMap.get(id);

    if (e.shiftKey) {
      this.context.store.dispatch(focusNextCell(this.props.focusedCell, true));
    }

    if (cell.get('cell_type') === 'code') {
      this.context.store.dispatch(
        executeCell(
          id,
          cell.get('source')
        )
      );
    }
  }

  resolveScrollPosition(id: string): void {
    const viewportHeight = window.innerHeight;
    const viewportOffset = document.body.scrollTop;

    const focusedCell = this.cellElements.get(id);

    if (focusedCell) {
      const cellTop = focusedCell.offsetTop;
      const cellHeight = focusedCell.offsetHeight;

      const belowFold = (cellTop + cellHeight) > (viewportOffset + viewportHeight);
      const aboveFold = cellTop < viewportOffset;

      if (aboveFold) {
        document.body.scrollTop = cellTop;
      }

      if (belowFold) {
        if (cellHeight > viewportHeight) {
          document.body.scrollTop = cellTop;
        } else {
          const offset = viewportHeight - cellHeight;
          document.body.scrollTop = cellTop - offset;
        }
      }
    }
  }

  createCellProps(id: string, cell: any): CellProps {
    return {
      id,
      cell,
      language: getLanguageMode(this.props.notebook),
      key: id,
      // TODO: This map _has_ to be cleaned up when cells are deleted
      ref: (el) => { this.cellElements = this.cellElements.set(id, el); },
      displayOrder: this.props.displayOrder,
      transforms: this.props.transforms,
      moveCell: this.moveCell,
      pagers: this.props.cellPagers.get(id),
      focusedCell: this.props.focusedCell,
      running: cell.get('status') === 'busy',
      // Theme is passed through to let the Editor component know when to
      // tell CodeMirror to remeasure
      theme: this.props.theme,
    };
  }

  createCellElement(id: string): ?React.Element<any> {
    const cellMap = this.props.notebook.get('cellMap');
    const cell = cellMap.get(id);
    const isStickied = this.props.stickyCells.get(id);

    const CellComponent = this.props.CellComponent;

    return (
      <div key={`cell-container-${id}`}>
        {isStickied ?

 :
            <CellComponent {...this.createCellProps(id, cell)} />}
        <CellCreator key={`creator-${id}`} id={id} above={false} />

);
  }

  createStickyCellElement(id: string): ?React.Element<any> {
    const cellMap = this.props.notebook.get('cellMap');
    const cell = cellMap.get(id);
    return (
      <div key={`cell-container-${id}`}>
        <Cell {...this.createCellProps(id, cell)} />

);
  }

  render(): ?React.Element<any> {
    if (!this.props.notebook) {
      return (

      );
    }
    const cellOrder = this.props.notebook.get('cellOrder');
    return (

 { this.stickyCellsPlaceholder = ref; }}
          />

 { this.stickyCellContainer = ref; }}
          >
            {cellOrder
              .filter(id => this.props.stickyCells.get(id))
              .map(this.createStickyCellElement)}

          <CellCreator id={cellOrder.get(0, null)} above />
          {cellOrder.map(this.createCellElement)}

        <StatusBar
          notebook={this.props.notebook}
          lastSaved={this.props.lastSaved}
          kernelSpecName={this.props.kernelSpecName}
          executionState={this.props.executionState}
        />
        <link rel="stylesheet" href={`../static/styles/theme-${this.props.theme}.css`} />

    );
  }
}

export const ConnectedNotebook = dragDropContext(HTML5Backend)(Notebook);
export default connect(mapStateToProps)(ConnectedNotebook);
<commit_msg>chore(Notebook): Resolved Redux flow errors<commit_after>/* eslint-disable no-return-assign */
/* @flow */
import React from 'react';
import ReactDOM from 'react-dom';
import { shouldComponentUpdate } from 'react-addons-pure-render-mixin';
import { DragDropContext as dragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { connect } from 'react-redux';

import { List as ImmutableList, Map as ImmutableMap } from 'immutable';

import './cell/editor/codemirror-ipython';

import {
  displayOrder,
  transforms,
} from './transforms';

import Cell from './cell/cell';
import DraggableCell from './cell/draggable-cell';
import CellCreator from './cell/cell-creator';
import StatusBar from './status-bar';
import {
  focusNextCell,
  moveCell,
} from '../actions';
import { executeCell } from '../epics/execute';

import type { CellProps } from './cell/cell';

// Always set up the markdown mode
require('codemirror/mode/markdown/markdown');

type Props = {
  displayOrder: ImmutableList<any>,
  notebook: any,
  transforms: ImmutableMap<string, any>,
  cellPagers: ImmutableMap<string, any>,
  stickyCells: ImmutableMap<string, any>,
  focusedCell: string,
  theme: string,
  lastSaved: Date,
  kernelSpecName: string,
  CellComponent: any,
  executionState: string,
};

export function getLanguageMode(notebook: any): string {
  // The syntax highlighting language should be set in the language info
  // object.  First try codemirror_mode, then name, and fallback on 'null'.
  const language =
    notebook.getIn(['metadata', 'language_info', 'codemirror_mode', 'name'],
    notebook.getIn(['metadata', 'language_info', 'codemirror_mode'],
    notebook.getIn(['metadata', 'language_info', 'name'],
    'text')));

  if (language !== 'ipython' && language !== 'text') {
    // HACK: This should give you the heeby-jeebies
    // Mostly because language could be ../../../../whatever
    // This is the notebook though, so hands off
    // We'll want to check for this existing later
    // and any other validation
    try {
      /* eslint-disable */
      require(`codemirror/mode/${language}/${language}`);
      /* eslint-enable */
    } catch (err) {
      /* istanbul ignore next */
      console.error(err);
    }
  }
  return language;
}

const mapStateToProps = (state: Object) => ({
  theme: state.config.theme,
  lastSaved: state.app.get('lastSaved'),
  kernelSpecName: state.app.get('kernelSpecName'),
  notebook: state.document.get('notebook'),
  cellPagers: state.document.get('cellPagers'),
  focusedCell: state.document.get('focusedCell'),
  stickyCells: state.document.get('stickyCells'),
  executionState: state.app.get('executionState'),
});

export class Notebook extends React.Component {
  props: Props;
  shouldComponentUpdate: (p: Props, s: any) => boolean;
  createCellElement: (s: string) => ?React.Element<any>;
  createStickyCellElement: (s: string) => ?React.Element<any>;
  keyDown: (e: KeyboardEvent) => void;
  moveCell: (source: string, dest: string, above: boolean) => void;
  stickyCellsPlaceholder: HTMLElement;
  stickyCellContainer: HTMLElement;
  cellElements: ImmutableMap<string, any>;

  static defaultProps = {
    displayOrder,
    transforms,
    CellComponent: DraggableCell,
  };

  static contextTypes = {
    store: React.PropTypes.object,
  };

  constructor(): void {
    super();
    this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
    this.createCellElement = this.createCellElement.bind(this);
    this.createStickyCellElement = this.createStickyCellElement.bind(this);
    this.keyDown = this.keyDown.bind(this);
    this.moveCell = this.moveCell.bind(this);
    this.cellElements = new ImmutableMap();
  }

  componentDidMount(): void {
    document.addEventListener('keydown', this.keyDown);
  }

  componentWillReceiveProps(nextProps: Props): void {
    if (nextProps.focusedCell !== this.props.focusedCell) {
      this.resolveScrollPosition(nextProps.focusedCell);
    }
  }

  componentDidUpdate(): void {
    // Make sure the document is vertically shifted so the top non-stickied
    // cell is always visible.
    this.stickyCellsPlaceholder.style.height =
      `${this.stickyCellContainer.clientHeight}px`;
  }

  componentWillUnmount(): void {
    document.removeEventListener('keydown', this.keyDown);
  }

  moveCell(sourceId: string, destinationId: string, above: boolean): void {
    this.context.store.dispatch(moveCell(sourceId, destinationId, above));
  }

  keyDown(e: KeyboardEvent): void {
    if (e.keyCode !== 13) {
      return;
    }

    const shiftXORctrl = (e.shiftKey || e.ctrlKey) && !(e.shiftKey && e.ctrlKey);
    if (!shiftXORctrl) {
      return;
    }

    if (!this.props.focusedCell) {
      return;
    }

    e.preventDefault();

    const cellMap = this.props.notebook.get('cellMap');
    const id = this.props.focusedCell;
    const cell = cellMap.get(id);

    if (e.shiftKey) {
      this.context.store.dispatch(focusNextCell(this.props.focusedCell, true));
    }

    if (cell.get('cell_type') === 'code') {
      this.context.store.dispatch(
        executeCell(
          id,
          cell.get('source')
        )
      );
    }
  }

  resolveScrollPosition(id: string): void {
    const viewportHeight = window.innerHeight;
    const viewportOffset = document.body.scrollTop;

    const focusedCell = this.cellElements.get(id);

    if (focusedCell) {
      const cellTop = focusedCell.offsetTop;
      const cellHeight = focusedCell.offsetHeight;

      const belowFold = (cellTop + cellHeight) > (viewportOffset + viewportHeight);
      const aboveFold = cellTop < viewportOffset;

      if (aboveFold) {
        document.body.scrollTop = cellTop;
      }

      if (belowFold) {
        if (cellHeight > viewportHeight) {
          document.body.scrollTop = cellTop;
        } else {
          const offset = viewportHeight - cellHeight;
          document.body.scrollTop = cellTop - offset;
        }
      }
    }
  }

  createCellProps(id: string, cell: any): CellProps {
    return {
      id,
      cell,
      language: getLanguageMode(this.props.notebook),
      key: id,
      // TODO: This map _has_ to be cleaned up when cells are deleted
      ref: (el) => { this.cellElements = this.cellElements.set(id, el); },
      displayOrder: this.props.displayOrder,
      transforms: this.props.transforms,
      moveCell: this.moveCell,
      pagers: this.props.cellPagers.get(id),
      focusedCell: this.props.focusedCell,
      running: cell.get('status') === 'busy',
      // Theme is passed through to let the Editor component know when to
      // tell CodeMirror to remeasure
      theme: this.props.theme,
    };
  }

  createCellElement(id: string): ?React.Element<any> {
    const cellMap = this.props.notebook.get('cellMap');
    const cell = cellMap.get(id);
    const isStickied = this.props.stickyCells.get(id);

    const CellComponent = this.props.CellComponent;

    return (
      <div key={`cell-container-${id}`}>
        {isStickied ?

 :
            <CellComponent {...this.createCellProps(id, cell)} />}
        <CellCreator key={`creator-${id}`} id={id} above={false} />

);
  }

  createStickyCellElement(id: string): ?React.Element<any> {
    const cellMap = this.props.notebook.get('cellMap');
    const cell = cellMap.get(id);
    return (
      <div key={`cell-container-${id}`}>
        <Cell {...this.createCellProps(id, cell)} />

);
  }

  render(): ?React.Element<any> {
    if (!this.props.notebook) {
      return (

      );
    }
    const cellOrder = this.props.notebook.get('cellOrder');
    return (

 { this.stickyCellsPlaceholder = ref; }}
          />

 { this.stickyCellContainer = ref; }}
          >
            {cellOrder
              .filter(id => this.props.stickyCells.get(id))
              .map(this.createStickyCellElement)}

          <CellCreator id={cellOrder.get(0, null)} above />
          {cellOrder.map(this.createCellElement)}

        <StatusBar
          notebook={this.props.notebook}
          lastSaved={this.props.lastSaved}
          kernelSpecName={this.props.kernelSpecName}
          executionState={this.props.executionState}
        />
        <link rel="stylesheet" href={`../static/styles/theme-${this.props.theme}.css`} />

    );
  }
}

export const ConnectedNotebook = dragDropContext(HTML5Backend)(Notebook);
export default connect(mapStateToProps)(ConnectedNotebook);
<|endoftext|>


<commit_before>goog.provide('ol.control.FullScreen');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.dom.fullscreen');
goog.require('goog.dom.fullscreen.EventType');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol');
goog.require('ol.control.Control');
goog.require('ol.css');

/**
 * @classdesc
 * Provides a button that when clicked fills up the full screen with the map.
 * The full screen source element is by default the element containing the map viewport unless
 * overriden by providing the `source` option. In which case, the dom
 * element introduced using this parameter will be displayed in full screen.
 *
 * When in full screen mode, a close button is shown to exit full screen mode.
 * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
 * toggle the map in full screen mode.
 *
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.FullScreenOptions=} opt_options Options.
 * @api stable
 */
ol.control.FullScreen = function(opt_options) {

  var options = opt_options ? opt_options : {};

  /**
   * @private
   * @type {string}
   */
  this.cssClassName_ = options.className ? options.className : 'ol-full-screen';

  var label = options.label ? options.label : '\u2922';

  /**
   * @private
   * @type {Node}
   */
  this.labelNode_ = typeof label === 'string' ?
      document.createTextNode(label) : label;

  var labelActive = options.labelActive ? options.labelActive : '\u00d7';

  /**
   * @private
   * @type {Node}
   */
  this.labelActiveNode_ = typeof labelActive === 'string' ?
      document.createTextNode(labelActive) : labelActive;

  var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
  var button = goog.dom.createDom('BUTTON', {
    'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(),
    'type': 'button',
    'title': tipLabel
  }, this.labelNode_);

  ol.events.listen(button, ol.events.EventType.CLICK,
      this.handleClick_, this);

  ol.events.listen(goog.global.document,
      goog.dom.fullscreen.EventType.CHANGE,
      this.handleFullScreenChange_, this);

  var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +
      ' ' + ol.css.CLASS_CONTROL + ' ' +
      (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '');
  var element = goog.dom.createDom('DIV', cssClasses, button);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @private
   * @type {boolean}
   */
  this.keys_ = options.keys !== undefined ? options.keys : false;

  /**
   * @private
   * @type {Element|string|undefined}
   */
  this.source_ = options.source;

};
goog.inherits(ol.control.FullScreen, ol.control.Control);

/**
 * @param {Event} event The event to handle
 * @private
 */
ol.control.FullScreen.prototype.handleClick_ = function(event) {
  event.preventDefault();
  this.handleFullScreen_();
};

/**
 * @private
 */
ol.control.FullScreen.prototype.handleFullScreen_ = function() {
  if (!goog.dom.fullscreen.isSupported()) {
    return;
  }
  var map = this.getMap();
  if (!map) {
    return;
  }
  if (goog.dom.fullscreen.isFullScreen()) {
    goog.dom.fullscreen.exitFullScreen();
  } else {
    var element = this.source_ ?
        goog.dom.getElement(this.source_) : map.getTargetElement();
    goog.asserts.assert(element, 'element should be defined');
    if (this.keys_) {
      goog.dom.fullscreen.requestFullScreenWithKeys(element);
    } else {
      goog.dom.fullscreen.requestFullScreen(element);
    }
  }
};

/**
 * @private
 */
ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
  var opened = this.cssClassName_ + '-true';
  var closed = this.cssClassName_ + '-false';
  var button = goog.dom.getFirstElementChild(this.element);
  var map = this.getMap();
  if (goog.dom.fullscreen.isFullScreen()) {
    goog.dom.classlist.swap(button, closed, opened);
    goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_);
  } else {
    goog.dom.classlist.swap(button, opened, closed);
    goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_);
  }
  if (map) {
    map.updateSize();
  }
};
<commit_msg>Fix checks for undefined in fullscreencontrol<commit_after>goog.provide('ol.control.FullScreen');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.dom.fullscreen');
goog.require('goog.dom.fullscreen.EventType');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol');
goog.require('ol.control.Control');
goog.require('ol.css');

/**
 * @classdesc
 * Provides a button that when clicked fills up the full screen with the map.
 * The full screen source element is by default the element containing the map viewport unless
 * overriden by providing the `source` option. In which case, the dom
 * element introduced using this parameter will be displayed in full screen.
 *
 * When in full screen mode, a close button is shown to exit full screen mode.
 * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
 * toggle the map in full screen mode.
 *
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.FullScreenOptions=} opt_options Options.
 * @api stable
 */
ol.control.FullScreen = function(opt_options) {

  var options = opt_options ? opt_options : {};

  /**
   * @private
   * @type {string}
   */
  this.cssClassName_ = options.className !== undefined ? options.className :
      'ol-full-screen';

  var label = options.label !== undefined ? options.label : '\u2922';

  /**
   * @private
   * @type {Node}
   */
  this.labelNode_ = typeof label === 'string' ?
      document.createTextNode(label) : label;

  var labelActive = options.labelActive !== undefined ? options.labelActive : '\u00d7';

  /**
   * @private
   * @type {Node}
   */
  this.labelActiveNode_ = typeof labelActive === 'string' ?
      document.createTextNode(labelActive) : labelActive;

  var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
  var button = goog.dom.createDom('BUTTON', {
    'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(),
    'type': 'button',
    'title': tipLabel
  }, this.labelNode_);

  ol.events.listen(button, ol.events.EventType.CLICK,
      this.handleClick_, this);

  ol.events.listen(goog.global.document,
      goog.dom.fullscreen.EventType.CHANGE,
      this.handleFullScreenChange_, this);

  var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +
      ' ' + ol.css.CLASS_CONTROL + ' ' +
      (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '');
  var element = goog.dom.createDom('DIV', cssClasses, button);

  goog.base(this, {
    element: element,
    target: options.target
  });

  /**
   * @private
   * @type {boolean}
   */
  this.keys_ = options.keys !== undefined ? options.keys : false;

  /**
   * @private
   * @type {Element|string|undefined}
   */
  this.source_ = options.source;

};
goog.inherits(ol.control.FullScreen, ol.control.Control);

/**
 * @param {Event} event The event to handle
 * @private
 */
ol.control.FullScreen.prototype.handleClick_ = function(event) {
  event.preventDefault();
  this.handleFullScreen_();
};

/**
 * @private
 */
ol.control.FullScreen.prototype.handleFullScreen_ = function() {
  if (!goog.dom.fullscreen.isSupported()) {
    return;
  }
  var map = this.getMap();
  if (!map) {
    return;
  }
  if (goog.dom.fullscreen.isFullScreen()) {
    goog.dom.fullscreen.exitFullScreen();
  } else {
    var element = this.source_ ?
        goog.dom.getElement(this.source_) : map.getTargetElement();
    goog.asserts.assert(element, 'element should be defined');
    if (this.keys_) {
      goog.dom.fullscreen.requestFullScreenWithKeys(element);
    } else {
      goog.dom.fullscreen.requestFullScreen(element);
    }
  }
};

/**
 * @private
 */
ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
  var opened = this.cssClassName_ + '-true';
  var closed = this.cssClassName_ + '-false';
  var button = goog.dom.getFirstElementChild(this.element);
  var map = this.getMap();
  if (goog.dom.fullscreen.isFullScreen()) {
    goog.dom.classlist.swap(button, closed, opened);
    goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_);
  } else {
    goog.dom.classlist.swap(button, opened, closed);
    goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_);
  }
  if (map) {
    map.updateSize();
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import reactMixin from 'react-mixin';
import { ExpandedStateHandlerMixin } from './mixins';
import JSONArrow from './JSONArrow';
import grabNode from './grab-node';

const styles = {
  base: {
    paddingTop: 2,
    paddingBottom: 2,
    paddingRight: 4,
    letterSpacing: 1,
    marginLeft: 10
  },
  label: {
    margin: 0,
    padding: 0,
    display: 'inline-block'
  },
  span: {
    fontSize: '0.85em',
    cursor: 'default'
  },
  spanType: {
    marginLeft: 5,
    marginRight: 5,
    fontSize: '1em'
  }
};

@reactMixin.decorate(ExpandedStateHandlerMixin)
export default class JSONObjectNode extends React.Component {
  defaultProps = {
    data: [],
    initialExpanded: false
  };
  // cache store for the number of items string we display
  itemString = false;

  // flag to see if we still need to render our child nodes
  needsChildNodes = true;

  // cache store for our child nodes
  renderedChildren = [];

  constructor(props) {
    super(props);
    this.state = {
      expanded: this.props.initialExpanded,
      createdChildNodes: false
    };
  }

  // Returns the child nodes for each element in the object. If we have
  // generated them previously, we return from cache, otherwise we create
  // them.
  getChildNodes() {
    if (this.state.expanded && this.needsChildNodes) {
      const obj = this.props.data;
      let childNodes = [];
      for (let k in obj) {
        if (obj.hasOwnProperty(k)) {
          let prevData;
          if (typeof this.props.previousData !== 'undefined') {
            prevData = this.props.previousData[k];
          }
          childNodes.push(grabNode(k, obj[k], prevData, this.props.theme));
        }
      }
      this.needsChildNodes = false;
      this.renderedChildren = childNodes;
    }
    return this.renderedChildren;
  }

  // Returns the "n Items" string for this node, generating and
  // caching it if it hasn't been created yet.
  getItemString() {
    if (!this.itemString) {
      const len = Object.keys(this.props.data).length;
      this.itemString = len + ' Item' + (len > 1 ? 's' : '');
    }
    return this.itemString;
  }

  render() {
    let childListStyle = {
      padding: 0,
      margin: 0,
      listStyle: 'none',
      display: (this.state.expanded) ? 'block' : 'none'
    };
    let containerStyle;
    let spanStyle = {
      ...styles.span,
      color: this.props.theme.base0B
    };
    containerStyle = {
      ...styles.base,
      ...styles.parentNode
    };
    if (this.state.expanded) {
      spanStyle = {
        ...spanStyle,
        color: this.props.theme.base05
      };
    }
    return (

        <JSONArrow theme={this.props.theme} open={this.state.expanded}/>

          {this.props.keyName}:

          {}
          {this.getItemString()}

          {this.getChildNodes()}

    );
  }
}
<commit_msg>renamed Items to Keys for clarity<commit_after>import React from 'react';
import reactMixin from 'react-mixin';
import { ExpandedStateHandlerMixin } from './mixins';
import JSONArrow from './JSONArrow';
import grabNode from './grab-node';

const styles = {
  base: {
    paddingTop: 2,
    paddingBottom: 2,
    paddingRight: 4,
    letterSpacing: 1,
    marginLeft: 10
  },
  label: {
    margin: 0,
    padding: 0,
    display: 'inline-block'
  },
  span: {
    fontSize: '0.85em',
    cursor: 'default'
  },
  spanType: {
    marginLeft: 5,
    marginRight: 5,
    fontSize: '1em'
  }
};

@reactMixin.decorate(ExpandedStateHandlerMixin)
export default class JSONObjectNode extends React.Component {
  defaultProps = {
    data: [],
    initialExpanded: false
  };
  // cache store for the number of items string we display
  itemString = false;

  // flag to see if we still need to render our child nodes
  needsChildNodes = true;

  // cache store for our child nodes
  renderedChildren = [];

  constructor(props) {
    super(props);
    this.state = {
      expanded: this.props.initialExpanded,
      createdChildNodes: false
    };
  }

  // Returns the child nodes for each element in the object. If we have
  // generated them previously, we return from cache, otherwise we create
  // them.
  getChildNodes() {
    if (this.state.expanded && this.needsChildNodes) {
      const obj = this.props.data;
      let childNodes = [];
      for (let k in obj) {
        if (obj.hasOwnProperty(k)) {
          let prevData;
          if (typeof this.props.previousData !== 'undefined') {
            prevData = this.props.previousData[k];
          }
          childNodes.push(grabNode(k, obj[k], prevData, this.props.theme));
        }
      }
      this.needsChildNodes = false;
      this.renderedChildren = childNodes;
    }
    return this.renderedChildren;
  }

  // Returns the "n Items" string for this node, generating and
  // caching it if it hasn't been created yet.
  getItemString() {
    if (!this.itemString) {
      const len = Object.keys(this.props.data).length;
      this.itemString = len + ' Key' + (len > 1 ? 's' : '');
    }
    return this.itemString;
  }

  render() {
    let childListStyle = {
      padding: 0,
      margin: 0,
      listStyle: 'none',
      display: (this.state.expanded) ? 'block' : 'none'
    };
    let containerStyle;
    let spanStyle = {
      ...styles.span,
      color: this.props.theme.base0B
    };
    containerStyle = {
      ...styles.base,
      ...styles.parentNode
    };
    if (this.state.expanded) {
      spanStyle = {
        ...spanStyle,
        color: this.props.theme.base05
      };
    }
    return (

        <JSONArrow theme={this.props.theme} open={this.state.expanded}/>

          {this.props.keyName}:

          {}
          {this.getItemString()}

          {this.getChildNodes()}

    );
  }
}
<|endoftext|>


<commit_before>/**
 * This file contains "high level" action creators. An action creator is
 * considered high level if it:
 *   - Doesn't create actions directly
 *   - Calls one or more other action creators
 */

const _ = require('lodash');
const fetch = require('../helpers/fetch');
const simpleActionCreators = require('./simpleActionCreators');

const actionCreators = _.clone(simpleActionCreators.notebooks);

const flattenResource = (resource) =>
  _.assign({ id: parseInt(resource.id, 10) }, resource.attributes);

actionCreators.updateFrame = (frame) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/frame/${frame.id}`, {
      method: 'put',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ frame: _.pick(frame, ['x', 'y', 'width', 'height']) })
    }).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.modifyFrame(data));
        resolve(data.frame);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to update frame');
      reject(err);
    });
  });

actionCreators.updateNotebook = (notebook) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/notebook/${notebook.id}`, {
      method: 'put',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ notebook })
    }).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.addNotebook(data.notebook));
        dispatch(simpleActionCreators.tags.removeTagsFromNotebook(data.notebook.id));
        dispatch(simpleActionCreators.tags.addTags(data.notebook.tags));
        resolve(data.notebook);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to update notebook');
      reject(err);
    });
  });

actionCreators.loadNotebook = (notebookId) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/notebook/${notebookId}`).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.addNotebook(data.notebook));
        resolve(data.notebook);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to load notebook');
      reject(err);
    });
  });

actionCreators.loadNotebooksShallow = () => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch('/api/v2/notebooks').then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        const notebooks = data.data.map(flattenResource);
        dispatch(actionCreators.addNotebooks(notebooks));
        resolve(notebooks);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to load notebook');
      reject(err);
    });
  });

actionCreators.deleteNotebook = (notebookId) => (dispatch) =>
  fetch(`/api/notebook/${notebookId}`, { method: 'delete' }).then((res) => {
    if(!res.ok) throw new Error(res.statusText);
    dispatch(actionCreators.removeTagsFromNotebook(notebookId));
    dispatch(actionCreators.removeNotebook(notebookId));
  }).catch((err) => {
    console.error(err);
    alert('Failed to delete notebook');
  });

module.exports = actionCreators;
<commit_msg>Fix notebook removal bug<commit_after>/**
 * This file contains "high level" action creators. An action creator is
 * considered high level if it:
 *   - Doesn't create actions directly
 *   - Calls one or more other action creators
 */

const _ = require('lodash');
const fetch = require('../helpers/fetch');
const simpleActionCreators = require('./simpleActionCreators');

const actionCreators = _.clone(simpleActionCreators.notebooks);

const flattenResource = (resource) =>
  _.assign({ id: parseInt(resource.id, 10) }, resource.attributes);

actionCreators.updateFrame = (frame) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/frame/${frame.id}`, {
      method: 'put',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ frame: _.pick(frame, ['x', 'y', 'width', 'height']) })
    }).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.modifyFrame(data));
        resolve(data.frame);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to update frame');
      reject(err);
    });
  });

actionCreators.updateNotebook = (notebook) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/notebook/${notebook.id}`, {
      method: 'put',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ notebook })
    }).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.addNotebook(data.notebook));
        dispatch(simpleActionCreators.tags.removeTagsFromNotebook(data.notebook.id));
        dispatch(simpleActionCreators.tags.addTags(data.notebook.tags));
        resolve(data.notebook);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to update notebook');
      reject(err);
    });
  });

actionCreators.loadNotebook = (notebookId) => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch(`/api/notebook/${notebookId}`).then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        dispatch(actionCreators.addNotebook(data.notebook));
        resolve(data.notebook);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to load notebook');
      reject(err);
    });
  });

actionCreators.loadNotebooksShallow = () => (dispatch) =>
  new Promise((resolve, reject) => {
    fetch('/api/v2/notebooks').then((res) => {
      if(!res.ok) throw new Error(res.statusText);
      res.json().then((data) => {
        const notebooks = data.data.map(flattenResource);
        dispatch(actionCreators.addNotebooks(notebooks));
        resolve(notebooks);
      }).catch(reject);
    }).catch((err) => {
      console.error(err);
      alert('Failed to load notebook');
      reject(err);
    });
  });

actionCreators.deleteNotebook = (notebookId) => (dispatch) =>
  fetch(`/api/notebook/${notebookId}`, { method: 'delete' }).then((res) => {
    if(!res.ok) throw new Error(res.statusText);
    dispatch(simpleActionCreators.tags.removeTagsFromNotebook(notebookId));
    dispatch(actionCreators.removeNotebook(notebookId));
  }).catch((err) => {
    console.error(err);
    alert('Failed to delete notebook');
  });

module.exports = actionCreators;
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { BackSide, DoubleSide, FlatShading, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding } from '../../constants';
import { WebGLProgram } from './WebGLProgram';

function WebGLPrograms( renderer, capabilities ) {

	var programs = [];

	var shaderIDs = {
		MeshDepthMaterial: 'depth',
		MeshNormalMaterial: 'normal',
		MeshBasicMaterial: 'basic',
		MeshLambertMaterial: 'lambert',
		MeshPhongMaterial: 'phong',
		MeshToonMaterial: 'phong',
		MeshStandardMaterial: 'physical',
		MeshPhysicalMaterial: 'physical',
		LineBasicMaterial: 'basic',
		LineDashedMaterial: 'dashed',
		PointsMaterial: 'points'
	};

	var parameterNames = [
		"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
		"roughnessMap", "metalnessMap", "gradientMap",
		"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
		"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
		"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
		"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
		"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
	];

	function allocateBones( object ) {

		var skeleton = object.skeleton;
		var bones = skeleton.bones;

		if ( capabilities.floatVertexTextures ) {

			return 1024;

		} else {

			// default for when object is not specified
			// ( for example when prebuilding shader to be used with multiple objects )
			//
			//  - leave some extra space for other uniforms
			//  - limit here is ANGLE's 254 max uniform vectors
			//    (up to 54 should be safe)

			var nVertexUniforms = capabilities.maxVertexUniforms;
			var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );

			var maxBones = Math.min( nVertexMatrices, bones.length );

			if ( maxBones < bones.length ) {

				console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
				return 0;

			}

			return maxBones;

		}

	}

	function getTextureEncodingFromMap( map, gammaOverrideLinear ) {

		var encoding;

		if ( ! map ) {

			encoding = LinearEncoding;

		} else if ( map.isTexture ) {

			encoding = map.encoding;

		} else if ( map.isWebGLRenderTarget ) {

			console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
			encoding = map.texture.encoding;

		}

		// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
		if ( encoding === LinearEncoding && gammaOverrideLinear ) {

			encoding = GammaEncoding;

		}

		return encoding;

	}

	this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {

		var shaderID = shaderIDs[ material.type ];

		// heuristics to create shader parameters according to lights in the scene
		// (not to blow over maxLights budget)

		var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
		var precision = renderer.getPrecision();

		if ( material.precision !== null ) {

			precision = capabilities.getMaxPrecision( material.precision );

			if ( precision !== material.precision ) {

				console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );

			}

		}

		var currentRenderTarget = renderer.getRenderTarget();

		var parameters = {

			shaderID: shaderID,

			precision: precision,
			supportsVertexTextures: capabilities.vertexTextures,
			outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
			map: !! material.map,
			mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
			envMap: !! material.envMap,
			envMapMode: material.envMap && material.envMap.mapping,
			envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
			envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
			lightMap: !! material.lightMap,
			aoMap: !! material.aoMap,
			emissiveMap: !! material.emissiveMap,
			emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
			bumpMap: !! material.bumpMap,
			normalMap: !! material.normalMap,
			displacementMap: !! material.displacementMap,
			roughnessMap: !! material.roughnessMap,
			metalnessMap: !! material.metalnessMap,
			specularMap: !! material.specularMap,
			alphaMap: !! material.alphaMap,

			gradientMap: !! material.gradientMap,

			combine: material.combine,

			vertexColors: material.vertexColors,

			fog: !! fog,
			useFog: material.fog,
			fogExp: ( fog && fog.isFogExp2 ),

			flatShading: material.shading === FlatShading,

			sizeAttenuation: material.sizeAttenuation,
			logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,

			skinning: material.skinning && maxBones > 0,
			maxBones: maxBones,
			useVertexTexture: capabilities.floatVertexTextures,

			morphTargets: material.morphTargets,
			morphNormals: material.morphNormals,
			maxMorphTargets: renderer.maxMorphTargets,
			maxMorphNormals: renderer.maxMorphNormals,

			numDirLights: lights.directional.length,
			numPointLights: lights.point.length,
			numSpotLights: lights.spot.length,
			numRectAreaLights: lights.rectArea.length,
			numHemiLights: lights.hemi.length,

			numClippingPlanes: nClipPlanes,
			numClipIntersection: nClipIntersection,

			dithering: material.dithering,

			shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
			shadowMapType: renderer.shadowMap.type,

			toneMapping: renderer.toneMapping,
			physicallyCorrectLights: renderer.physicallyCorrectLights,

			premultipliedAlpha: material.premultipliedAlpha,

			alphaTest: material.alphaTest,
			doubleSided: material.side === DoubleSide,
			flipSided: material.side === BackSide,

			depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false

		};

		return parameters;

	};

	this.getProgramCode = function ( material, parameters ) {

		var array = [];

		if ( parameters.shaderID ) {

			array.push( parameters.shaderID );

		} else {

			array.push( material.fragmentShader );
			array.push( material.vertexShader );

		}

		if ( material.defines !== undefined ) {

			for ( var name in material.defines ) {

				array.push( name );
				array.push( material.defines[ name ] );

			}

		}

		for ( var i = 0; i < parameterNames.length; i ++ ) {

			array.push( parameters[ parameterNames[ i ] ] );

		}

		return array.join();

	};

	this.acquireProgram = function ( material, parameters, code ) {

		var program;

		// Check if code has been already compiled
		for ( var p = 0, pl = programs.length; p < pl; p ++ ) {

			var programInfo = programs[ p ];

			if ( programInfo.code === code ) {

				program = programInfo;
				++ program.usedTimes;

				break;

			}

		}

		if ( program === undefined ) {

			program = new WebGLProgram( renderer, code, material, parameters );
			programs.push( program );

		}

		return program;

	};

	this.releaseProgram = function ( program ) {

		if ( -- program.usedTimes === 0 ) {

			// Remove from unordered set
			var i = programs.indexOf( program );
			programs[ i ] = programs[ programs.length - 1 ];
			programs.pop();

			// Free WebGL resources
			program.destroy();

		}

	};

	// Exposed for resource monitoring & error feedback via renderer.info:
	this.programs = programs;

}

export { WebGLPrograms };
<commit_msg>Add renderer.gammaOutput to program code<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

import { BackSide, DoubleSide, FlatShading, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding } from '../../constants';
import { WebGLProgram } from './WebGLProgram';

function WebGLPrograms( renderer, capabilities ) {

	var programs = [];

	var shaderIDs = {
		MeshDepthMaterial: 'depth',
		MeshNormalMaterial: 'normal',
		MeshBasicMaterial: 'basic',
		MeshLambertMaterial: 'lambert',
		MeshPhongMaterial: 'phong',
		MeshToonMaterial: 'phong',
		MeshStandardMaterial: 'physical',
		MeshPhysicalMaterial: 'physical',
		LineBasicMaterial: 'basic',
		LineDashedMaterial: 'dashed',
		PointsMaterial: 'points'
	};

	var parameterNames = [
		"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
		"roughnessMap", "metalnessMap", "gradientMap",
		"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
		"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
		"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
		"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
		"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
	];

	function allocateBones( object ) {

		var skeleton = object.skeleton;
		var bones = skeleton.bones;

		if ( capabilities.floatVertexTextures ) {

			return 1024;

		} else {

			// default for when object is not specified
			// ( for example when prebuilding shader to be used with multiple objects )
			//
			//  - leave some extra space for other uniforms
			//  - limit here is ANGLE's 254 max uniform vectors
			//    (up to 54 should be safe)

			var nVertexUniforms = capabilities.maxVertexUniforms;
			var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );

			var maxBones = Math.min( nVertexMatrices, bones.length );

			if ( maxBones < bones.length ) {

				console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
				return 0;

			}

			return maxBones;

		}

	}

	function getTextureEncodingFromMap( map, gammaOverrideLinear ) {

		var encoding;

		if ( ! map ) {

			encoding = LinearEncoding;

		} else if ( map.isTexture ) {

			encoding = map.encoding;

		} else if ( map.isWebGLRenderTarget ) {

			console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
			encoding = map.texture.encoding;

		}

		// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
		if ( encoding === LinearEncoding && gammaOverrideLinear ) {

			encoding = GammaEncoding;

		}

		return encoding;

	}

	this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {

		var shaderID = shaderIDs[ material.type ];

		// heuristics to create shader parameters according to lights in the scene
		// (not to blow over maxLights budget)

		var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
		var precision = renderer.getPrecision();

		if ( material.precision !== null ) {

			precision = capabilities.getMaxPrecision( material.precision );

			if ( precision !== material.precision ) {

				console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );

			}

		}

		var currentRenderTarget = renderer.getRenderTarget();

		var parameters = {

			shaderID: shaderID,

			precision: precision,
			supportsVertexTextures: capabilities.vertexTextures,
			outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
			map: !! material.map,
			mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
			envMap: !! material.envMap,
			envMapMode: material.envMap && material.envMap.mapping,
			envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
			envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
			lightMap: !! material.lightMap,
			aoMap: !! material.aoMap,
			emissiveMap: !! material.emissiveMap,
			emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
			bumpMap: !! material.bumpMap,
			normalMap: !! material.normalMap,
			displacementMap: !! material.displacementMap,
			roughnessMap: !! material.roughnessMap,
			metalnessMap: !! material.metalnessMap,
			specularMap: !! material.specularMap,
			alphaMap: !! material.alphaMap,

			gradientMap: !! material.gradientMap,

			combine: material.combine,

			vertexColors: material.vertexColors,

			fog: !! fog,
			useFog: material.fog,
			fogExp: ( fog && fog.isFogExp2 ),

			flatShading: material.shading === FlatShading,

			sizeAttenuation: material.sizeAttenuation,
			logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,

			skinning: material.skinning && maxBones > 0,
			maxBones: maxBones,
			useVertexTexture: capabilities.floatVertexTextures,

			morphTargets: material.morphTargets,
			morphNormals: material.morphNormals,
			maxMorphTargets: renderer.maxMorphTargets,
			maxMorphNormals: renderer.maxMorphNormals,

			numDirLights: lights.directional.length,
			numPointLights: lights.point.length,
			numSpotLights: lights.spot.length,
			numRectAreaLights: lights.rectArea.length,
			numHemiLights: lights.hemi.length,

			numClippingPlanes: nClipPlanes,
			numClipIntersection: nClipIntersection,

			dithering: material.dithering,

			shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
			shadowMapType: renderer.shadowMap.type,

			toneMapping: renderer.toneMapping,
			physicallyCorrectLights: renderer.physicallyCorrectLights,

			premultipliedAlpha: material.premultipliedAlpha,

			alphaTest: material.alphaTest,
			doubleSided: material.side === DoubleSide,
			flipSided: material.side === BackSide,

			depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false

		};

		return parameters;

	};

	this.getProgramCode = function ( material, parameters ) {

		var array = [];

		if ( parameters.shaderID ) {

			array.push( parameters.shaderID );

		} else {

			array.push( material.fragmentShader );
			array.push( material.vertexShader );

		}

		if ( material.defines !== undefined ) {

			for ( var name in material.defines ) {

				array.push( name );
				array.push( material.defines[ name ] );

			}

		}

		for ( var i = 0; i < parameterNames.length; i ++ ) {

			array.push( parameters[ parameterNames[ i ] ] );

		}

		array.push( renderer.gammaOutput );

		return array.join();

	};

	this.acquireProgram = function ( material, parameters, code ) {

		var program;

		// Check if code has been already compiled
		for ( var p = 0, pl = programs.length; p < pl; p ++ ) {

			var programInfo = programs[ p ];

			if ( programInfo.code === code ) {

				program = programInfo;
				++ program.usedTimes;

				break;

			}

		}

		if ( program === undefined ) {

			program = new WebGLProgram( renderer, code, material, parameters );
			programs.push( program );

		}

		return program;

	};

	this.releaseProgram = function ( program ) {

		if ( -- program.usedTimes === 0 ) {

			// Remove from unordered set
			var i = programs.indexOf( program );
			programs[ i ] = programs[ programs.length - 1 ];
			programs.pop();

			// Free WebGL resources
			program.destroy();

		}

	};

	// Exposed for resource monitoring & error feedback via renderer.info:
	this.programs = programs;

}

export { WebGLPrograms };
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global', 'sap/ui/core/Renderer', './InputBaseRenderer'],
	function(jQuery, Renderer, InputBaseRenderer) {
	"use strict";

	/**
	 * Input renderer.
	 * @namespace
	 *
	 * InputRenderer extends the InputBaseRenderer
	 */
	var InputRenderer = Renderer.extend(InputBaseRenderer);

	/**
	 * Adds control specific class
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterClasses = function(oRm, oControl) {
		oRm.addClass("sapMInput");
		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			oRm.addClass("sapMInputVH");
			if (oControl.getValueHelpOnly()) {
				oRm.addClass("sapMInputVHO");
			}
		}
		if (oControl.getDescription()) {
				oRm.addClass("sapMInputDescription");
		}
	};

	/**
	 * Add extra styles for input container
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterStyles = function(oRm, oControl) {
	};

	/**
	 * add extra attributes to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerAttributes = function(oRm, oControl) {
		oRm.writeAttribute("type", oControl.getType().toLowerCase());
		if ((!oControl.getEnabled() && oControl.getType() == "Password")
				|| (oControl.getShowSuggestion() && oControl._bUseDialog)
				|| (oControl.getValueHelpOnly() && oControl.getEnabled() && oControl.getEditable() && oControl.getShowValueHelp())) {
			// required for JAWS reader on password fields on desktop and in other cases:
			oRm.writeAttribute("readonly", "readonly");
		}
	};

	/**
	 * Adds inner css classes to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerClasses = function(oRm, oControl) {
	};

	/**
	 * Add inner styles to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerStyles = function(oRm, oControl) {

		if (oControl.getDescription()) {
			oRm.addStyle("width", oControl.getFieldWidth() || "50%");
		}
	};

	/**
	 * add extra content to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerContent = function(oRm, oControl) {

		if (!oControl.getDescription()) {
			this.writeValueHelpIcon(oRm, oControl);
		}else {
			var sDescription = oControl.getDescription();
			oRm.write("");
			this.writeValueHelpIcon(oRm, oControl);
			oRm.writeEscaped(sDescription);
			oRm.write("");
		}

		if (sap.ui.getCore().getConfiguration().getAccessibility()) {
			if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
				oRm.write("");
			}
		}

	};

	InputRenderer.writeValueHelpIcon = function(oRm, oControl) {

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			oRm.write('
');
			oRm.renderControl(oControl._getValueHelpIcon());
			oRm.write("
");
		}

	};

	/**
	 * Add inner styles to the placeholder
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addPlaceholderStyles = function(oRm, oControl) {

		if (oControl.getDescription()) {
			oRm.addStyle("width", oControl.getFieldWidth() || "50%");
		}

	};

	InputRenderer.getAriaDescribedBy = function(oControl) {

		var sAriaDescribedBy = InputBaseRenderer.getAriaDescribedBy.apply(this, arguments);

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			if (sAriaDescribedBy) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl._sAriaValueHelpLabelId;
			} else {
				sAriaDescribedBy = oControl._sAriaValueHelpLabelId;
			}
			if (oControl.getValueHelpOnly()) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl._sAriaInputDisabledLabelId;
			}
		}

		if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
			if (sAriaDescribedBy) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl.getId() + "-SuggDescr";
			} else {
				sAriaDescribedBy = oControl.getId() + "-SuggDescr";
			}
		}

		return sAriaDescribedBy;

	};

	InputRenderer.getAccessibilityState = function(oControl) {

		var mAccessibilityState = InputBaseRenderer.getAccessibilityState.apply(this, arguments);

		if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
			mAccessibilityState.autocomplete = "list";
		}

		return mAccessibilityState;

	};

	return InputRenderer;

}, /* bExport= */ true);
<commit_msg>[INTERNAL] ARIA label for sap.m.Input with descriptions<commit_after>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global', 'sap/ui/core/Renderer', './InputBaseRenderer'],
	function(jQuery, Renderer, InputBaseRenderer) {
	"use strict";

	/**
	 * Input renderer.
	 * @namespace
	 *
	 * InputRenderer extends the InputBaseRenderer
	 */
	var InputRenderer = Renderer.extend(InputBaseRenderer);

	/**
	 * Adds control specific class
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterClasses = function(oRm, oControl) {
		oRm.addClass("sapMInput");
		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			oRm.addClass("sapMInputVH");
			if (oControl.getValueHelpOnly()) {
				oRm.addClass("sapMInputVHO");
			}
		}
		if (oControl.getDescription()) {
				oRm.addClass("sapMInputDescription");
		}
	};

	/**
	 * Add extra styles for input container
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterStyles = function(oRm, oControl) {
	};

	/**
	 * add extra attributes to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerAttributes = function(oRm, oControl) {
		oRm.writeAttribute("type", oControl.getType().toLowerCase());
		if ((!oControl.getEnabled() && oControl.getType() == "Password")
				|| (oControl.getShowSuggestion() && oControl._bUseDialog)
				|| (oControl.getValueHelpOnly() && oControl.getEnabled() && oControl.getEditable() && oControl.getShowValueHelp())) {
			// required for JAWS reader on password fields on desktop and in other cases:
			oRm.writeAttribute("readonly", "readonly");
		}
	};

	/**
	 * Adds inner css classes to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerClasses = function(oRm, oControl) {
	};

	/**
	 * Add inner styles to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerStyles = function(oRm, oControl) {

		if (oControl.getDescription()) {
			oRm.addStyle("width", oControl.getFieldWidth() || "50%");
		}
	};

	/**
	 * add extra content to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerContent = function(oRm, oControl) {

		var id = oControl.getId(),
			description = oControl.getDescription();

		if (!description) {
			this.writeValueHelpIcon(oRm, oControl);
		} else {
			oRm.write("");
			this.writeValueHelpIcon(oRm, oControl);
			oRm.writeEscaped(description);
			oRm.write("");
		}

		if (sap.ui.getCore().getConfiguration().getAccessibility()) {
			if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
				oRm.write("");
			}
		}

	};

	InputRenderer.writeValueHelpIcon = function(oRm, oControl) {

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			oRm.write('
');
			oRm.renderControl(oControl._getValueHelpIcon());
			oRm.write("
");
		}

	};

	/**
	 * Add inner styles to the placeholder
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addPlaceholderStyles = function(oRm, oControl) {

		if (oControl.getDescription()) {
			oRm.addStyle("width", oControl.getFieldWidth() || "50%");
		}

	};

	InputRenderer.getAriaLabelledBy = function(oControl) {
		var ariaLabels = InputBaseRenderer.getAriaLabelledBy.call(this, oControl) || "";
		if (oControl.getDescription()) {
			ariaLabels = ariaLabels + " " + oControl.getId() + "-Descr";
		}
		return ariaLabels;
	};

	InputRenderer.getAriaDescribedBy = function(oControl) {

		var sAriaDescribedBy = InputBaseRenderer.getAriaDescribedBy.apply(this, arguments);

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			if (sAriaDescribedBy) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl._sAriaValueHelpLabelId;
			} else {
				sAriaDescribedBy = oControl._sAriaValueHelpLabelId;
			}
			if (oControl.getValueHelpOnly()) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl._sAriaInputDisabledLabelId;
			}
		}

		if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
			if (sAriaDescribedBy) {
				sAriaDescribedBy = sAriaDescribedBy + " " + oControl.getId() + "-SuggDescr";
			} else {
				sAriaDescribedBy = oControl.getId() + "-SuggDescr";
			}
		}

		return sAriaDescribedBy;

	};

	InputRenderer.getAccessibilityState = function(oControl) {

		var mAccessibilityState = InputBaseRenderer.getAccessibilityState.apply(this, arguments);

		if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
			mAccessibilityState.autocomplete = "list";
		}

		return mAccessibilityState;

	};

	return InputRenderer;

}, /* bExport= */ true);
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define(['sap/ui/core/InvisibleText', 'sap/ui/core/Renderer', './InputBaseRenderer', 'sap/m/library'],
	function(InvisibleText, Renderer, InputBaseRenderer, library) {
	"use strict";

	// shortcut for sap.m.InputType
	var InputType = library.InputType;

	/**
	 * Input renderer.
	 *
	 * InputRenderer extends the InputBaseRenderer
	 *
	 * @namespace
	 */
	var InputRenderer = Renderer.extend(InputBaseRenderer);
	InputRenderer.apiVersion = 2;

	/**
	 * Adds control specific class
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterClasses = function (oRm, oControl) {
		oRm.class("sapMInput");

		if (oControl.getDescription()) {
			oRm.class("sapMInputWithDescription");
		}
	};

	/**
	 * add extra attributes to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerAttributes = function (oRm, oControl) {
		var bShowSuggestions = oControl.getShowSuggestion();

		oRm.attr("type", oControl.getType().toLowerCase());
		//if Input is of type "Number" step attribute should be "any" allowing input of floating point numbers
		if (oControl.getType() == InputType.Number) {
			oRm.attr("step", "any");
		}
		if (oControl.getType() == InputType.Number && sap.ui.getCore().getConfiguration().getRTL()) {
			oRm.attr("dir", "ltr").style("text-align", "right");
		}

		if (bShowSuggestions) {
			oRm.attr("aria-haspopup", "listbox");
		}

		if (bShowSuggestions || oControl.getShowValueStateMessage()) {
			oRm.attr("autocomplete", "off"); // autocomplete="off" needed so the native browser autocomplete is not shown?
		}

		if ((!oControl.getEnabled() && oControl.getType() == "Password")
			|| (oControl.getShowSuggestion() && oControl.isMobileDevice())
			|| (oControl.getValueHelpOnly() && oControl.getEnabled() && oControl.getEditable() && oControl.getShowValueHelp())) {
			// required for JAWS reader on password fields on desktop and in other cases:
			oRm.attr("readonly", "readonly");
		}
	};

	/**
	 * Adds inner css classes to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerClasses = function (oRm, oControl) {
	};

	InputRenderer.writeDescription = function (oRm, oControl) {
		oRm.openStart("div")
			.class("sapMInputDescriptionWrapper")
			.style("width", "calc(100% - " + oControl.getFieldWidth() + ")")
			.openEnd();

		oRm.openStart("span", oControl.getId() + "-descr")
			.class("sapMInputDescriptionText")
			.openEnd()
			.text(oControl.getDescription())
			.close("span");
		oRm.close("div");
	};

	InputRenderer.writeDecorations = function (oRm, oControl) {
		if (oControl.getDescription()) {
			this.writeDescription(oRm, oControl);
		}

		if (sap.ui.getCore().getConfiguration().getAccessibility()) {
			if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
				oRm.openStart("span", oControl.getId() + "-SuggDescr").class("sapUiPseudoInvisibleText")
					.attr("role", "status").attr("aria-live", "polite")
					.openEnd()
					.close("span");
			}
		}
	};

	InputRenderer.addWrapperStyles = function (oRm, oControl) {
		oRm.style("width", oControl.getDescription() ? oControl.getFieldWidth() : "100%");
	};

	InputRenderer.getAriaDescribedBy = function (oControl) {

		var sAriaDescribedBy = InputBaseRenderer.getAriaDescribedBy.apply(this, arguments);

		function append(s) {
			sAriaDescribedBy = sAriaDescribedBy ? sAriaDescribedBy + " " + s : s;
		}

		if (oControl.getDescription()) {
			append(oControl.getId() + "-descr");
		}

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			append(InvisibleText.getStaticId("sap.m", "INPUT_VALUEHELP"));
			if (oControl.getValueHelpOnly()) {
				append(InvisibleText.getStaticId("sap.m", "INPUT_DISABLED"));
			}
		}

		return sAriaDescribedBy;

	};

	/**
	 * Returns aria accessibility role for the control.
	 * Hook for the subclasses.
	 *
	 * @param {sap.ui.core.Control} oControl an object representation of the control
	 * @returns {String}
	 */
	InputRenderer.getAriaRole = function (oControl) {
		return "";
	};

	InputRenderer.getAccessibilityState = function (oControl) {

		var mAccessibilityState = InputBaseRenderer.getAccessibilityState.apply(this, arguments);

		return mAccessibilityState;

	};

	return InputRenderer;

}, /* bExport= */ true);
<commit_msg>[FIX] sap.m.Input: Accessibility enhancement<commit_after>/*!
 * ${copyright}
 */

sap.ui.define(['sap/ui/core/InvisibleText', 'sap/ui/core/Renderer', './InputBaseRenderer', 'sap/m/library'],
	function(InvisibleText, Renderer, InputBaseRenderer, library) {
	"use strict";

	// shortcut for sap.m.InputType
	var InputType = library.InputType;

	/**
	 * Input renderer.
	 *
	 * InputRenderer extends the InputBaseRenderer
	 *
	 * @namespace
	 */
	var InputRenderer = Renderer.extend(InputBaseRenderer);
	InputRenderer.apiVersion = 2;

	/**
	 * Adds control specific class
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addOuterClasses = function (oRm, oControl) {
		oRm.class("sapMInput");

		if (oControl.getDescription()) {
			oRm.class("sapMInputWithDescription");
		}
	};

	/**
	 * add extra attributes to Input
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.writeInnerAttributes = function (oRm, oControl) {
		var bShowSuggestions = oControl.getShowSuggestion();

		oRm.attr("type", oControl.getType().toLowerCase());
		//if Input is of type "Number" step attribute should be "any" allowing input of floating point numbers
		if (oControl.getType() == InputType.Number) {
			oRm.attr("step", "any");
		}
		if (oControl.getType() == InputType.Number && sap.ui.getCore().getConfiguration().getRTL()) {
			oRm.attr("dir", "ltr").style("text-align", "right");
		}

		if (bShowSuggestions || oControl.getShowValueStateMessage()) {
			oRm.attr("autocomplete", "off"); // autocomplete="off" needed so the native browser autocomplete is not shown?
		}

		if ((!oControl.getEnabled() && oControl.getType() == "Password")
			|| (oControl.getShowSuggestion() && oControl.isMobileDevice())
			|| (oControl.getValueHelpOnly() && oControl.getEnabled() && oControl.getEditable() && oControl.getShowValueHelp())) {
			// required for JAWS reader on password fields on desktop and in other cases:
			oRm.attr("readonly", "readonly");
		}
	};

	/**
	 * Adds inner css classes to the input field
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	InputRenderer.addInnerClasses = function (oRm, oControl) {
	};

	InputRenderer.writeDescription = function (oRm, oControl) {
		oRm.openStart("div")
			.class("sapMInputDescriptionWrapper")
			.style("width", "calc(100% - " + oControl.getFieldWidth() + ")")
			.openEnd();

		oRm.openStart("span", oControl.getId() + "-descr")
			.class("sapMInputDescriptionText")
			.openEnd()
			.text(oControl.getDescription())
			.close("span");
		oRm.close("div");
	};

	InputRenderer.writeDecorations = function (oRm, oControl) {
		if (oControl.getDescription()) {
			this.writeDescription(oRm, oControl);
		}

		if (sap.ui.getCore().getConfiguration().getAccessibility()) {
			if (oControl.getShowSuggestion() && oControl.getEnabled() && oControl.getEditable()) {
				oRm.openStart("span", oControl.getId() + "-SuggDescr").class("sapUiPseudoInvisibleText")
					.attr("role", "status").attr("aria-live", "polite")
					.openEnd()
					.close("span");
			}
		}
	};

	InputRenderer.addWrapperStyles = function (oRm, oControl) {
		oRm.style("width", oControl.getDescription() ? oControl.getFieldWidth() : "100%");
	};

	InputRenderer.getAriaDescribedBy = function (oControl) {

		var sAriaDescribedBy = InputBaseRenderer.getAriaDescribedBy.apply(this, arguments);

		function append(s) {
			sAriaDescribedBy = sAriaDescribedBy ? sAriaDescribedBy + " " + s : s;
		}

		if (oControl.getDescription()) {
			append(oControl.getId() + "-descr");
		}

		if (oControl.getShowValueHelp() && oControl.getEnabled() && oControl.getEditable()) {
			append(InvisibleText.getStaticId("sap.m", "INPUT_VALUEHELP"));
			if (oControl.getValueHelpOnly()) {
				append(InvisibleText.getStaticId("sap.m", "INPUT_DISABLED"));
			}
		}

		return sAriaDescribedBy;

	};

	/**
	 * Returns aria accessibility role for the control.
	 * Hook for the subclasses.
	 *
	 * @param {sap.ui.core.Control} oControl an object representation of the control
	 * @returns {String}
	 */
	InputRenderer.getAriaRole = function (oControl) {
		return "";
	};

	InputRenderer.getAccessibilityState = function (oControl) {
		var bShowSuggestions = oControl.getShowSuggestion();

		var mAccessibilityState = InputBaseRenderer.getAccessibilityState.apply(this, arguments);

		if (bShowSuggestions) {
			mAccessibilityState["haspopup"] = "listbox";
		}

		return mAccessibilityState;

	};

	return InputRenderer;

}, /* bExport= */ true);
<|endoftext|>


<commit_before>// dependencies ----------------------------------------------------------------------

import Reflux    from 'reflux';
import Actions   from './dataset.actions.js';
import scitran   from '../utils/scitran';
import crn       from '../utils/crn';
import bids      from '../utils/bids';
import router    from '../utils/router-container';
import userStore from '../user/user.store';
import upload    from '../utils/upload';
import config    from '../config';
import files     from '../utils/files';

let datasetStore = Reflux.createStore({

// store setup -----------------------------------------------------------------------

	listenables: Actions,

	init: function () {
		this.setInitialState();
		crn.getApps((err, res) => {
			this.update({apps: res.body});
		});
	},

	getInitialState: function () {
		return this.data;
	},

// data ------------------------------------------------------------------------------

	data: {},

	update: function (data) {
		for (let prop in data) {this.data[prop] = data[prop];}
		this.trigger(this.data);
	},

	/**
	 * Set Initial State
	 *
	 * Sets the state to the data object defined
	 * inside the function. Also takes a diffs object
	 * which will set the state to the initial state
	 * with any differences passed.
	 */
	setInitialState: function (diffs) {
		let data = {
			app: [],
			loading: false,
			dataset: null,
			status: null,
			showJobsModal: false,
			showShareModal: false,
			users: []
		};
		for (let prop in diffs) {data[prop] = diffs[prop];}
		this.update(data);
	},

// Actions ---------------------------------------------------------------------------

	// Dataset -----------------------------------------------------------------------

	/**
	 * Load Dataset
	 *
	 * Takes a datasetId and loads the dataset.
	 */
	loadDataset(datasetId) {
		this.update({loading: true, dataset: null});
		bids.getDataset(datasetId, (res) => {
			if (res.status === 404 || res.status === 403) {
				this.update({status: res.status, loading: false});
			} else {
				this.update({dataset: res, loading: false});
			}
		});
	},

	/**
	 * Reload Dataset
	 *
	 * Optionally takes a datasetId and only reloads
	 * the dataset if that ID matches the current ID.
	 * If no ID is passed it reloads the current ID.
	 */
	reloadDataset(datasetId) {
		if (this.data.dataset) {
			if (!datasetId) {
				this.loadDataset(this.data.dataset._id);
			}else if (this.data.dataset._id == datasetId) {
				this.loadDataset(datasetId);
			}
		}
	},

	/**
	 * Load Users
	 *
	 * Loads a list of all users.
	 */
	loadUsers() {
		scitran.getUsers((err, res) => {
			this.update({users: res.body});
		});
	},

	/**
	 * Publish
	 *
	 * Takes a datasetId and sets the datset to public.
	 */
	publish(datasetId) {
		let self = this;
		scitran.updateProject(datasetId, {public: true}, (err, res) => {
			if (!err) {
				let dataset = self.data.dataset;
				dataset.public = true;
				self.update({dataset});
			}
		});
	},

	/**
	 * Download Dataset
	 *
	 */
	downloadDataset() {
		scitran.getBIDSDownloadTicket(this.data.dataset._id, (err, res) => {
			let ticket = res.body.ticket;
			window.open(res.req.url.split('?')[0] + '?ticket=' + ticket);
		});
	},

	/**
	 * Delete Dataset
	 *
	 * Takes a datsetId, deletes the dataset, and returns the user
	 * to the my datasets page.
	 */
	deleteDataset(datasetId) {
		bids.deleteDataset(datasetId, () => {
            router.transitionTo('datasets');
		});
	},

	/**
	 * Toggle Modal
	 */
	toggleModal(name) {
		let updates = {};
		updates['show' + name + 'Modal'] = !this.data['show' + name + 'Modal'];
		this.update(updates);
	},

	// Metadata ----------------------------------------------------------------------

	/**
	 * Update Description
	 *
	 * Takes a key and a value and updates the dataset
	 * description JSON note accordingly.
	 */
	updateDescription(key, value, callback) {
		let dataset = this.data.dataset;
		let description = dataset.description;
		description[key] = value;
		if (key !== 'Authors'){description.Authors = dataset.authors;}
		this.saveDescription(description, callback);
		this.update({dataset: dataset});
	},

	/**
	 * Save Description
	 *
	 * Takes a description object and upserts
	 * the JSON description file.
	 */
	saveDescription(description, callback) {
		let datasetId = this.data.dataset._id;
		let authorsNote = {
			author: 'authors',
			text: JSON.stringify(description.Authors)
		}
		scitran.updateNote(datasetId, authorsNote, (err, res) => {
			let authors = [];
			for (let author of description.Authors) {
				authors.push(author.name);
			}
			description.Authors = authors;
			scitran.updateFileFromString('projects', datasetId, 'dataset_description.json', JSON.stringify(description), callback);
		});
	},

	/**
	 * Update Note
	 *
	 * Takes a name, value and callback and
	 * upserts a corresponding note for the
	 * current dataset.
	 */
	updateNote(name, value, callback) {
	 	let dataset = this.data.dataset;
	 	let note = {
	 		author: name,
	 		text: value
	 	};
	 	scitran.updateNote(dataset._id, note, callback);
	},

	 /**
	  * Update README
	  */
	updateREADME(value, callback) {
		scitran.updateFileFromString('projects', this.data.dataset._id, 'README', value, callback);
	},

	// Attachments -------------------------------------------------------------------

	/**
	 * Upload Attachment
	 *
	 * Takes a file and a callback and uploads
	 * the file to the current dataset.
	 */
	uploadAttachment(file, callback) {
		let attachmentExists, fileExists;
		for (let attachment of this.data.dataset.attachments) {
			if (attachment.name === file.name) {
				attachmentExists = true;
			}
		}

		for (let existingFile of this.data.dataset.children) {
			if (existingFile.name === file.name) {
				fileExists = true;
			}
		}

		if (attachmentExists) {
			callback({error: '"' + file.name + '" has already been uploaded. Multiple attachments with the same name are not allowed.'});
		} else if (fileExists) {
			callback({error: 'You cannot upload a file named "' + file.name + '" as an attachment because it already exists in the dataset.'});
		} else {
			let request = {
				url: config.scitran.url + 'projects/' + this.data.dataset._id + '/file/' + file.name,
				file: file,
				tag: 'attachment',
				progressStart: () => {},
				progressEnd: () => {
					bids.getDataset(this.data.dataset._id, (res) => {
						let dataset = this.data.dataset;
						dataset.attachments = res.attachments;
						this.update({dataset: dataset});
						callback();
					});
				},
				error: (err, req) => {
					callback({error: 'There was an error uploading your attachment. Please try again and contact the site administrator if the issue persists.'});
				}
			};
			upload.add(request);
		}
	},

	/**
	 * Delete Attachment
	 *
	 * Takes a filename and index and deletes
	 * the attachment from the current dataset.
	 */
	deleteAttachment(filename, index) {
		scitran.deleteFile('projects', this.data.dataset._id, filename, (err, res) => {
			let dataset = this.data.dataset;
			dataset.attachments.splice(index, 1);
			this.update({dataset});
		});
	},

	/**
	 * Download Attachment
	 *
	 * Takes a filename and starts a downloads
	 * for the file within the current dataset.
	 */
	downloadAttachment(filename) {
		scitran.getDownloadTicket('projects', this.data.dataset._id, filename, (err, res) => {
			let ticket = res.body.ticket;
			window.open(res.req.url + ticket);
		});
	},

	// File Structure ----------------------------------------------------------------

	/**
	 * Add File
	 */
	addFile(container, file) {
		let exists;
		for (let existingFile of container.children) {
			if (existingFile.name === file.name) {
				exists = true;
			}
		}

		if (exists) {
			this.updateDirectoryState(container._id, {error: '"' + file.name + '" already exists in this directory.'});
		} else {
			this.updateDirectoryState(container._id, {loading: true});
			scitran.updateFile(container.containerType, container._id, file, () => {
				let children = container.children
				children.unshift({
					filename: file.name,
					name: file.name,
					parentContainer: container.containerType,
					parentId: container._id
				});
				this.updateDirectoryState(container._id, {children: children, loading: false});
			});
		}
	},

	/**
	 * Delete File
	 */
	deleteFile(file) {
		let dataset = this.data.dataset;
		scitran.deleteFile(file.parentContainer, file.parentId, file.name, (err, res) => {
			let match = files.findInTree([dataset], file.parentId);
			let children = [];
			for (let existingFile of match.children) {
				if (file.filename !== existingFile.filename) {
					children.push(existingFile);
				}
			}
			match.children = children;
			this.update({dataset});
		});
	},

	/**
	 * Dismiss Error
	 */
	dismissError(item) {
		if (item.children) {
			this.updateDirectoryState(item._id, {error: ''});
		} else {
			this.updateFileState(item, {error: ''});
		}
	},

	/**
	 * Update File
	 */
	updateFile(item, file) {
		let id       = item.parentId,
			level    = item.parentContainer,
			filename = item.name;

		if (filename !== file.name) {
			this.updateFileState(item, {
				error: 'You must replace a file with a file of the same name.'
			});
		} else {
			this.updateFileState(item, {error: null, loading: true});
			scitran.updateFile(level, id, file, (err, res) => {
				this.updateFileState(item, {loading: false});
			});
		}
	},

	/**
	 * Update Directory State
	 *
	 */
	updateDirectoryState(directoryId, changes) {
		let dataset = this.data.dataset;
		let match = files.findInTree([dataset], directoryId);
		if (match) {
			for (let key in changes) {
				match[key] = changes[key];
			}
		}
		this.update({dataset});
	},

	/**
	 * Update File State
	 *
	 * Take a file object and changes to be
	 * made and applies those changes by
	 * updating the state of the file tree
	 */
	updateFileState(file, changes) {
		let dataset = this.data.dataset;
		let parent = files.findInTree([dataset], file.parentId);
		let children = [];
		for (let existingFile of parent.children) {
			if (file.filename == existingFile.filename) {
				for (let key in changes) {
					existingFile[key] = changes[key];
				}
			}
		}
		this.update({dataset});
	},

	/**
	 * Toggle Folder
	 *
	 * Takes the id of a container in the
	 * current dataset and toggles its showChildren
	 * boolean which determines whether container
	 * children are shown in the tree hierarchy UI.
	 */
	toggleFolder(directory) {
		this.updateDirectoryState(directory._id, {showChildren: !directory.showChildren});
	},

	// Jobs --------------------------------------------------------------------------

	/**
	 * Start Job
	 */
	startJob(appName, appId, parameters, callback) {
		crn.createJob({
			name: appName,
			appId: appId,
			datasetId: this.data.dataset._id,
			userId: userStore.data.scitran._id,
			parameters: parameters
		}, (err, res) => {
			callback(err, res);
			this.toggleModal('Jobs');
		});
	}

});

export default datasetStore;<commit_msg>updated download function to circumvent popup blockers<commit_after>// dependencies ----------------------------------------------------------------------

import Reflux    from 'reflux';
import Actions   from './dataset.actions.js';
import scitran   from '../utils/scitran';
import crn       from '../utils/crn';
import bids      from '../utils/bids';
import router    from '../utils/router-container';
import userStore from '../user/user.store';
import upload    from '../utils/upload';
import config    from '../config';
import files     from '../utils/files';

let datasetStore = Reflux.createStore({

// store setup -----------------------------------------------------------------------

	listenables: Actions,

	init: function () {
		this.setInitialState();
		crn.getApps((err, res) => {
			this.update({apps: res.body});
		});
	},

	getInitialState: function () {
		return this.data;
	},

// data ------------------------------------------------------------------------------

	data: {},

	update: function (data) {
		for (let prop in data) {this.data[prop] = data[prop];}
		this.trigger(this.data);
	},

	/**
	 * Set Initial State
	 *
	 * Sets the state to the data object defined
	 * inside the function. Also takes a diffs object
	 * which will set the state to the initial state
	 * with any differences passed.
	 */
	setInitialState: function (diffs) {
		let data = {
			app: [],
			loading: false,
			dataset: null,
			status: null,
			showJobsModal: false,
			showShareModal: false,
			users: []
		};
		for (let prop in diffs) {data[prop] = diffs[prop];}
		this.update(data);
	},

// Actions ---------------------------------------------------------------------------

	// Dataset -----------------------------------------------------------------------

	/**
	 * Load Dataset
	 *
	 * Takes a datasetId and loads the dataset.
	 */
	loadDataset(datasetId) {
		this.update({loading: true, dataset: null});
		bids.getDataset(datasetId, (res) => {
			if (res.status === 404 || res.status === 403) {
				this.update({status: res.status, loading: false});
			} else {
				this.update({dataset: res, loading: false});
			}
		});
	},

	/**
	 * Reload Dataset
	 *
	 * Optionally takes a datasetId and only reloads
	 * the dataset if that ID matches the current ID.
	 * If no ID is passed it reloads the current ID.
	 */
	reloadDataset(datasetId) {
		if (this.data.dataset) {
			if (!datasetId) {
				this.loadDataset(this.data.dataset._id);
			}else if (this.data.dataset._id == datasetId) {
				this.loadDataset(datasetId);
			}
		}
	},

	/**
	 * Load Users
	 *
	 * Loads a list of all users.
	 */
	loadUsers() {
		scitran.getUsers((err, res) => {
			this.update({users: res.body});
		});
	},

	/**
	 * Publish
	 *
	 * Takes a datasetId and sets the datset to public.
	 */
	publish(datasetId) {
		let self = this;
		scitran.updateProject(datasetId, {public: true}, (err, res) => {
			if (!err) {
				let dataset = self.data.dataset;
				dataset.public = true;
				self.update({dataset});
			}
		});
	},

	/**
	 * Download Dataset
	 *
	 */
	downloadDataset() {
		// open download window as synchronous action from click to avoid throwing popup blockers
		window.open('', 'bids-download');
		scitran.getBIDSDownloadTicket(this.data.dataset._id, (err, res) => {
			let ticket = res.body.ticket;
			let downloadWindow = window.open(res.req.url.split('?')[0] + '?ticket=' + ticket, 'bids-download');
			// close download window on next cycle
			setTimeout(() => {downloadWindow.close();});
		});
	},

	/**
	 * Delete Dataset
	 *
	 * Takes a datsetId, deletes the dataset, and returns the user
	 * to the my datasets page.
	 */
	deleteDataset(datasetId) {
		bids.deleteDataset(datasetId, () => {
            router.transitionTo('datasets');
		});
	},

	/**
	 * Toggle Modal
	 */
	toggleModal(name) {
		let updates = {};
		updates['show' + name + 'Modal'] = !this.data['show' + name + 'Modal'];
		this.update(updates);
	},

	// Metadata ----------------------------------------------------------------------

	/**
	 * Update Description
	 *
	 * Takes a key and a value and updates the dataset
	 * description JSON note accordingly.
	 */
	updateDescription(key, value, callback) {
		let dataset = this.data.dataset;
		let description = dataset.description;
		description[key] = value;
		if (key !== 'Authors'){description.Authors = dataset.authors;}
		this.saveDescription(description, callback);
		this.update({dataset: dataset});
	},

	/**
	 * Save Description
	 *
	 * Takes a description object and upserts
	 * the JSON description file.
	 */
	saveDescription(description, callback) {
		let datasetId = this.data.dataset._id;
		let authorsNote = {
			author: 'authors',
			text: JSON.stringify(description.Authors)
		}
		scitran.updateNote(datasetId, authorsNote, (err, res) => {
			let authors = [];
			for (let author of description.Authors) {
				authors.push(author.name);
			}
			description.Authors = authors;
			scitran.updateFileFromString('projects', datasetId, 'dataset_description.json', JSON.stringify(description), callback);
		});
	},

	/**
	 * Update Note
	 *
	 * Takes a name, value and callback and
	 * upserts a corresponding note for the
	 * current dataset.
	 */
	updateNote(name, value, callback) {
	 	let dataset = this.data.dataset;
	 	let note = {
	 		author: name,
	 		text: value
	 	};
	 	scitran.updateNote(dataset._id, note, callback);
	},

	 /**
	  * Update README
	  */
	updateREADME(value, callback) {
		scitran.updateFileFromString('projects', this.data.dataset._id, 'README', value, callback);
	},

	// Attachments -------------------------------------------------------------------

	/**
	 * Upload Attachment
	 *
	 * Takes a file and a callback and uploads
	 * the file to the current dataset.
	 */
	uploadAttachment(file, callback) {
		let attachmentExists, fileExists;
		for (let attachment of this.data.dataset.attachments) {
			if (attachment.name === file.name) {
				attachmentExists = true;
			}
		}

		for (let existingFile of this.data.dataset.children) {
			if (existingFile.name === file.name) {
				fileExists = true;
			}
		}

		if (attachmentExists) {
			callback({error: '"' + file.name + '" has already been uploaded. Multiple attachments with the same name are not allowed.'});
		} else if (fileExists) {
			callback({error: 'You cannot upload a file named "' + file.name + '" as an attachment because it already exists in the dataset.'});
		} else {
			let request = {
				url: config.scitran.url + 'projects/' + this.data.dataset._id + '/file/' + file.name,
				file: file,
				tag: 'attachment',
				progressStart: () => {},
				progressEnd: () => {
					bids.getDataset(this.data.dataset._id, (res) => {
						let dataset = this.data.dataset;
						dataset.attachments = res.attachments;
						this.update({dataset: dataset});
						callback();
					});
				},
				error: (err, req) => {
					callback({error: 'There was an error uploading your attachment. Please try again and contact the site administrator if the issue persists.'});
				}
			};
			upload.add(request);
		}
	},

	/**
	 * Delete Attachment
	 *
	 * Takes a filename and index and deletes
	 * the attachment from the current dataset.
	 */
	deleteAttachment(filename, index) {
		scitran.deleteFile('projects', this.data.dataset._id, filename, (err, res) => {
			let dataset = this.data.dataset;
			dataset.attachments.splice(index, 1);
			this.update({dataset});
		});
	},

	/**
	 * Download Attachment
	 *
	 * Takes a filename and starts a downloads
	 * for the file within the current dataset.
	 */
	downloadAttachment(filename) {
		scitran.getDownloadTicket('projects', this.data.dataset._id, filename, (err, res) => {
			let ticket = res.body.ticket;
			window.open(res.req.url + ticket);
		});
	},

	// File Structure ----------------------------------------------------------------

	/**
	 * Add File
	 */
	addFile(container, file) {
		let exists;
		for (let existingFile of container.children) {
			if (existingFile.name === file.name) {
				exists = true;
			}
		}

		if (exists) {
			this.updateDirectoryState(container._id, {error: '"' + file.name + '" already exists in this directory.'});
		} else {
			this.updateDirectoryState(container._id, {loading: true});
			scitran.updateFile(container.containerType, container._id, file, () => {
				let children = container.children
				children.unshift({
					filename: file.name,
					name: file.name,
					parentContainer: container.containerType,
					parentId: container._id
				});
				this.updateDirectoryState(container._id, {children: children, loading: false});
			});
		}
	},

	/**
	 * Delete File
	 */
	deleteFile(file) {
		let dataset = this.data.dataset;
		scitran.deleteFile(file.parentContainer, file.parentId, file.name, (err, res) => {
			let match = files.findInTree([dataset], file.parentId);
			let children = [];
			for (let existingFile of match.children) {
				if (file.filename !== existingFile.filename) {
					children.push(existingFile);
				}
			}
			match.children = children;
			this.update({dataset});
		});
	},

	/**
	 * Dismiss Error
	 */
	dismissError(item) {
		if (item.children) {
			this.updateDirectoryState(item._id, {error: ''});
		} else {
			this.updateFileState(item, {error: ''});
		}
	},

	/**
	 * Update File
	 */
	updateFile(item, file) {
		let id       = item.parentId,
			level    = item.parentContainer,
			filename = item.name;

		if (filename !== file.name) {
			this.updateFileState(item, {
				error: 'You must replace a file with a file of the same name.'
			});
		} else {
			this.updateFileState(item, {error: null, loading: true});
			scitran.updateFile(level, id, file, (err, res) => {
				this.updateFileState(item, {loading: false});
			});
		}
	},

	/**
	 * Update Directory State
	 *
	 */
	updateDirectoryState(directoryId, changes) {
		let dataset = this.data.dataset;
		let match = files.findInTree([dataset], directoryId);
		if (match) {
			for (let key in changes) {
				match[key] = changes[key];
			}
		}
		this.update({dataset});
	},

	/**
	 * Update File State
	 *
	 * Take a file object and changes to be
	 * made and applies those changes by
	 * updating the state of the file tree
	 */
	updateFileState(file, changes) {
		let dataset = this.data.dataset;
		let parent = files.findInTree([dataset], file.parentId);
		let children = [];
		for (let existingFile of parent.children) {
			if (file.filename == existingFile.filename) {
				for (let key in changes) {
					existingFile[key] = changes[key];
				}
			}
		}
		this.update({dataset});
	},

	/**
	 * Toggle Folder
	 *
	 * Takes the id of a container in the
	 * current dataset and toggles its showChildren
	 * boolean which determines whether container
	 * children are shown in the tree hierarchy UI.
	 */
	toggleFolder(directory) {
		this.updateDirectoryState(directory._id, {showChildren: !directory.showChildren});
	},

	// Jobs --------------------------------------------------------------------------

	/**
	 * Start Job
	 */
	startJob(appName, appId, parameters, callback) {
		crn.createJob({
			name: appName,
			appId: appId,
			datasetId: this.data.dataset._id,
			userId: userStore.data.scitran._id,
			parameters: parameters
		}, (err, res) => {
			callback(err, res);
			this.toggleModal('Jobs');
		});
	}

});

export default datasetStore;<|endoftext|>