<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
  DeviceEventEmitter, // android
  NativeAppEventEmitter, // ios
  NativeModules,
  Platform,
  StyleSheet,
  findNodeHandle,
  requireNativeComponent,
  ViewPropTypes,
  PermissionsAndroid,
  ActivityIndicator,
  View,
  Text,
  UIManager,
} from 'react-native';

const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;
const CAMERA_REF = 'camera';

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.flashMode === 'string') {
    newProps.flashMode = Camera.constants.FlashMode[props.flashMode];
  }

  if (typeof props.zoom === 'string' || typeof props.zoom === 'number') {
    if (props.zoom >= 0 && props.zoom <= 100) {
      newProps.zoom = parseInt(props.zoom);
    }
  }

  if (typeof props.orientation === 'string') {
    newProps.orientation = Camera.constants.Orientation[props.orientation];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.type === 'string') {
    newProps.type = Camera.constants.Type[props.type];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  if (typeof props.captureMode === 'string') {
    newProps.captureMode = Camera.constants.CaptureMode[props.captureMode];
  }

  if (typeof props.captureTarget === 'string') {
    newProps.captureTarget = Camera.constants.CaptureTarget[props.captureTarget];
  }

  // do not register barCodeTypes if no barcode listener
  if (typeof props.onBarCodeRead !== 'function') {
    newProps.barCodeTypes = [];
  }

  newProps.barcodeScannerEnabled = typeof props.onBarCodeRead === 'function';

  return newProps;
}

export default class Camera extends Component {
  static constants = {
    Aspect: CameraManager.Aspect,
    BarCodeType: CameraManager.BarCodeType,
    Type: CameraManager.Type,
    CaptureMode: CameraManager.CaptureMode,
    CaptureTarget: CameraManager.CaptureTarget,
    CaptureQuality: CameraManager.CaptureQuality,
    Orientation: CameraManager.Orientation,
    FlashMode: CameraManager.FlashMode,
    Zoom: CameraManager.Zoom,
    TorchMode: CameraManager.TorchMode,
  };

  static propTypes = {
    ...ViewPropTypes,
    aspect: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureAudio: PropTypes.bool,
    captureMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureQuality: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureTarget: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    defaultOnFocusComponent: PropTypes.bool,
    flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    zoom: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    keepAwake: PropTypes.bool,
    onBarCodeRead: PropTypes.func,
    barcodeScannerEnabled: PropTypes.bool,
    cropToPreview: PropTypes.bool,
    clearWindowBackground: PropTypes.bool,
    onFocusChanged: PropTypes.func,
    onZoomChanged: PropTypes.func,
    mirrorImage: PropTypes.bool,
    fixOrientation: PropTypes.bool,
    barCodeTypes: PropTypes.array,
    orientation: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    playSoundOnCapture: PropTypes.bool,
    torchMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    permissionDialogTitle: PropTypes.string,
    permissionDialogMessage: PropTypes.string,
    notAuthorizedView: PropTypes.element,
    pendingAuthorizationView: PropTypes.element,
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    type: CameraManager.Type.back,
    orientation: CameraManager.Orientation.auto,
    fixOrientation: false,
    captureAudio: false,
    captureMode: CameraManager.CaptureMode.still,
    captureTarget: CameraManager.CaptureTarget.cameraRoll,
    captureQuality: CameraManager.CaptureQuality.high,
    defaultOnFocusComponent: true,
    flashMode: CameraManager.FlashMode.off,
    zoom: 0,
    playSoundOnCapture: true,
    torchMode: CameraManager.TorchMode.off,
    mirrorImage: false,
    cropToPreview: false,
    clearWindowBackground: false,
    barCodeTypes: Object.values(CameraManager.BarCodeType),
    permissionDialogTitle: '',
    permissionDialogMessage: '',
    notAuthorizedView: (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <Text
          style={{
            textAlign: 'center',
            fontSize: 16,
          }}
        >
          Camera not authorized
        </Text>
      </View>
    ),
    pendingAuthorizationView: (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <ActivityIndicator size="small" />
      </View>
    ),
  };

  static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus;
  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;
  static checkAudioAuthorizationStatus = CameraManager.checkAudioAuthorizationStatus;

  setNativeProps(props) {
    // eslint-disable-next-line
    this.refs[CAMERA_REF].setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false,
      isAuthorizationChecked: false,
      isRecording: false,
    };
  }

  async componentWillMount() {
    this._addOnBarCodeReadListener();

    let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode });
    let hasVideoAndAudio =
      this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video;

    if (Platform.OS === 'ios') {
      let check = hasVideoAndAudio
        ? Camera.checkDeviceAuthorizationStatus
        : Camera.checkVideoAuthorizationStatus;

      if (check) {
        const isAuthorized = await check();
        this.setState({ isAuthorized, isAuthorizationChecked: true });
      }
    } else if (Platform.OS === 'android') {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
        title: this.props.permissionDialogTitle,
        message: this.props.permissionDialogMessage,
      });

      // On devices before SDK version 23, the permissions are automatically granted if they appear in the manifest,
      // so check and request should always be true.
      // https://github.com/facebook/react-native-website/blob/master/docs/permissionsandroid.md
      const isAuthorized =
        Platform.Version >= 23 ? granted === PermissionsAndroid.RESULTS.GRANTED : granted === true;

      this.setState({
        isAuthorized,
        isAuthorizationChecked: true,
      });
    } else {
      this.setState({ isAuthorized: true, isAuthorizationChecked: true });
    }
  }

  componentWillUnmount() {
    this._removeOnBarCodeReadListener();

    if (this.state.isRecording) {
      this.stopCapture();
    }
  }

  componentWillReceiveProps(newProps) {
    const { onBarCodeRead } = this.props;
    if (onBarCodeRead !== newProps.onBarCodeRead) {
      this._addOnBarCodeReadListener(newProps);
    }
  }

  _addOnBarCodeReadListener(props) {
    const { onBarCodeRead } = props || this.props;
    this._removeOnBarCodeReadListener();
    if (onBarCodeRead) {
      this.cameraBarCodeReadListener = Platform.select({
        ios: NativeAppEventEmitter.addListener('CameraBarCodeRead', this._onBarCodeRead),
        android: DeviceEventEmitter.addListener('CameraBarCodeReadAndroid', this._onBarCodeRead),
      });
    }
  }
  _removeOnBarCodeReadListener() {
    const listener = this.cameraBarCodeReadListener;
    if (listener) {
      listener.remove();
    }
  }

  render() {
    // TODO - style is not used, figure it out why
    // eslint-disable-next-line
    const style = [styles.base, this.props.style];
    const nativeProps = convertNativeProps(this.props);

    if (this.state.isAuthorized) {
      return <RCTCamera ref={CAMERA_REF} {...nativeProps} />;
    } else if (!this.state.isAuthorizationChecked) {
      return this.props.pendingAuthorizationView;
    } else {
      return this.props.notAuthorizedView;
    }
  }

  _onBarCodeRead = data => {
    if (this.props.onBarCodeRead) {
      this.props.onBarCodeRead(data);
    }
  };

  capture(options) {
    const props = convertNativeProps(this.props);
    options = {
      audio: props.captureAudio,
      barCodeTypes: props.barCodeTypes,
      mode: props.captureMode,
      playSoundOnCapture: props.playSoundOnCapture,
      target: props.captureTarget,
      quality: props.captureQuality,
      type: props.type,
      title: '',
      description: '',
      mirrorImage: props.mirrorImage,
      fixOrientation: props.fixOrientation,
      cropToPreview: props.cropToPreview,
      ...options,
    };

    if (options.mode === Camera.constants.CaptureMode.video) {
      options.totalSeconds = options.totalSeconds > -1 ? options.totalSeconds : -1;
      options.preferredTimeScale = options.preferredTimeScale || 30;
      options.cropToPreview = false;
      this.setState({ isRecording: true });
    }

    return CameraManager.capture(options);
  }

  startPreview() {
    if (Platform.OS === 'android') {
      UIManager.dispatchViewManagerCommand(
        findNodeHandle(this),
        UIManager.RCTCamera.Commands.startPreview,
      );
    } else {
      CameraManager.startPreview();
    }
  }

  stopPreview() {
    if (Platform.OS === 'android') {
      UIManager.dispatchViewManagerCommand(
        findNodeHandle(this),
        UIManager.RCTCamera.Commands.stopPreview,
      );
    } else {
      CameraManager.stopPreview();
    }
  }

  stopCapture() {
    if (this.state.isRecording) {
      this.setState({ isRecording: false });
      return CameraManager.stopCapture();
    }
    return Promise.resolve('Not Recording.');
  }

  getFOV() {
    return CameraManager.getFOV();
  }

  hasFlash() {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.hasFlash({
        type: props.type,
      });
    }
    return CameraManager.hasFlash();
  }

  setZoom(zoom) {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.setZoom(
        {
          type: props.type,
        },
        zoom,
      );
    }

    return CameraManager.setZoom(zoom);
  }
}

export const constants = Camera.constants;

const RCTCamera = requireNativeComponent('RCTCamera', Camera, {
  nativeOnly: {
    testID: true,
    renderToHardwareTextureAndroid: true,
    accessibilityLabel: true,
    importantForAccessibility: true,
    accessibilityLiveRegion: true,
    accessibilityComponentType: true,
    onLayout: true,
  },
});

const styles = StyleSheet.create({
  base: {},
});
<commit_msg>Save Camera ref and handle<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
  DeviceEventEmitter, // android
  NativeAppEventEmitter, // ios
  NativeModules,
  Platform,
  StyleSheet,
  findNodeHandle,
  requireNativeComponent,
  ViewPropTypes,
  PermissionsAndroid,
  ActivityIndicator,
  View,
  Text,
  UIManager,
} from 'react-native';

const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;

function convertNativeProps(props) {
  const newProps = { ...props };
  if (typeof props.aspect === 'string') {
    newProps.aspect = Camera.constants.Aspect[props.aspect];
  }

  if (typeof props.flashMode === 'string') {
    newProps.flashMode = Camera.constants.FlashMode[props.flashMode];
  }

  if (typeof props.zoom === 'string' || typeof props.zoom === 'number') {
    if (props.zoom >= 0 && props.zoom <= 100) {
      newProps.zoom = parseInt(props.zoom);
    }
  }

  if (typeof props.orientation === 'string') {
    newProps.orientation = Camera.constants.Orientation[props.orientation];
  }

  if (typeof props.torchMode === 'string') {
    newProps.torchMode = Camera.constants.TorchMode[props.torchMode];
  }

  if (typeof props.type === 'string') {
    newProps.type = Camera.constants.Type[props.type];
  }

  if (typeof props.captureQuality === 'string') {
    newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality];
  }

  if (typeof props.captureMode === 'string') {
    newProps.captureMode = Camera.constants.CaptureMode[props.captureMode];
  }

  if (typeof props.captureTarget === 'string') {
    newProps.captureTarget = Camera.constants.CaptureTarget[props.captureTarget];
  }

  // do not register barCodeTypes if no barcode listener
  if (typeof props.onBarCodeRead !== 'function') {
    newProps.barCodeTypes = [];
  }

  newProps.barcodeScannerEnabled = typeof props.onBarCodeRead === 'function';

  return newProps;
}

export default class Camera extends Component {
  static constants = {
    Aspect: CameraManager.Aspect,
    BarCodeType: CameraManager.BarCodeType,
    Type: CameraManager.Type,
    CaptureMode: CameraManager.CaptureMode,
    CaptureTarget: CameraManager.CaptureTarget,
    CaptureQuality: CameraManager.CaptureQuality,
    Orientation: CameraManager.Orientation,
    FlashMode: CameraManager.FlashMode,
    Zoom: CameraManager.Zoom,
    TorchMode: CameraManager.TorchMode,
  };

  static propTypes = {
    ...ViewPropTypes,
    aspect: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureAudio: PropTypes.bool,
    captureMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureQuality: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    captureTarget: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    defaultOnFocusComponent: PropTypes.bool,
    flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    zoom: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    keepAwake: PropTypes.bool,
    onBarCodeRead: PropTypes.func,
    barcodeScannerEnabled: PropTypes.bool,
    cropToPreview: PropTypes.bool,
    clearWindowBackground: PropTypes.bool,
    onFocusChanged: PropTypes.func,
    onZoomChanged: PropTypes.func,
    mirrorImage: PropTypes.bool,
    fixOrientation: PropTypes.bool,
    barCodeTypes: PropTypes.array,
    orientation: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    playSoundOnCapture: PropTypes.bool,
    torchMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    permissionDialogTitle: PropTypes.string,
    permissionDialogMessage: PropTypes.string,
    notAuthorizedView: PropTypes.element,
    pendingAuthorizationView: PropTypes.element,
  };

  static defaultProps = {
    aspect: CameraManager.Aspect.fill,
    type: CameraManager.Type.back,
    orientation: CameraManager.Orientation.auto,
    fixOrientation: false,
    captureAudio: false,
    captureMode: CameraManager.CaptureMode.still,
    captureTarget: CameraManager.CaptureTarget.cameraRoll,
    captureQuality: CameraManager.CaptureQuality.high,
    defaultOnFocusComponent: true,
    flashMode: CameraManager.FlashMode.off,
    zoom: 0,
    playSoundOnCapture: true,
    torchMode: CameraManager.TorchMode.off,
    mirrorImage: false,
    cropToPreview: false,
    clearWindowBackground: false,
    barCodeTypes: Object.values(CameraManager.BarCodeType),
    permissionDialogTitle: '',
    permissionDialogMessage: '',
    notAuthorizedView: (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <Text
          style={{
            textAlign: 'center',
            fontSize: 16,
          }}
        >
          Camera not authorized
        </Text>
      </View>
    ),
    pendingAuthorizationView: (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <ActivityIndicator size="small" />
      </View>
    ),
  };

  static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus;
  static checkVideoAuthorizationStatus = CameraManager.checkVideoAuthorizationStatus;
  static checkAudioAuthorizationStatus = CameraManager.checkAudioAuthorizationStatus;

  setNativeProps(props) {
    // eslint-disable-next-line
    this._cameraRef.setNativeProps(props);
  }

  constructor() {
    super();
    this.state = {
      isAuthorized: false,
      isAuthorizationChecked: false,
      isRecording: false,
    };
    this._cameraRef = null;
    this._cameraHandle = null;
  }

  async componentWillMount() {
    this._addOnBarCodeReadListener();

    let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode });
    let hasVideoAndAudio =
      this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video;

    if (Platform.OS === 'ios') {
      let check = hasVideoAndAudio
        ? Camera.checkDeviceAuthorizationStatus
        : Camera.checkVideoAuthorizationStatus;

      if (check) {
        const isAuthorized = await check();
        this.setState({ isAuthorized, isAuthorizationChecked: true });
      }
    } else if (Platform.OS === 'android') {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
        title: this.props.permissionDialogTitle,
        message: this.props.permissionDialogMessage,
      });

      // On devices before SDK version 23, the permissions are automatically granted if they appear in the manifest,
      // so check and request should always be true.
      // https://github.com/facebook/react-native-website/blob/master/docs/permissionsandroid.md
      const isAuthorized =
        Platform.Version >= 23 ? granted === PermissionsAndroid.RESULTS.GRANTED : granted === true;

      this.setState({
        isAuthorized,
        isAuthorizationChecked: true,
      });
    } else {
      this.setState({ isAuthorized: true, isAuthorizationChecked: true });
    }
  }

  componentWillUnmount() {
    this._removeOnBarCodeReadListener();

    if (this.state.isRecording) {
      this.stopCapture();
    }
  }

  componentWillReceiveProps(newProps) {
    const { onBarCodeRead } = this.props;
    if (onBarCodeRead !== newProps.onBarCodeRead) {
      this._addOnBarCodeReadListener(newProps);
    }
  }

  _addOnBarCodeReadListener(props) {
    const { onBarCodeRead } = props || this.props;
    this._removeOnBarCodeReadListener();
    if (onBarCodeRead) {
      this.cameraBarCodeReadListener = Platform.select({
        ios: NativeAppEventEmitter.addListener('CameraBarCodeRead', this._onBarCodeRead),
        android: DeviceEventEmitter.addListener('CameraBarCodeReadAndroid', this._onBarCodeRead),
      });
    }
  }
  _removeOnBarCodeReadListener() {
    const listener = this.cameraBarCodeReadListener;
    if (listener) {
      listener.remove();
    }
  }

  _setReference = ref => {
    if (ref) {
      this._cameraRef = ref;
      this._cameraHandle = findNodeHandle(ref);
    } else {
      this._cameraRef = null;
      this._cameraHandle = null;
    }
  };

  render() {
    // TODO - style is not used, figure it out why
    // eslint-disable-next-line
    const style = [styles.base, this.props.style];
    const nativeProps = convertNativeProps(this.props);

    if (this.state.isAuthorized) {
      return <RCTCamera ref={this._setReference} {...nativeProps} />;
    } else if (!this.state.isAuthorizationChecked) {
      return this.props.pendingAuthorizationView;
    } else {
      return this.props.notAuthorizedView;
    }
  }

  _onBarCodeRead = data => {
    if (this.props.onBarCodeRead) {
      this.props.onBarCodeRead(data);
    }
  };

  capture(options) {
    const props = convertNativeProps(this.props);
    options = {
      audio: props.captureAudio,
      barCodeTypes: props.barCodeTypes,
      mode: props.captureMode,
      playSoundOnCapture: props.playSoundOnCapture,
      target: props.captureTarget,
      quality: props.captureQuality,
      type: props.type,
      title: '',
      description: '',
      mirrorImage: props.mirrorImage,
      fixOrientation: props.fixOrientation,
      cropToPreview: props.cropToPreview,
      ...options,
    };

    if (options.mode === Camera.constants.CaptureMode.video) {
      options.totalSeconds = options.totalSeconds > -1 ? options.totalSeconds : -1;
      options.preferredTimeScale = options.preferredTimeScale || 30;
      options.cropToPreview = false;
      this.setState({ isRecording: true });
    }

    return CameraManager.capture(options);
  }

  startPreview() {
    if (Platform.OS === 'android') {
      UIManager.dispatchViewManagerCommand(
        this._cameraHandle,
        UIManager.RCTCamera.Commands.startPreview,
      );
    } else {
      CameraManager.startPreview();
    }
  }

  stopPreview() {
    if (Platform.OS === 'android') {
      UIManager.dispatchViewManagerCommand(
        this._cameraHandle,
        UIManager.RCTCamera.Commands.stopPreview,
      );
    } else {
      CameraManager.stopPreview();
    }
  }

  stopCapture() {
    if (this.state.isRecording) {
      this.setState({ isRecording: false });
      return CameraManager.stopCapture();
    }
    return Promise.resolve('Not Recording.');
  }

  getFOV() {
    return CameraManager.getFOV();
  }

  hasFlash() {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.hasFlash({
        type: props.type,
      });
    }
    return CameraManager.hasFlash();
  }

  setZoom(zoom) {
    if (Platform.OS === 'android') {
      const props = convertNativeProps(this.props);
      return CameraManager.setZoom(
        {
          type: props.type,
        },
        zoom,
      );
    }

    return CameraManager.setZoom(zoom);
  }
}

export const constants = Camera.constants;

const RCTCamera = requireNativeComponent('RCTCamera', Camera, {
  nativeOnly: {
    testID: true,
    renderToHardwareTextureAndroid: true,
    accessibilityLabel: true,
    importantForAccessibility: true,
    accessibilityLiveRegion: true,
    accessibilityComponentType: true,
    onLayout: true,
  },
});

const styles = StyleSheet.create({
  base: {},
});
<|endoftext|>


<commit_before>/**
 * Handles Project Organizer on dashboard page of OSF.
 * For Treebeard and _item API's check: https://github.com/caneruguz/treebeard/wiki
 */
'use strict';

var Treebeard = require('treebeard');

// CSS
require('css/typeahead.css');
require('css/fangorn.css');

var $ = require('jquery');
var m = require('mithril');
var moment = require('moment');
var Raven = require('raven-js');
var $osf = require('js/osfHelpers');
var iconmap = require('js/iconmap');

var LinkObject;
var allProjectsCache;
/**
 * Edits the template for the column titles.
 * Used here to make smart folder italicized
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @this Treebeard.controller Check Treebeard API for methods available
 * @private
 */
function _poTitleColumn(item) {
    var tb = this;
    var preventSelect = function(e){
        e.stopImmediatePropagation();
    };
    var node = item.data; // Where actual data of the node is
    var css = ''; // Keep for future expandability -- Remove: item.data.isSmartFolder ? 'project-smart-folder smart-folder' : '';
    if (item.data.archiving) { // TODO check if this variable will be available
        return  m('span', {'class': 'registration-archiving'}, node.attributes.title + ' [Archiving]');
    } else if(node.links.html){
        return [ m('a.fg-file-links', { 'class' : css, href : node.links.html, 'data-nodeID' : node.id, onclick : preventSelect}, node.attributes.title) ];
    } else {
        return  m('span', { 'class' : css, 'data-nodeID' : node.id }, node.attributes.title);
    }
}

/**
 * Contributors have first person's name and then number of contributors. This function returns the proper html
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @returns {Object} A Mithril virtual DOM template object
 * @private
 */
function _poContributors(item) {
    var contributorList = item.data.embeds.contributors.data;
    if (contributorList.length === 0) {
        return '';
    }

    return contributorList.map(function (person, index, arr) {
        var name;
        var familyName = person.embeds.users.data.attributes.family_name;
        var givenName = person.embeds.users.data.attributes.given_name;
        if (familyName) {
            name = familyName;
        } else if(givenName){
            name = givenName;
        } else {
            name = 'A Contributor';
        }
        var comma;
        if (index === 0) {
            comma = '';
        } else {
            comma = ', ';
        }
        if (index > 2) {
            return m('span');
        }
        if (index === 2) {
            return m('span', ' + ' + (arr.length - 2));
        }
        return m('span', comma + name);
    });
}

/**
 * Displays who modified the data and when. i.e. "6 days ago, by Uguz"
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @private
 */
function _poModified(item) {
    var dateString = '';
    var node = item.data;
    dateString = moment.utc(node.attributes.date_modified).fromNow();
    return m('span', dateString);
}

/**
 * Organizes all the row displays based on what that item requires.
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @returns {Array} An array of columns as col objects
 * @this Treebeard.controller Check Treebeard API For available methods
 * @private
 */
function _poResolveRows(item) {
    var mobile = window.innerWidth < 767; // true if mobile view

    var css = '',
        default_columns = [];
    if(this.isMultiselected(item.id)){
        item.css = 'fangorn-selected';
    } else {
        item.css = '';
    }

    default_columns.push({
        data : 'name',  // Data field name
        folderIcons : true,
        filter : true,
        css : 'po-draggable', // All projects are draggable since we separated collections from the grid
        custom : _poTitleColumn
    });

    if (!mobile) {
        default_columns.push({
            data : 'contributors',
            filter : true,
            custom : _poContributors
        }, {
            data : 'dateModified',
            filter : false,
            custom : _poModified
        });
    } else {
        default_columns.push({
            data : 'name',
            filter : false,
            custom : function (row){
                return m('.btn.btn-default.btn-sm[data-toggle="modal"][data-target="#infoModal"]', {
                }, m('i.fa.fa-ellipsis-h'));
            }
        });
    }

    return default_columns;
}

/**
 * Organizes the information for Column title row.
 * @returns {Array} An array of columns with pertinent column information
 * @private
 */
function _poColumnTitles() {
    var columns = [];
    var mobile = window.innerWidth < 767; // true if mobile view
    if(!mobile){
        columns.push({
            title: 'Name',
            width : '50%',
            sort : true,
            sortType : 'text'
        },{
            title : 'Contributors',
            width : '25%',
            sort : false
        }, {
            title : 'Modified',
            width : '25%',
            sort : false
        });
    } else {
        columns.push({
            title: 'Name',
            width : '90%',
            sort : true,
            sortType : 'text'
        },{
            title : '',
            width : '10%',
            sort : false
        });
    }

    return columns;
}

/**
 * Returns custom folder toggle icons for OSF
 * @param {Object} item A Treebeard _item object. Node information is inside item.data
 * @this Treebeard.controller
 * @returns {string} Returns a mithril template with m() function, or empty string.
 * @private
 */
function _poResolveToggle(item) {
    var toggleMinus = m('i.fa.fa-minus'),
        togglePlus = m('i.fa.fa-plus'),
        childrenCount = item.data.relationships.children.links.related.meta.count;
    if (childrenCount > 0) {
        if (item.open) {
            return toggleMinus;
        }
        return togglePlus;
    }
    return '';
}

/**
 * Resolves lazy load url for fetching children
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @this Treebeard.controller
 * @returns {String|Boolean} Returns the fetch URL in string or false if there is no url.
 * @private
 */
function _poResolveLazyLoad(item) {
    var node = item.data;
    if(item.children.length > 0) {
        return false;
    }
    if(node.relationships.children){
        //return node.relationships.children.links.related.href;
        return $osf.apiV2Url('nodes/' + node.id + '/children/', {
            query : {
                'related_counts' : true,
                'embed' : 'contributors'
            }
        });
    }
    return false;

}

/**
 * Hook to run after multiselect is run when an item is selected.
 * @param event Browser click event object
 * @param {Object} tree A Treebeard _item object. Node information is inside item.data
 * @this Treebeard.controller
 * @private
 */
function _poMultiselect(event, tree) {
    var tb = this;
    filterRowsNotInParent.call(tb, tb.multiselected());
    var scrollToItem = false;
    tb.options.updateSelected(tb.multiselected());
    if (tb.multiselected().length === 1) {
        tb.select('#tb-tbody').removeClass('unselectable');
    } else if (tb.multiselected().length > 1) {
        tb.select('#tb-tbody').addClass('unselectable');
    }
    m.redraw();
}

/**
 * When multiple rows are selected remove those that are not in the parent
 * @param {Array} rows List of item objects
 * @returns {Array} newRows Returns the revised list of rows
 */
function filterRowsNotInParent(rows) {
    var tb = this;
    if (tb.multiselected().length < 2) {
        return tb.multiselected();
    }
    var i, newRows = [],
        originalRow = tb.find(tb.multiselected()[0].id),
        originalParent,
        currentItem;
    var changeColor = function() { $(this).css('background-color', ''); };
    if (typeof originalRow !== 'undefined') {
        originalParent = originalRow.parentID;
        for (i = 0; i < rows.length; i++) {
            currentItem = rows[i];
            if (currentItem.parentID === originalParent && currentItem.id !== -1) {
                newRows.push(rows[i]);
            } else {
                $('.tb-row[data-id="' + rows[i].id + '"]').stop().css('background-color', '#D18C93').animate({ backgroundColor: '#fff'}, 500, changeColor);
            }
        }
    }
    tb.multiselected(newRows);
    tb.highlightMultiselect();
    return newRows;
}

function _poIconView(item) {
    return false;
}

/**
 * OSF-specific Treebeard options common to all addons.
 * For documentation visit: https://github.com/caneruguz/treebeard/wiki
 */
var tbOptions = {
    placement : 'dashboard',
    divID: 'projectOrganizer',
    rowHeight : 35,         // user can override or get from .tb-row height
    showTotal : 15,         // Actually this is calculated with div height, not needed. NEEDS CHECKING
    columnTitles : _poColumnTitles,
    resolveRows : _poResolveRows,
    showFilter : true,     // Gives the option to filter by showing the filter box.
    title : false,          // Title of the grid, boolean, string OR function that returns a string.
    allowMove : true,       // Turn moving on or off.
    moveClass : 'po-draggable',
    hoverClass : 'fangorn-hover',
    multiselect : true,
    hoverClassMultiselect : 'fangorn-selected',
    sortButtonSelector : {
        up : 'i.fa.fa-angle-up',
        down : 'i.fa.fa-angle-down'
    },
    sortDepth : 0,
    onload : function () {

        var tb = this,
            rowDiv = tb.select('.tb-row');
        rowDiv.first().trigger('click');
        $('.gridWrapper').on('mouseout', function () {
            tb.select('.tb-row').removeClass('po-hover');
        });
        m.render(document.getElementById('poFilter'), tb.options.filterTemplate.call(this));
    },
    ontogglefolder : function (item, event) {
        if (!item.open) {
            item.load = false;
        }
        $('[data-toggle="tooltip"]').tooltip();
    },
    onscrollcomplete : function () {
        $('[data-toggle="tooltip"]').tooltip();
    },
    onmultiselect : _poMultiselect,
    resolveIcon : _poIconView,
    resolveToggle : _poResolveToggle,
    resolveLazyloadUrl : _poResolveLazyLoad,
    resolveRefreshIcon : function () {
        return m('i.fa.fa-refresh.fa-spin');
    }, naturalScrollLimit : 0,
    removeIcon : function(){
        return m.trust('×');
    },
    headerTemplate : function(){ return ''; },
    xhrconfig : function(xhr) {
        xhr.withCredentials = true;
    },
    ondblclickrow : function(item, event){
        var tb = this;
        var node = item.data;
        var linkObject = new LinkObject('node', node, node.attributes.title);
        // Get ancestors
        linkObject.ancestors = [];
        function getAncestors (item) {
            var parent = item.parent();
            if(parent && parent.id > tb.treeData.id) {
                linkObject.ancestors.unshift(parent);
                getAncestors(parent);
            }
        }
        getAncestors(item);
        tb.options.updateFilesData(linkObject);
    },
    hScroll : 300,
    filterTemplate : function() {
        var tb = this;
        return [
            m('input.form-control[placeholder="Search all my projects"][type="text"]', {
                style: 'display:inline;',
                onkeyup: function(event){
                    if ($(this).val().length === 1){
                        tb.updateFolder(allProjectsCache().data, tb.treeData);
                    }
                    tb.filter(event);
                },
                onchange: m.withAttr('value', tb.filterText),
                value: tb.filterText()
            }),
            m('.filterReset', { onclick : function () {
                tb.resetFilter.call(tb);
                $('#poFilter>input').val('');
            } }, tb.options.removeIcon())
        ];
    },
    hiddenFilterRows : ['tags']
};

var ProjectOrganizer = {
    controller : function (args) {
        LinkObject = args.LinkObject;
        var self = this;
        self.updateTB = function(){
            var poOptions = $.extend(
                {
                    updateSelected : args.updateSelected,
                    updateFilesData : args.updateFilesData,
                    filesData: args.filesData().data,
                    wrapperSelector : args.wrapperSelector,
                    dragContainment : args.dragContainment
                },
                tbOptions
            );
            var tb = new Treebeard(poOptions, true);
            m.redraw.strategy('all');
            return tb;
        };
        allProjectsCache = args.allProjects;
        self.tb = self.updateTB();
    },
    view : function (ctrl, args) {
        var tb = ctrl.tb;
        if (args.reload()) {
            tb = ctrl.updateTB();
            args.reload(false);
        }
        return m('.fb-project-organizer#projectOrganizer', tb );
    }
};

module.exports = ProjectOrganizer;

<commit_msg>Remove toggle icons in filter mode [skip ci]<commit_after>/**
 * Handles Project Organizer on dashboard page of OSF.
 * For Treebeard and _item API's check: https://github.com/caneruguz/treebeard/wiki
 */
'use strict';

var Treebeard = require('treebeard');

// CSS
require('css/typeahead.css');
require('css/fangorn.css');

var $ = require('jquery');
var m = require('mithril');
var moment = require('moment');
var Raven = require('raven-js');
var $osf = require('js/osfHelpers');
var iconmap = require('js/iconmap');

var LinkObject;
var allProjectsCache;
/**
 * Edits the template for the column titles.
 * Used here to make smart folder italicized
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @this Treebeard.controller Check Treebeard API for methods available
 * @private
 */
function _poTitleColumn(item) {
    var tb = this;
    var preventSelect = function(e){
        e.stopImmediatePropagation();
    };
    var node = item.data; // Where actual data of the node is
    var css = ''; // Keep for future expandability -- Remove: item.data.isSmartFolder ? 'project-smart-folder smart-folder' : '';
    if (item.data.archiving) { // TODO check if this variable will be available
        return  m('span', {'class': 'registration-archiving'}, node.attributes.title + ' [Archiving]');
    } else if(node.links.html){
        return [ m('a.fg-file-links', { 'class' : css, href : node.links.html, 'data-nodeID' : node.id, onclick : preventSelect}, node.attributes.title) ];
    } else {
        return  m('span', { 'class' : css, 'data-nodeID' : node.id }, node.attributes.title);
    }
}

/**
 * Contributors have first person's name and then number of contributors. This function returns the proper html
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @returns {Object} A Mithril virtual DOM template object
 * @private
 */
function _poContributors(item) {
    var contributorList = item.data.embeds.contributors.data;
    if (contributorList.length === 0) {
        return '';
    }

    return contributorList.map(function (person, index, arr) {
        var name;
        var familyName = person.embeds.users.data.attributes.family_name;
        var givenName = person.embeds.users.data.attributes.given_name;
        if (familyName) {
            name = familyName;
        } else if(givenName){
            name = givenName;
        } else {
            name = 'A Contributor';
        }
        var comma;
        if (index === 0) {
            comma = '';
        } else {
            comma = ', ';
        }
        if (index > 2) {
            return m('span');
        }
        if (index === 2) {
            return m('span', ' + ' + (arr.length - 2));
        }
        return m('span', comma + name);
    });
}

/**
 * Displays who modified the data and when. i.e. "6 days ago, by Uguz"
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @private
 */
function _poModified(item) {
    var dateString = '';
    var node = item.data;
    dateString = moment.utc(node.attributes.date_modified).fromNow();
    return m('span', dateString);
}

/**
 * Organizes all the row displays based on what that item requires.
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @returns {Array} An array of columns as col objects
 * @this Treebeard.controller Check Treebeard API For available methods
 * @private
 */
function _poResolveRows(item) {
    var mobile = window.innerWidth < 767; // true if mobile view
    var tb = this;
    var folderIcons = tb.filterOn ? false : true;
    var default_columns = [];

    if(this.isMultiselected(item.id)){
        item.css = 'fangorn-selected';
    } else {
        item.css = '';
    }

    default_columns.push({
        data : 'name',  // Data field name
        folderIcons : folderIcons,
        filter : true,
        css : 'po-draggable', // All projects are draggable since we separated collections from the grid
        custom : _poTitleColumn
    });

    if (!mobile) {
        default_columns.push({
            data : 'contributors',
            filter : true,
            custom : _poContributors
        }, {
            data : 'dateModified',
            filter : false,
            custom : _poModified
        });
    } else {
        default_columns.push({
            data : 'name',
            filter : false,
            custom : function (row){
                return m('.btn.btn-default.btn-sm[data-toggle="modal"][data-target="#infoModal"]', {
                }, m('i.fa.fa-ellipsis-h'));
            }
        });
    }

    return default_columns;
}

/**
 * Organizes the information for Column title row.
 * @returns {Array} An array of columns with pertinent column information
 * @private
 */
function _poColumnTitles() {
    var columns = [];
    var mobile = window.innerWidth < 767; // true if mobile view
    if(!mobile){
        columns.push({
            title: 'Name',
            width : '50%',
            sort : true,
            sortType : 'text'
        },{
            title : 'Contributors',
            width : '25%',
            sort : false
        }, {
            title : 'Modified',
            width : '25%',
            sort : false
        });
    } else {
        columns.push({
            title: 'Name',
            width : '90%',
            sort : true,
            sortType : 'text'
        },{
            title : '',
            width : '10%',
            sort : false
        });
    }

    return columns;
}

/**
 * Returns custom folder toggle icons for OSF
 * @param {Object} item A Treebeard _item object. Node information is inside item.data
 * @this Treebeard.controller
 * @returns {string} Returns a mithril template with m() function, or empty string.
 * @private
 */
function _poResolveToggle(item) {
    var toggleMinus = m('i.fa.fa-minus'),
        togglePlus = m('i.fa.fa-plus'),
        childrenCount = item.data.relationships.children.links.related.meta.count;
    if (childrenCount > 0) {
        if (item.open) {
            return toggleMinus;
        }
        return togglePlus;
    }
    return '';
}

/**
 * Resolves lazy load url for fetching children
 * @param {Object} item A Treebeard _item object for the row involved. Node information is inside item.data
 * @this Treebeard.controller
 * @returns {String|Boolean} Returns the fetch URL in string or false if there is no url.
 * @private
 */
function _poResolveLazyLoad(item) {
    var node = item.data;
    if(item.children.length > 0) {
        return false;
    }
    if(node.relationships.children){
        //return node.relationships.children.links.related.href;
        return $osf.apiV2Url('nodes/' + node.id + '/children/', {
            query : {
                'related_counts' : true,
                'embed' : 'contributors'
            }
        });
    }
    return false;

}

/**
 * Hook to run after multiselect is run when an item is selected.
 * @param event Browser click event object
 * @param {Object} tree A Treebeard _item object. Node information is inside item.data
 * @this Treebeard.controller
 * @private
 */
function _poMultiselect(event, tree) {
    var tb = this;
    filterRowsNotInParent.call(tb, tb.multiselected());
    var scrollToItem = false;
    tb.options.updateSelected(tb.multiselected());
    if (tb.multiselected().length === 1) {
        tb.select('#tb-tbody').removeClass('unselectable');
    } else if (tb.multiselected().length > 1) {
        tb.select('#tb-tbody').addClass('unselectable');
    }
    m.redraw();
}

/**
 * When multiple rows are selected remove those that are not in the parent
 * @param {Array} rows List of item objects
 * @returns {Array} newRows Returns the revised list of rows
 */
function filterRowsNotInParent(rows) {
    var tb = this;
    if (tb.multiselected().length < 2) {
        return tb.multiselected();
    }
    var i, newRows = [],
        originalRow = tb.find(tb.multiselected()[0].id),
        originalParent,
        currentItem;
    var changeColor = function() { $(this).css('background-color', ''); };
    if (typeof originalRow !== 'undefined') {
        originalParent = originalRow.parentID;
        for (i = 0; i < rows.length; i++) {
            currentItem = rows[i];
            if (currentItem.parentID === originalParent && currentItem.id !== -1) {
                newRows.push(rows[i]);
            } else {
                $('.tb-row[data-id="' + rows[i].id + '"]').stop().css('background-color', '#D18C93').animate({ backgroundColor: '#fff'}, 500, changeColor);
            }
        }
    }
    tb.multiselected(newRows);
    tb.highlightMultiselect();
    return newRows;
}

function _poIconView(item) {
    return false;
}

/**
 * OSF-specific Treebeard options common to all addons.
 * For documentation visit: https://github.com/caneruguz/treebeard/wiki
 */
var tbOptions = {
    placement : 'dashboard',
    divID: 'projectOrganizer',
    rowHeight : 35,         // user can override or get from .tb-row height
    showTotal : 15,         // Actually this is calculated with div height, not needed. NEEDS CHECKING
    columnTitles : _poColumnTitles,
    resolveRows : _poResolveRows,
    showFilter : true,     // Gives the option to filter by showing the filter box.
    title : false,          // Title of the grid, boolean, string OR function that returns a string.
    allowMove : true,       // Turn moving on or off.
    moveClass : 'po-draggable',
    hoverClass : 'fangorn-hover',
    multiselect : true,
    hoverClassMultiselect : 'fangorn-selected',
    sortButtonSelector : {
        up : 'i.fa.fa-angle-up',
        down : 'i.fa.fa-angle-down'
    },
    sortDepth : 0,
    onload : function () {

        var tb = this,
            rowDiv = tb.select('.tb-row');
        rowDiv.first().trigger('click');
        $('.gridWrapper').on('mouseout', function () {
            tb.select('.tb-row').removeClass('po-hover');
        });
        m.render(document.getElementById('poFilter'), tb.options.filterTemplate.call(this));
    },
    ontogglefolder : function (item, event) {
        if (!item.open) {
            item.load = false;
        }
        $('[data-toggle="tooltip"]').tooltip();
    },
    onscrollcomplete : function () {
        $('[data-toggle="tooltip"]').tooltip();
    },
    onmultiselect : _poMultiselect,
    resolveIcon : _poIconView,
    resolveToggle : _poResolveToggle,
    resolveLazyloadUrl : _poResolveLazyLoad,
    resolveRefreshIcon : function () {
        return m('i.fa.fa-refresh.fa-spin');
    }, naturalScrollLimit : 0,
    removeIcon : function(){
        return m.trust('×');
    },
    headerTemplate : function(){ return ''; },
    xhrconfig : function(xhr) {
        xhr.withCredentials = true;
    },
    ondblclickrow : function(item, event){
        var tb = this;
        var node = item.data;
        var linkObject = new LinkObject('node', node, node.attributes.title);
        // Get ancestors
        linkObject.ancestors = [];
        function getAncestors (item) {
            var parent = item.parent();
            if(parent && parent.id > tb.treeData.id) {
                linkObject.ancestors.unshift(parent);
                getAncestors(parent);
            }
        }
        getAncestors(item);
        tb.options.updateFilesData(linkObject);
    },
    hScroll : 300,
    filterTemplate : function() {
        var tb = this;
        return [
            m('input.form-control[placeholder="Search all my projects"][type="text"]', {
                style: 'display:inline;',
                onkeyup: function(event){
                    if ($(this).val().length === 1){
                        tb.updateFolder(allProjectsCache().data, tb.treeData);
                    }
                    tb.filter(event);
                },
                onchange: m.withAttr('value', tb.filterText),
                value: tb.filterText()
            }),
            m('.filterReset', { onclick : function () {
                tb.resetFilter.call(tb);
                $('#poFilter>input').val('');
            } }, tb.options.removeIcon())
        ];
    },
    hiddenFilterRows : ['tags']
};

var ProjectOrganizer = {
    controller : function (args) {
        LinkObject = args.LinkObject;
        var self = this;
        self.updateTB = function(){
            var poOptions = $.extend(
                {
                    updateSelected : args.updateSelected,
                    updateFilesData : args.updateFilesData,
                    filesData: args.filesData().data,
                    wrapperSelector : args.wrapperSelector,
                    dragContainment : args.dragContainment
                },
                tbOptions
            );
            var tb = new Treebeard(poOptions, true);
            m.redraw.strategy('all');
            return tb;
        };
        allProjectsCache = args.allProjects;
        self.tb = self.updateTB();
    },
    view : function (ctrl, args) {
        var tb = ctrl.tb;
        if (args.reload()) {
            tb = ctrl.updateTB();
            args.reload(false);
        }
        return m('.fb-project-organizer#projectOrganizer', tb );
    }
};

module.exports = ProjectOrganizer;

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2007-2009 Diego Perini
 * All rights reserved.
 *
 * this is just a small example to show
 * how an extension for NWMatcher could be
 * adapted to handle special jQuery selectors
 *
 * Child Selectors
 * :even, :odd, :eq, :lt, :gt, :first, :last, :nth
 *
 * Pseudo Selectors
 * :has, :button, :header, :input, :checkbox, :radio, :file, :image
 * :password, :reset, :submit, :text, :hidden, :visible, :parent
 *
 */

// for structural pseudo-classes extensions
var jquery_ChildSelectors = function(match, source) {

  var status = true,
  // do not change this, it is searched & replaced
  ACCEPT_NODE = 'r[r.length]=c[k];continue main;';

  if (match[2]) {
    match[2] = match[2].replace(/^\((.*)\)$/, '$1');
  }

  switch (match[1]) {
    case 'even':
      source = source.replace(ACCEPT_NODE, 'x=1-x;if(x==1){' + ACCEPT_NODE + '}');
      break;
    case 'odd':
      source = source.replace(ACCEPT_NODE, 'x=1-x;if(x==0){' + ACCEPT_NODE + '}');
      break;
    case 'eq':
      source = source.replace(ACCEPT_NODE, 'if(x++==' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'lt':
      source = source.replace(ACCEPT_NODE, 'if(x++<' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'gt':
      source = source.replace(ACCEPT_NODE, 'if(x++>' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'first':
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[0]==e){' + source + '}';
      break;
    case 'last':
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[n.length-1]==e){' + source + '}';
      break;
    case 'nth':
      match[2] = match[2].replace(/\(["']*|['"]*\)/g, '');
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[' + match[2] + ']==e){' + source + '}';
      break;
    default:
      status = false;
      break;
  }

  // compiler will add this to "source"
  return {
    'source': source,
    'status': status
  };

};

// for element pseudo-classes extensions
var jquery_PseudoSelectors = function(match, source) {

  var status = true,
  // do not change this, it is searched & replaced
  ACCEPT_NODE = 'r[r.length]=c[k];continue main;';

  switch(match[1]) {
    case 'has':
      if (match[2]) {
        match[2] = match[2].replace(/^\((.*)\)$/, '$1');
      }
      source = source.replace(ACCEPT_NODE, 'if(this.byTag("' + match[2] + '",e)[0]){' + ACCEPT_NODE + '}');
      break;
    case 'checkbox':
    case 'file':
    case 'image':
    case 'password':
    case 'radio':
    case 'reset':
    case 'submit':
    case 'text':
      // :checkbox, :file, :image, :password, :radio, :reset, :submit, :text, ... ;-)
      source = 'if(e.type&&e.type=="' + match[1] + '"){' + source + '}';
      break;
    case 'button':
    case 'input':
      source = 'if(e.type||/button/i.test(e.nodeName)){' + source + '}';
      break;
    case 'header':
      source = 'if(/h[1-6]/i.test(e.nodeName)){' + source + '}';
      break;
    case 'hidden':
      source = 'if(e.type=="hidden"||e.style.display=="none"||e.style.visibility=="hidden"){' + source + '}';
      break;
    case 'visible':
      source = 'if(e.type!="hidden"&&e.style.display!="none"&&e.style.visibility!="hidden"){' + source + '}';
      break;
    case 'parent':
      source += 'if(e.firstChild){' + source + '}';
      break;
    default:
      status = false;
      break;
  }

  // compiler will add this to "source"
  return {
    'source': source,
    'status': status
  };

};

// the following is taken directly from latest jQuery
// /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/;
var RE1 = /^\:(first|last|even|odd|nth|eq|gt|lt)(\((?:even|odd|[^\)]*)\))?(.*)/;
var RE2 = /^\:((?:[-\w]|\\.)+)(\(([\x22\x27]*)?(.*?(\(.*?\))?[^(]*?)\3\))?(.*)/;

// must register in this order due to how the selectors
// are written, the second begins with a grab all rule...
NW.Dom.registerSelector('jQuery-child', RE1, jquery_ChildSelectors);
NW.Dom.registerSelector('jQuery-pseudo', RE2, jquery_PseudoSelectors);

(function(global) {

  // # cleaned
  var cnt = 0,

  context = global.document;

  root = context.documentElement,

  // remove comment nodes and empty text nodes
  // unique child with empty text nodes are kept
  // to pass Prototype selector test unit :-)
  cleanDOM =
    function(node) {
      var next, val;
      while (node) {
        next = node.nextSibling;
        if (node.nodeType == 1 && node.firstChild) {
          cleanDOM(node.firstChild);
        } else if (node.nodeType == 3) {
          val = node.nodeValue.replace(/\s+/g, ' ');
          if (val == ' ' && node != node.parentNode.childNodes[0]) {
            node.parentNode.removeChild(node);
            cnt++;
          }
        } else if (node.nodeType == 8) {
          node.parentNode.removeChild(node);
        }
        node = next;
      }
    },

  start = root.addEventListener ?
    function() {
      context.removeEventListener('DOMContentLoaded', start, false);
      cleanDOM(root);
      NW.Dom.select('*:nth-child(n)');
      // XML parsing ?
      root.normalize();
      top.status += 'Removed ' + cnt + ' empty text nodes.';
    } :
    function() {
      if (context.readyState == 'complete') {
        context.detachEvent('onreadystatechange', start);
        cleanDOM(root);
        NW.Dom.select('*:nth-child(n)');
        // will crash IE6
        //root.normalize();
        top.status += 'Removed ' + cnt + ' empty text nodes.';
      }
    };

  if (context.addEventListener) {
    context.addEventListener('DOMContentLoaded', start, false);
  } else if (context.attachEvent) {
    context.attachEvent('onreadystatechange', start);
  } else {
    global.onload = start;
  }

})(this);
<commit_msg>avoid warnings in firefox 'strict mode'<commit_after>/*
 * Copyright (C) 2007-2009 Diego Perini
 * All rights reserved.
 *
 * this is just a small example to show
 * how an extension for NWMatcher could be
 * adapted to handle special jQuery selectors
 *
 * Child Selectors
 * :even, :odd, :eq, :lt, :gt, :first, :last, :nth
 *
 * Pseudo Selectors
 * :has, :button, :header, :input, :checkbox, :radio, :file, :image
 * :password, :reset, :submit, :text, :hidden, :visible, :parent
 *
 */

// for structural pseudo-classes extensions
var jquery_ChildSelectors = function(match, source) {

  var status = true,
  // do not change this, it is searched & replaced
  ACCEPT_NODE = 'r[r.length]=c[k];continue main;';

  if (match[2]) {
    match[2] = match[2].replace(/^\((.*)\)$/, '$1');
  }

  switch (match[1]) {
    case 'even':
      source = source.replace(ACCEPT_NODE, 'x=1-x;if(x==1){' + ACCEPT_NODE + '}');
      break;
    case 'odd':
      source = source.replace(ACCEPT_NODE, 'x=1-x;if(x==0){' + ACCEPT_NODE + '}');
      break;
    case 'eq':
      source = source.replace(ACCEPT_NODE, 'if(x++==' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'lt':
      source = source.replace(ACCEPT_NODE, 'if(x++<' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'gt':
      source = source.replace(ACCEPT_NODE, 'if(x++>' + match[2] + '){' + ACCEPT_NODE + '}');
      break;
    case 'first':
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[0]==e){' + source + '}';
      break;
    case 'last':
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[n.length-1]==e){' + source + '}';
      break;
    case 'nth':
      match[2] = match[2].replace(/\(["']*|['"]*\)/g, '');
      source = 'n=this.byTag(e.nodeName,e.ownerDocument);if(n&&n[' + match[2] + ']==e){' + source + '}';
      break;
    default:
      status = false;
      break;
  }

  // compiler will add this to "source"
  return {
    'source': source,
    'status': status
  };

};

// for element pseudo-classes extensions
var jquery_PseudoSelectors = function(match, source) {

  var status = true,
  // do not change this, it is searched & replaced
  ACCEPT_NODE = 'r[r.length]=c[k];continue main;';

  switch(match[1]) {
    case 'has':
      if (match[2]) {
        match[2] = match[2].replace(/^\((.*)\)$/, '$1');
      }
      source = source.replace(ACCEPT_NODE, 'if(this.byTag("' + match[2] + '",e)[0]){' + ACCEPT_NODE + '}');
      break;
    case 'checkbox':
    case 'file':
    case 'image':
    case 'password':
    case 'radio':
    case 'reset':
    case 'submit':
    case 'text':
      // :checkbox, :file, :image, :password, :radio, :reset, :submit, :text, ... ;-)
      source = 'if(e.type&&e.type=="' + match[1] + '"){' + source + '}';
      break;
    case 'button':
    case 'input':
      source = 'if(e.type||/button/i.test(e.nodeName)){' + source + '}';
      break;
    case 'header':
      source = 'if(/h[1-6]/i.test(e.nodeName)){' + source + '}';
      break;
    case 'hidden':
      source = 'if(e.type=="hidden"||e.style.display=="none"||e.style.visibility=="hidden"){' + source + '}';
      break;
    case 'visible':
      source = 'if(e.type!="hidden"&&e.style.display!="none"&&e.style.visibility!="hidden"){' + source + '}';
      break;
    case 'parent':
      source += 'if(e.firstChild){' + source + '}';
      break;
    default:
      status = false;
      break;
  }

  // compiler will add this to "source"
  return {
    'source': source,
    'status': status
  };

};

// the following is taken directly from latest jQuery
// /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/;
var RE1 = /^\:(first|last|even|odd|nth|eq|gt|lt)(\((?:even|odd|[^\)]*)\))?(.*)/;
var RE2 = /^\:((?:[-\w]|\\.)+)(\(([\x22\x27]*)?(.*?(\(.*?\))?[^(]*?)\3\))?(.*)/;

// must register in this order due to how the selectors
// are written, the second begins with a grab all rule...
NW.Dom.registerSelector('jQuery-child', RE1, jquery_ChildSelectors);
NW.Dom.registerSelector('jQuery-pseudo', RE2, jquery_PseudoSelectors);

(function(global) {

  // # cleaned
  var cnt = 0,

  context = global.document,

  root = context.documentElement,

  // remove comment nodes and empty text nodes
  // unique child with empty text nodes are kept
  // to pass Prototype selector test unit :-)
  cleanDOM =
    function(node) {
      var next, val;
      while (node) {
        next = node.nextSibling;
        if (node.nodeType == 1 && node.firstChild) {
          cleanDOM(node.firstChild);
        } else if (node.nodeType == 3) {
          val = node.nodeValue.replace(/\s+/g, ' ');
          if (val == ' ' && node != node.parentNode.childNodes[0]) {
            node.parentNode.removeChild(node);
            cnt++;
          }
        } else if (node.nodeType == 8) {
          node.parentNode.removeChild(node);
        }
        node = next;
      }
    },

  start = root.addEventListener ?
    function() {
      context.removeEventListener('DOMContentLoaded', start, false);
      cleanDOM(root);
      NW.Dom.select('*:nth-child(n)');
      // XML parsing ?
      root.normalize();
      top.status += 'Removed ' + cnt + ' empty text nodes.';
    } :
    function() {
      if (context.readyState == 'complete') {
        context.detachEvent('onreadystatechange', start);
        cleanDOM(root);
        NW.Dom.select('*:nth-child(n)');
        // will crash IE6
        //root.normalize();
        top.status += 'Removed ' + cnt + ' empty text nodes.';
      }
    };

  if (context.addEventListener) {
    context.addEventListener('DOMContentLoaded', start, false);
  } else if (context.attachEvent) {
    context.attachEvent('onreadystatechange', start);
  } else {
    global.onload = start;
  }

})(this);
<|endoftext|>


<commit_before>/**
 * This is a bridge between ultrafast particle renderer and react world.
 *
 * It listens to graph loading events. Once graph positions are loaded it calls
 * native renderer to show the positions.
 *
 * It also listens to native renderer for user interaction. When user hovers
 * over a node or clicks on it - it reports user actions back to the global
 * events bus. These events are later consumed by stores to show appropriate
 * UI feedback
 */
import unrender from 'unrender';
import eventify from 'ngraph.events';
import appEvents from '../service/appEvents.js';
import scene from '../store/scene.js';
import getNearestIndex from './getNearestIndex.js';

export default sceneRenderer;

function sceneRenderer(container) {
  var renderer, positions, graphModel;
  var hitTest;

  appEvents.positionsDownloaded.on(setPositions);
  appEvents.toggleSteering.on(toggleSteering);
  appEvents.focusOnNode.on(focusOnNode);

  var api = {
    destroy: destroy
  };

  eventify(api);
  return api;

  function toggleSteering() {
    if (!renderer) return;

    var input = renderer.input();
    var isDragToLookEnabled = input.toggleDragToLook();

    // steering does not require "drag":
    var isSteering = !isDragToLookEnabled;
    appEvents.showSteeringMode.fire(isSteering);
  }

  function focusOnNode(nodeId) {
    if (!renderer) return;

    renderer.lookAt(nodeId * 3, highlightFocused);

    function highlightFocused() {
      appEvents.selectNode.fire(nodeId);
    }
  }

  function setPositions(_positions) {
    destroyHitTest();

    positions = _positions;

    if (!renderer) renderer = unrender(container);
    renderer.particles(positions);

    hitTest = renderer.hitTest();
    hitTest.on('over', handleOver);
    hitTest.on('click', handleClick);
  }

  function destroyHitTest() {
    if (!hitTest) return; // nothing to destroy
    hitTest.off('over', handleOver);
  }

  function handleClick(e) {
    var nearestIndex = getNearestIndex(positions, e.indexes, e.ray, 30);

    appEvents.selectNode.fire(getModelIndex(nearestIndex));
  }

  function handleOver(e) {
    var nearestIndex = getNearestIndex(positions, e.indexes, e.ray, 30);

    highlightNode(nearestIndex);
    appEvents.nodeHover.fire({
      nodeIndex: getModelIndex(nearestIndex),
      mouseInfo: e
    });
  }

  function highlightNode(nodeIndex) {
    if (nodeIndex !== undefined) {
      renderer.highlight([nodeIndex], 0xff0000, 3);
    } else {
      // reset old highlihgt:
      renderer.highlight(nodeIndex, 0xff0000);
    }
  }

  function getModelIndex(nearestIndex) {
    if (nearestIndex !== undefined) {
      // since each node represented as triplet we need to divide by 3 to
      // get actual index:
      return nearestIndex/3
    }
  }

  function destroy() {
    renderer.destroy();
    scene.off('positions', setPositions);
    renderer = null;
  }
}
<commit_msg>Added double click for fly to<commit_after>/**
 * This is a bridge between ultrafast particle renderer and react world.
 *
 * It listens to graph loading events. Once graph positions are loaded it calls
 * native renderer to show the positions.
 *
 * It also listens to native renderer for user interaction. When user hovers
 * over a node or clicks on it - it reports user actions back to the global
 * events bus. These events are later consumed by stores to show appropriate
 * UI feedback
 */
import unrender from 'unrender';
import eventify from 'ngraph.events';
import appEvents from '../service/appEvents.js';
import scene from '../store/scene.js';
import getNearestIndex from './getNearestIndex.js';

export default sceneRenderer;

function sceneRenderer(container) {
  var renderer, positions, graphModel;
  var hitTest;

  appEvents.positionsDownloaded.on(setPositions);
  appEvents.toggleSteering.on(toggleSteering);
  appEvents.focusOnNode.on(focusOnNode);

  var api = {
    destroy: destroy
  };

  eventify(api);
  return api;

  function toggleSteering() {
    if (!renderer) return;

    var input = renderer.input();
    var isDragToLookEnabled = input.toggleDragToLook();

    // steering does not require "drag":
    var isSteering = !isDragToLookEnabled;
    appEvents.showSteeringMode.fire(isSteering);
  }

  function focusOnNode(nodeId) {
    if (!renderer) return;

    renderer.lookAt(nodeId * 3, highlightFocused);

    function highlightFocused() {
      appEvents.selectNode.fire(nodeId);
    }
  }

  function setPositions(_positions) {
    destroyHitTest();

    positions = _positions;

    if (!renderer) renderer = unrender(container);
    renderer.particles(positions);

    hitTest = renderer.hitTest();
    hitTest.on('over', handleOver);
    hitTest.on('click', handleClick);
    hitTest.on('dblclick', handleDblClick);
  }

  function destroyHitTest() {
    if (!hitTest) return; // nothing to destroy
    hitTest.off('over', handleOver);
    hitTest.off('click', handleClick);
    hitTest.off('dblclick', handleDblClick);
  }

  function handleClick(e) {
    var nearestIndex = getNearestIndex(positions, e.indexes, e.ray, 30);

    appEvents.selectNode.fire(getModelIndex(nearestIndex));
  }

  function handleDblClick(e) {
    var nearestIndex = getNearestIndex(positions, e.indexes, e.ray, 30);
    if (nearestIndex !== undefined) {
      focusOnNode(nearestIndex/3);
    }
  }

  function handleOver(e) {
    var nearestIndex = getNearestIndex(positions, e.indexes, e.ray, 30);

    highlightNode(nearestIndex);
    appEvents.nodeHover.fire({
      nodeIndex: getModelIndex(nearestIndex),
      mouseInfo: e
    });
  }

  function highlightNode(nodeIndex) {
    if (nodeIndex !== undefined) {
      renderer.highlight([nodeIndex], 0xff0000, 3);
    } else {
      // reset old highlihgt:
      renderer.highlight(nodeIndex, 0xff0000);
    }
  }

  function getModelIndex(nearestIndex) {
    if (nearestIndex !== undefined) {
      // since each node represented as triplet we need to divide by 3 to
      // get actual index:
      return nearestIndex/3
    }
  }

  function destroy() {
    renderer.destroy();
    scene.off('positions', setPositions);
    renderer = null;
  }
}
<|endoftext|>


<commit_before>
Tasks = new Mongo.Collection("tasks");

if(Meteor.isServer){
    if(Tasks.find().count() === 0){
        var toAdd = [
            {name: 'This is Task 1'},
            {name: 'This is Task 2'},
            {name: 'This is Task 3'}
        ];

        toAdd.forEach(function(item){
           Tasks.insert(item);
        });
    }
}

Meteor.startup(function () {
    Meteor.userEmail = function () {
        var currentEmail = null;
        try {
            currentEmail = Meteor.user().emails[0].address;
        } catch (e) {
            currentEmail = null;
        }
        return currentEmail;
    };
});

Meteor.methods({
    addTask: function (text) {
        Tasks.insert({
            name: text,
            email: Meteor.userEmail(),
            createdAt: new Date()
        });
    },
    deleteTask: function (id) {
        Tasks.remove(id);
    }
});
<commit_msg>Allow only owner to delete tasks<commit_after>
Tasks = new Mongo.Collection("tasks");

if(Meteor.isServer){
    if(Tasks.find().count() === 0){
        var toAdd = [
            {name: 'This is Task 1'},
            {name: 'This is Task 2'},
            {name: 'This is Task 3'}
        ];

        toAdd.forEach(function(item){
           Tasks.insert(item);
        });
    }
}

Meteor.startup(function () {
    Meteor.userEmail = function () {
        var currentEmail = null;
        try {
            currentEmail = Meteor.user().emails[0].address;
        } catch (e) {
            currentEmail = null;
        }
        return currentEmail;
    };
});

Meteor.methods({
    addTask: function (text) {
        Tasks.insert({
            name: text,
            email: Meteor.userEmail(),
            owner: Meteor.userId(),
            createdAt: new Date()
        });
    },
    deleteTask: function (id) {
        var task = Tasks.findOne(id);
        if (task.owner && task.owner !== Meteor.userId()) {
            throw new Meteor.Error("not-authorized");
        }
        Tasks.remove(id);
    }
});
<|endoftext|>


<commit_before>exports.data = function(cb) {
	var util = require('util');
	var exec = require('child_process').exec;
	var res = {
		updates : []
	};

	exec("/usr/bin/sudo /usr/bin/apt-get --just-print upgrade", function(err, stdout, stderr) {
		if (!err) {
			var updates = stdout.split(/[\r\n]{1,2}/);
			for (var c = 0; c < updates.length; c++) {
				var update = updates[c];
				if (update) {
					var matches = update.match(/^Inst\s+(.*)\s+\[(.*)\]\s+\(([^s]*)\s+.*\)/);
					if (matches && matches.length) {
						res.updates.push({
							name : matches[1],
							old_version : matches[2],
							new_version : matches[3]
						});
					}
				}
			}
		}

		cb(res);
	});
};

exports.manage_post = function(post, cb) {
	cb(0, null);
};

exports.updatetime = 5 * 60 * 1000;
exports.title = 'Updates Info';
exports.columns = 6;<commit_msg>Updated values to sync with old DB value<commit_after>exports.data = function(cb) {
	var util = require('util');
	var exec = require('child_process').exec;
	var res = {
		updates : []
	};

	exec("/usr/bin/sudo /usr/bin/apt-get --just-print upgrade", function(err, stdout) {
		if (!err) {
			var updates = stdout.split(/[\r\n]{1,2}/);
			for (var c = 0; c < updates.length; c++) {
				var update = updates[c];
				if (update) {
					var matches = update.match(/^Inst\s+(.*)\s+\[(.*)\]\s+\(([^s]*)\s+.*\)/);
					if (matches && matches.length) {
						res.updates.push({
							name : matches[1],
							old_version : matches[2],
							new_version : matches[3]
						});
					}
				}
			}
		}

		cb(res);
	});
};

exports.manage_post = function(post, cb) {
	cb(0, null);
};

exports.updatetime = 60 * 60 * 1000;
exports.title = 'Updates Info';
exports.columns = 6;<|endoftext|>


<commit_before>// Export classes
module.exports = {
    version :                       require('../package.json').version,

    AABB :                          require('./collision/AABB'),
    ArrayCollisionMatrix :          require('./collision/ArrayCollisionMatrix'),
    Body :                          require('./objects/Body'),
    Box :                           require('./shapes/Box'),
    Broadphase :                    require('./collision/Broadphase'),
    Constraint :                    require('./constraints/Constraint'),
    ContactEquation :               require('./equations/ContactEquation'),
    Narrowphase :                   require('./world/Narrowphase'),
    ConeTwistConstraint :           require('./constraints/ConeTwistConstraint'),
    ContactMaterial :               require('./material/ContactMaterial'),
    ConvexPolyhedron :              require('./shapes/ConvexPolyhedron'),
    Cylinder :                      require('./shapes/Cylinder'),
    DistanceConstraint :            require('./constraints/DistanceConstraint'),
    Equation :                      require('./equations/Equation'),
    EventTarget :                   require('./utils/EventTarget'),
    FrictionEquation :              require('./equations/FrictionEquation'),
    GSSolver :                      require('./solver/GSSolver'),
    GridBroadphase :                require('./collision/GridBroadphase'),
    Heightfield :                   require('./shapes/Heightfield'),
    HingeConstraint :               require('./constraints/HingeConstraint'),
    LockConstraint :                require('./constraints/LockConstraint'),
    Mat3 :                          require('./math/Mat3'),
    Material :                      require('./material/Material'),
    NaiveBroadphase :               require('./collision/NaiveBroadphase'),
    ObjectCollisionMatrix :         require('./collision/ObjectCollisionMatrix'),
    Pool :                          require('./utils/Pool'),
    Particle :                      require('./shapes/Particle'),
    Plane :                         require('./shapes/Plane'),
    PointToPointConstraint :        require('./constraints/PointToPointConstraint'),
    Quaternion :                    require('./math/Quaternion'),
    Ray :                           require('./collision/Ray'),
    RaycastVehicle :                require('./objects/RaycastVehicle'),
    RaycastResult :                 require('./collision/RaycastResult'),
    RigidVehicle :                  require('./objects/RigidVehicle'),
    RotationalEquation :            require('./equations/RotationalEquation'),
    RotationalMotorEquation :       require('./equations/RotationalMotorEquation'),
    SAPBroadphase :                 require('./collision/SAPBroadphase'),
    SPHSystem :                     require('./objects/SPHSystem'),
    Shape :                         require('./shapes/Shape'),
    Solver :                        require('./solver/Solver'),
    Sphere :                        require('./shapes/Sphere'),
    SplitSolver :                   require('./solver/SplitSolver'),
    Spring :                        require('./objects/Spring'),
    Transform :                     require('./math/Transform'),
    Trimesh :                       require('./shapes/Trimesh'),
    Vec3 :                          require('./math/Vec3'),
    Vec3Pool :                      require('./utils/Vec3Pool'),
    World :                         require('./world/World'),
};
<commit_msg>ellipsoid shape  *** WIP ***<commit_after>// Export classes
module.exports = {
    version :                       require('../package.json').version,

    AABB :                          require('./collision/AABB'),
    ArrayCollisionMatrix :          require('./collision/ArrayCollisionMatrix'),
    Body :                          require('./objects/Body'),
    Box :                           require('./shapes/Box'),
    Broadphase :                    require('./collision/Broadphase'),
    Constraint :                    require('./constraints/Constraint'),
    ContactEquation :               require('./equations/ContactEquation'),
    Narrowphase :                   require('./world/Narrowphase'),
    ConeTwistConstraint :           require('./constraints/ConeTwistConstraint'),
    ContactMaterial :               require('./material/ContactMaterial'),
    ConvexPolyhedron :              require('./shapes/ConvexPolyhedron'),
    Cylinder :                      require('./shapes/Cylinder'),
    DistanceConstraint :            require('./constraints/DistanceConstraint'),
    Ellipsoid :                     require('./shapes/Ellipsoid'),
    Equation :                      require('./equations/Equation'),
    EventTarget :                   require('./utils/EventTarget'),
    FrictionEquation :              require('./equations/FrictionEquation'),
    GSSolver :                      require('./solver/GSSolver'),
    GridBroadphase :                require('./collision/GridBroadphase'),
    Heightfield :                   require('./shapes/Heightfield'),
    HingeConstraint :               require('./constraints/HingeConstraint'),
    LockConstraint :                require('./constraints/LockConstraint'),
    Mat3 :                          require('./math/Mat3'),
    Material :                      require('./material/Material'),
    NaiveBroadphase :               require('./collision/NaiveBroadphase'),
    ObjectCollisionMatrix :         require('./collision/ObjectCollisionMatrix'),
    Pool :                          require('./utils/Pool'),
    Particle :                      require('./shapes/Particle'),
    Plane :                         require('./shapes/Plane'),
    PointToPointConstraint :        require('./constraints/PointToPointConstraint'),
    Quaternion :                    require('./math/Quaternion'),
    Ray :                           require('./collision/Ray'),
    RaycastVehicle :                require('./objects/RaycastVehicle'),
    RaycastResult :                 require('./collision/RaycastResult'),
    RigidVehicle :                  require('./objects/RigidVehicle'),
    RotationalEquation :            require('./equations/RotationalEquation'),
    RotationalMotorEquation :       require('./equations/RotationalMotorEquation'),
    SAPBroadphase :                 require('./collision/SAPBroadphase'),
    SPHSystem :                     require('./objects/SPHSystem'),
    Shape :                         require('./shapes/Shape'),
    Solver :                        require('./solver/Solver'),
    Sphere :                        require('./shapes/Sphere'),
    SplitSolver :                   require('./solver/SplitSolver'),
    Spring :                        require('./objects/Spring'),
    Transform :                     require('./math/Transform'),
    Trimesh :                       require('./shapes/Trimesh'),
    Vec3 :                          require('./math/Vec3'),
    Vec3Pool :                      require('./utils/Vec3Pool'),
    World :                         require('./world/World'),
};
<|endoftext|>


<commit_before>/**
 *
 * @param metadataBackend
 * @param options
 * @constructor
 * @type {UserLimitsBackend}
 */
function UserLimitsBackend(metadataBackend, options) {
    this.metadataBackend = metadataBackend;
    this.options = options || {};
    this.options.limits = this.options.limits || {};

    this.preprareRateLimit();
}

module.exports = UserLimitsBackend;

UserLimitsBackend.prototype.getRenderLimits = function (username, apiKey, callback) {
    var self = this;

    var limits = {
        cacheOnTimeout: self.options.limits.cacheOnTimeout || false,
        render: self.options.limits.render || 0
    };

    self.getTimeoutRenderLimit(username, apiKey, function (err, timeoutRenderLimit) {
        if (err) {
            return callback(err);
        }

        if (timeoutRenderLimit && timeoutRenderLimit.render) {
            if (Number.isFinite(timeoutRenderLimit.render)) {
                limits.render = timeoutRenderLimit.render;
            }
        }

        return callback(null, limits);
    });
};

UserLimitsBackend.prototype.getTimeoutRenderLimit = function (username, apiKey, callback) {
    isAuthorized(this.metadataBackend, username, apiKey, (err, authorized) => {
        if (err) {
            return callback(err);
        }

        this.metadataBackend.getUserTimeoutRenderLimits(username, (err, timeoutRenderLimit) => {
            if (err) {
                return callback(err);
            }

            callback(
                null,
                { render: authorized ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic }
            );
        });
    });
};

function isAuthorized(metadataBackend, username, apiKey, callback) {
    if (!apiKey) {
        return callback(null, false);
    }

    metadataBackend.getUserMapKey(username, function (err, userApiKey) {
        if (err) {
            return callback(err);
        }

        return callback(null, userApiKey === apiKey);
    });
}

UserLimitsBackend.prototype.preprareRateLimit = function () {
    if (this.options.limits.rateLimitsEnabled) {
        this.metadataBackend.loadRateLimitsScript();
    }
};

UserLimitsBackend.prototype.getRateLimit = function (user, endpointGroup, callback) {
    this.metadataBackend.getRateLimit(user, 'maps', endpointGroup, callback);
};
<commit_msg>return callback<commit_after>/**
 *
 * @param metadataBackend
 * @param options
 * @constructor
 * @type {UserLimitsBackend}
 */
function UserLimitsBackend(metadataBackend, options) {
    this.metadataBackend = metadataBackend;
    this.options = options || {};
    this.options.limits = this.options.limits || {};

    this.preprareRateLimit();
}

module.exports = UserLimitsBackend;

UserLimitsBackend.prototype.getRenderLimits = function (username, apiKey, callback) {
    var self = this;

    var limits = {
        cacheOnTimeout: self.options.limits.cacheOnTimeout || false,
        render: self.options.limits.render || 0
    };

    self.getTimeoutRenderLimit(username, apiKey, function (err, timeoutRenderLimit) {
        if (err) {
            return callback(err);
        }

        if (timeoutRenderLimit && timeoutRenderLimit.render) {
            if (Number.isFinite(timeoutRenderLimit.render)) {
                limits.render = timeoutRenderLimit.render;
            }
        }

        return callback(null, limits);
    });
};

UserLimitsBackend.prototype.getTimeoutRenderLimit = function (username, apiKey, callback) {
    isAuthorized(this.metadataBackend, username, apiKey, (err, authorized) => {
        if (err) {
            return callback(err);
        }

        this.metadataBackend.getUserTimeoutRenderLimits(username, (err, timeoutRenderLimit) => {
            if (err) {
                return callback(err);
            }

            return callback(
                null,
                { render: authorized ? timeoutRenderLimit.render : timeoutRenderLimit.renderPublic }
            );
        });
    });
};

function isAuthorized(metadataBackend, username, apiKey, callback) {
    if (!apiKey) {
        return callback(null, false);
    }

    metadataBackend.getUserMapKey(username, function (err, userApiKey) {
        if (err) {
            return callback(err);
        }

        return callback(null, userApiKey === apiKey);
    });
}

UserLimitsBackend.prototype.preprareRateLimit = function () {
    if (this.options.limits.rateLimitsEnabled) {
        this.metadataBackend.loadRateLimitsScript();
    }
};

UserLimitsBackend.prototype.getRateLimit = function (user, endpointGroup, callback) {
    this.metadataBackend.getRateLimit(user, 'maps', endpointGroup, callback);
};
<|endoftext|>


<commit_before>/**
 * Created by hunte on 06/06/2016.
 */

var prntSvcs = angular.module("prntSvcs",['$rootScope', '$compile','$http','$timeout']);

prntSvcs.factory('printer',['printer', function($rootScope, $compile, $http, $timeout ){
    var printHtml = function (html) {
        var deferred = $q.defer();
        var hiddenFrame = $('').appendTo('body')[0];
        hiddenFrame.contentWindow.printAndRemove = function() {
            hiddenFrame.contentWindow.print();
            $(hiddenFrame).remove();
        };

    };

    var print = function (templateUrl, data) {
        $http.get(templateUrl).success(function(template){
            var printScope = $rootScope.$new()
            angular.extend(printScope, data);
            var element = $compile($('
' + template + '
'))(printScope);
            var waitForRenderAndPrint = function() {
                if(printScope.$$phase || $http.pendingRequests.length) {
                    $timeout(waitForRenderAndPrint);
                } else {
                    // Replace printHtml with openNewWindow for debugging
                    printHtml(element.html());
                    printScope.$destroy();
                }
            };
            waitForRenderAndPrint();
        });
    };
}]);

<commit_msg>Updated printService.js<commit_after>/**
 * Created by hunte on 06/06/2016.
 */

var prntSvcs = angular.module("prntSvcs",['$rootScope', '$compile','$http','$timeout']);

prntSvcs.factory('printer',['printer', function($rootScope, $compile, $http, $timeout ){
    var printHtml = function (html) {
        var deferred = $q.defer();
        var hiddenFrame = $('').appendTo('body')[0];
        hiddenFrame.contentWindow.printAndRemove = function() {
            hiddenFrame.contentWindow.print();
            $(hiddenFrame).remove();
        };

    };

}]);

<|endoftext|>


<commit_before>define([
	'jquery',
	'room-info',
	'local-session',
	'utils',
	'notify',
	'jquery.fancybox'
], function ($, roomInfo, localSession, Utils, Notify) {
"use strict";

/**
 * チャットログに関する処理
 * @type {Object}
 */
return {
	/**
	 * チャットログを保持する
	 * @type {Array}
	 */
	_history: [],

	/**
	 * チャットログを表示する要素
	 * @type {HTMLElement}
	 */
	_$log: $('.chat_log'),

	/**
	 * URL
	 * @type {RegExp}
	 */
	_URLRegex: /(?:^|[\s　]+)((?:https?|ftp):\/\/[^\s　]+)/g,

	/**
	 * チャットログのHTMLテンプレート
	 * @type {String}
	 */
	_logText: '
%s
',

	/**
	 * 初期化
	 * @param  {Connection} connection
	 */
	init: function (connection) {
		var _self = this;

		// テキストボックスでエンターキーが押されたら送信
		$('.js_chat_send').keydown(function (e) {
			var eCode = e.keyCode || e.charCode,
				message = $(this).val();

			if (eCode !== 13 || !message) return;
			_self.send(message);
			$(this).val('');
		});

		/**
		 * 発言する
		 * @param  {String} message
		 * @param  {String} [type]
		 */
		this.send = function (message, type) {
			var data = [{
				viewer_id: localSession.get(roomInfo.room.id),
				image: roomInfo.viewer.image,
				message: encodeURIComponent(message),
				type: type || false
			}];
			this.update(data, true);

			connection.sendRTC({
				updated: true,
				chat_log: data
			});
		}
	},

	/**
	 * 受信データをチャットログに反映する
	 * @param  {Object} logs      受信したログのリスト
	 * @param  {Boolean} selfEnter 自身の発言による挿入か
	 */
	update: function (logs, selfEnter) {
		var html = '',
			currentHtml = $.trim(this._$log.html());

		for (var i in logs) {
			var data = logs[i];

			// TODO: ついさっきスクリプトから挿入した自分の発言が、サーバーからも送られて来るので無視している。もっと構造を整える。
			if (!selfEnter && currentHtml !== '' && localSession.get(roomInfo.room.id) === data.viewer_id) continue;

			this._history.push($.extend(true, {}, data));

			var logData = this._createHTMLAndNotifyMessage(data);
			html = logData.HTML + html;

			// 自分の更新でなく、今この画面を見ていなければデスクトップ通知を出す
			if (localSession.get(roomInfo.room.id) !== data.viewer_id) {
				Utils.executeIfNotViewing(function () {
					var myNotification = new Notify('Ko-cha', {
						icon: this.getIconUrl(data.image),
						body: logData.notificationMessage
					});
					myNotification.show();
				}.bind(this));
			}
		}

		this._$log.prepend(html).scrollTop(0);
		$('.fancybox').fancybox({
			autoSize: true
		});
	},

	/**
	 * チャットログと通知用メッセージ生成
	 * @param  {[type]} log
	 */
	_createHTMLAndNotifyMessage: function (log) {
		var logHTML = "", notificationMessage = "";

		switch (log.type) {
		case 'image':
			notificationMessage = '画像を送信しました。';
			logHTML = this._buildImageHTML(log);
			break;

		case 'file':
			notificationMessage = 'ファイルを送信しました。';
			logHTML = this._buildFileHTML(log);
			break;

		default:
			notificationMessage = log.message;
			logHTML = this._buildRemarkHTML(log);
			break;
		}

		return {
			HTML: logHTML,
			notificationMessage: notificationMessage
		}
	},

	/**
	 * 発言ログHTML生成
	 * @param  {Object} log
	 * @return {String} ログHTML
	 */
	_buildRemarkHTML: function (log) {
		var message = Utils.escapeHTML(decodeURIComponent(log.message));

		// URLをリンク化
		message = message.replace(this._URLRegex, function ($1, url) {
			return Utils.sprintf('%s', url, url);
		}.bind(this));

		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), message);
	},

	/**
	 * 画像ログHTML生成
	 * @param  {Object} log
	 * @return {String} 画像ログHTML
	 */
	_buildImageHTML: function (log) {
		var imageName = decodeURIComponent(log.message);
		var baseUrl = 'assets/upload/' + roomInfo.room.id + '/';
		var imageUrl = baseUrl + imageName;

		var thumbExt = imageName.substr(imageName.lastIndexOf('.') + 1).toLowerCase();
		var thumbUrl = baseUrl + 'thumb-' + imageName.substr(0, imageName.length-3) + thumbExt;

		var image = Utils.sprintf('画像を送信しました。', imageUrl, thumbUrl);
		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), image);
	},

	/**
	 * ファイル送信ログのHTML生成
	 * @param  {[type]} log [description]
	 * @return {[type]}     [description]
	 */
	_buildFileHTML: function (log) {
		var fileName = decodeURIComponent(log.message);
		var baseUrl = 'assets/upload/' + roomInfo.room.id + '/';
		var fileUrl = baseUrl + fileName;

		var thumbExt = fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase();
		var thumbUrl = baseUrl + 'thumb-' + fileName.substr(0, fileName.lastIndexOf('.') + 1) + thumbExt;

		var file = Utils.sprintf('ファイルを送信しました。
【 %s 】
', fileUrl, fileName);
		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), file);
	},

	/**
	 * ユーザーアイコンのURL生成
	 * @param  {String} fileName
	 * @return {String} HTML
	 */
	getIconUrl: function (fileName) {
		fileName = "" + fileName;
		return fileName.length < 10 ? 'assets/img/user/default/' + fileName + '.png' : fileName;
	},

	/**
	 * チャット履歴を取得
	 * @return {Object} チャット履歴
	 */
	getHistory: function () {
		return this._history;
	}
}

});
<commit_msg>chat.js余分なコード削除<commit_after>define([
	'jquery',
	'room-info',
	'local-session',
	'utils',
	'notify',
	'jquery.fancybox'
], function ($, roomInfo, localSession, Utils, Notify) {
"use strict";

/**
 * チャットログに関する処理
 * @type {Object}
 */
return {
	/**
	 * チャットログを保持する
	 * @type {Array}
	 */
	_history: [],

	/**
	 * チャットログを表示する要素
	 * @type {HTMLElement}
	 */
	_$log: $('.chat_log'),

	/**
	 * URL
	 * @type {RegExp}
	 */
	_URLRegex: /(?:^|[\s　]+)((?:https?|ftp):\/\/[^\s　]+)/g,

	/**
	 * チャットログのHTMLテンプレート
	 * @type {String}
	 */
	_logText: '
%s
',

	/**
	 * 初期化
	 * @param  {Connection} connection
	 */
	init: function (connection) {
		var _self = this;

		// テキストボックスでエンターキーが押されたら送信
		$('.js_chat_send').keydown(function (e) {
			var eCode = e.keyCode || e.charCode,
				message = $(this).val();

			if (eCode !== 13 || !message) return;
			_self.send(message);
			$(this).val('');
		});

		/**
		 * 発言する
		 * @param  {String} message
		 * @param  {String} [type]
		 */
		this.send = function (message, type) {
			var data = [{
				viewer_id: localSession.get(roomInfo.room.id),
				image: roomInfo.viewer.image,
				message: encodeURIComponent(message),
				type: type || false
			}];
			this.update(data, true);

			connection.sendRTC({
				updated: true,
				chat_log: data
			});
		}
	},

	/**
	 * 受信データをチャットログに反映する
	 * @param  {Object} logs      受信したログのリスト
	 * @param  {Boolean} selfEnter 自身の発言による挿入か
	 */
	update: function (logs, selfEnter) {
		var html = '',
			currentHtml = $.trim(this._$log.html());

		for (var i in logs) {
			var data = logs[i];

			// TODO: ついさっきスクリプトから挿入した自分の発言が、サーバーからも送られて来るので無視している。もっと構造を整える。
			if (!selfEnter && currentHtml !== '' && localSession.get(roomInfo.room.id) === data.viewer_id) continue;

			this._history.push($.extend(true, {}, data));

			var logData = this._createHTMLAndNotifyMessage(data);
			html = logData.HTML + html;

			// 自分の更新でなく、今この画面を見ていなければデスクトップ通知を出す
			if (localSession.get(roomInfo.room.id) !== data.viewer_id) {
				Utils.executeIfNotViewing(function () {
					var myNotification = new Notify('Ko-cha', {
						icon: this.getIconUrl(data.image),
						body: logData.notificationMessage
					});
					myNotification.show();
				}.bind(this));
			}
		}

		this._$log.prepend(html).scrollTop(0);
		$('.fancybox').fancybox({
			autoSize: true
		});
	},

	/**
	 * チャットログと通知用メッセージ生成
	 * @param  {[type]} log
	 */
	_createHTMLAndNotifyMessage: function (log) {
		var logHTML = "", notificationMessage = "";

		switch (log.type) {
		case 'image':
			notificationMessage = '画像を送信しました。';
			logHTML = this._buildImageHTML(log);
			break;

		case 'file':
			notificationMessage = 'ファイルを送信しました。';
			logHTML = this._buildFileHTML(log);
			break;

		default:
			notificationMessage = log.message;
			logHTML = this._buildRemarkHTML(log);
			break;
		}

		return {
			HTML: logHTML,
			notificationMessage: notificationMessage
		}
	},

	/**
	 * 発言ログHTML生成
	 * @param  {Object} log
	 * @return {String} ログHTML
	 */
	_buildRemarkHTML: function (log) {
		var message = Utils.escapeHTML(decodeURIComponent(log.message));

		// URLをリンク化
		message = message.replace(this._URLRegex, function ($1, url) {
			return Utils.sprintf('%s', url, url);
		}.bind(this));

		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), message);
	},

	/**
	 * 画像ログHTML生成
	 * @param  {Object} log
	 * @return {String} 画像ログHTML
	 */
	_buildImageHTML: function (log) {
		var imageName = decodeURIComponent(log.message);
		var baseUrl = 'assets/upload/' + roomInfo.room.id + '/';
		var imageUrl = baseUrl + imageName;

		var thumbExt = imageName.substr(imageName.lastIndexOf('.') + 1).toLowerCase();
		var thumbUrl = baseUrl + 'thumb-' + imageName.substr(0, imageName.length-3) + thumbExt;

		var image = Utils.sprintf('画像を送信しました。', imageUrl, thumbUrl);
		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), image);
	},

	/**
	 * ファイル送信ログのHTML生成
	 * @param  {[type]} log [description]
	 * @return {[type]}     [description]
	 */
	_buildFileHTML: function (log) {
		var fileName = decodeURIComponent(log.message);
		var baseUrl = 'assets/upload/' + roomInfo.room.id + '/';

		var file = Utils.sprintf('ファイルを送信しました。
【 %s 】
', baseUrl + fileName, fileName);
		return Utils.sprintf(this._logText, log.viewer_id, this.getIconUrl(log.image), file);
	},

	/**
	 * ユーザーアイコンのURL生成
	 * @param  {String} fileName
	 * @return {String} HTML
	 */
	getIconUrl: function (fileName) {
		fileName = "" + fileName;
		return fileName.length < 10 ? 'assets/img/user/default/' + fileName + '.png' : fileName;
	},

	/**
	 * チャット履歴を取得
	 * @return {Object} チャット履歴
	 */
	getHistory: function () {
		return this._history;
	}
}

});
<|endoftext|>