<commit_before>/**
 * react-lazyload
 */
import React, {Component, PropTypes} from 'react';
import ReactDom from 'react-dom';
import {on, off} from './utils/event';
import scrollParent from './utils/scrollParent';
import debounce from './utils/debounce';

const listeners = [];
let pending = [];

/**
 * Check if `component` is visible in overflow container `parent`
 * @param  {node} component React component
 * @param  {node} parent    component's scroll parent
 * @return {bool}
 */
const checkOverflowVisible = function(component, parent) {
  const node = ReactDom.findDOMNode(component);

  const scrollTop = parent.scrollTop;
  const { height: elementHeight } = node.getBoundingClientRect();

  let offsets = Array.isArray(component.props.offset) ?
                component.props.offset :
                [component.props.offset, component.props.offset]; // Be compatible with previous API
  const elementTop = node.offsetTop;

  return (elementTop < (scrollTop + offsets[0])) &&
         ((elementTop + elementHeight + offsets[1]) > scrollTop);
}

/**
 * Check if `component` is visible in document
 * @param  {node} component React component
 * @return {bool}
 */
const checkNormalVisible = function(component) {
  const node = ReactDom.findDOMNode(component);

  const { top, bottom } = node.getBoundingClientRect();

  const supportPageOffset = window.pageXOffset !== undefined;
  const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');

  const scrollTop = supportPageOffset ? window.pageYOffset :
                                        isCSS1Compat ?
                                        document.documentElement.scrollTop :
                                        document.body.scrollTop;

  const elementTop = top + scrollTop;
  const elementHeight = bottom - top;
  const windowInnerHeight = window.innerHeight || document.documentElement.clientHeight;

  let offsets = Array.isArray(component.props.offset) ?
                component.props.offset :
                [component.props.offset, component.props.offset]; // Be compatible with previous API

  return (elementTop < (scrollTop + windowInnerHeight + offsets[0])) &&
         ((elementTop + elementHeight + offsets[1]) > scrollTop);
}

/**
 * Detect if element is visible in viewport, if so, set `visible` state to true.
 * If `once` prop is provided true, remove component as listener after checkVisible
 *
 * @param  {React} component   React component that respond to scroll and resize
 */
const checkVisible = function(component) {
  const node = ReactDom.findDOMNode(component);
  const parent = scrollParent(node);
  const isOverflow = parent !== (node.ownerDocument || document);

  const visible = isOverflow ? checkOverflowVisible(component, parent) : checkNormalVisible(component);

  if (visible) {
    // Avoid extra render if previously is visible, yeah I mean `render` call,
    // not actual DOM render
    if (!component.state.visible) {
      component._firstTimeVisible = component._firstTimeVisible === undefined;
      component.setState({
        visible: true
      });
    }

    if (component.props.once) {
      pending.push(component);
    }
  }
  else if (component.state.visible) {
    if (component._firstTimeVisible !== undefined) {
      component._firstTimeVisible = false;
    }

    component.setState({
      visible: false
    });
  }
};

const purgePending = function() {
  pending.forEach(component => {
    const index = listeners.indexOf(component);
    if (index !== -1) {
      listeners.splice(index, 1);
    }
  });

  pending = [];
};

const lazyLoadHandler = debounce(() => {
  for(let i = 0; i < listeners.length; ++i) {
    const listener = listeners[i];
    checkVisible(listener);
  }

  // Remove `once` component in listeners
  purgePending();
}, 300);

class LazyLoad extends Component {
  constructor(props) {
    super(props);

    if (props.scroll === true && props.wheel === true) {
      console && console.warn('[react-lazyload] Don\'t use both `scroll` and `wheel` event in LazyLoad component, pick one!');
    }

    this.state = {
      visible: false
    };
  }

  componentDidMount() {
    if (listeners.length === 0) {
      if (this.props.scroll) {
        on(window, 'scroll', lazyLoadHandler);
      }

      if (this.props.wheel) {
        if (window.hasOwnProperty('onwheel')) {
          on(window, 'wheel', lazyLoadHandler);
        }
        else {
          on(window, 'mousewheel', lazyLoadHandler);
        }
      }

      if (this.props.resize) {
        on(window, 'resize', lazyLoadHandler);
      }
    }

    listeners.push(this);
    checkVisible(this);
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.visible;
  }

  componentWillUpdate(nextProps, nextState) {
    if (this.state.visible && nextState.visible && this._firstTimeVisible) {
      this._firstTimeVisible = false;
    }
  }

  componentWillUnmount() {
    const index = listeners.indexOf(this);
    if (index !== -1) {
      listeners.splice(index, 1);
    }

    if (listeners.length === 0) {
      off(window, 'wheel', lazyLoadHandler);
      off(window, 'mousewheel', lazyLoadHandler);
      off(window, 'resize', lazyLoadHandler);
      off(window, 'scroll', lazyLoadHandler);
    }
  }

  render() {
    return React.cloneElement(this.props.children, {
      visible: this.state.visible,
      firstTimeVisible: this._firstTimeVisible
    });
  }
}

LazyLoad.propTypes = {
  once: PropTypes.bool,
  offset: PropTypes.oneOfType([PropTypes.number, PropTypes.arrayOf(PropTypes.number)]),
  scroll: PropTypes.bool,
  wheel: PropTypes.bool,
  resize: PropTypes.bool,
  children: PropTypes.node
};

LazyLoad.defaultProps = {
  once: false,
  offset: 0,
  scroll: true,
  wheel: false,
  resize: false,
};

export default LazyLoad;
<commit_msg>fix: return null for `once` element when first time render<commit_after>/**
 * react-lazyload
 */
import React, {Component, PropTypes} from 'react';
import ReactDom from 'react-dom';
import {on, off} from './utils/event';
import scrollParent from './utils/scrollParent';
import debounce from './utils/debounce';

const listeners = [];
let pending = [];

/**
 * Check if `component` is visible in overflow container `parent`
 * @param  {node} component React component
 * @param  {node} parent    component's scroll parent
 * @return {bool}
 */
const checkOverflowVisible = function(component, parent) {
  const node = ReactDom.findDOMNode(component);

  const scrollTop = parent.scrollTop;
  const { height: elementHeight } = node.getBoundingClientRect();

  let offsets = Array.isArray(component.props.offset) ?
                component.props.offset :
                [component.props.offset, component.props.offset]; // Be compatible with previous API
  const elementTop = node.offsetTop;

  return (elementTop < (scrollTop + offsets[0])) &&
         ((elementTop + elementHeight + offsets[1]) > scrollTop);
}

/**
 * Check if `component` is visible in document
 * @param  {node} component React component
 * @return {bool}
 */
const checkNormalVisible = function(component) {
  const node = ReactDom.findDOMNode(component);

  const { top, bottom } = node.getBoundingClientRect();

  const supportPageOffset = window.pageXOffset !== undefined;
  const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');

  const scrollTop = supportPageOffset ? window.pageYOffset :
                                        isCSS1Compat ?
                                        document.documentElement.scrollTop :
                                        document.body.scrollTop;

  const elementTop = top + scrollTop;
  const elementHeight = bottom - top;
  const windowInnerHeight = window.innerHeight || document.documentElement.clientHeight;

  let offsets = Array.isArray(component.props.offset) ?
                component.props.offset :
                [component.props.offset, component.props.offset]; // Be compatible with previous API

  return (elementTop < (scrollTop + windowInnerHeight + offsets[0])) &&
         ((elementTop + elementHeight + offsets[1]) > scrollTop);
}

/**
 * Detect if element is visible in viewport, if so, set `visible` state to true.
 * If `once` prop is provided true, remove component as listener after checkVisible
 *
 * @param  {React} component   React component that respond to scroll and resize
 */
const checkVisible = function(component) {
  const node = ReactDom.findDOMNode(component);
  const parent = scrollParent(node);
  const isOverflow = parent !== (node.ownerDocument || document);

  const visible = isOverflow ? checkOverflowVisible(component, parent) : checkNormalVisible(component);

  if (visible) {
    // Avoid extra render if previously is visible, yeah I mean `render` call,
    // not actual DOM render
    if (!component.state.visible) {
      component._firstTimeVisible = component._firstTimeVisible === undefined;
      component.setState({
        visible: true
      });
    }

    if (component.props.once) {
      pending.push(component);
    }
  }
  else if (component.state.visible) {
    if (component._firstTimeVisible !== undefined) {
      component._firstTimeVisible = false;
    }

    component.setState({
      visible: false
    });
  }
};

const purgePending = function() {
  pending.forEach(component => {
    const index = listeners.indexOf(component);
    if (index !== -1) {
      listeners.splice(index, 1);
    }
  });

  pending = [];
};

const lazyLoadHandler = debounce(() => {
  for(let i = 0; i < listeners.length; ++i) {
    const listener = listeners[i];
    checkVisible(listener);
  }

  // Remove `once` component in listeners
  purgePending();
}, 300);

class LazyLoad extends Component {
  constructor(props) {
    super(props);

    if (props.scroll === true && props.wheel === true) {
      console && console.warn('[react-lazyload] Don\'t use both `scroll` and `wheel` event in LazyLoad component, pick one!');
    }

    this.state = {
      visible: false
    };
  }

  componentDidMount() {
    if (listeners.length === 0) {
      if (this.props.scroll) {
        on(window, 'scroll', lazyLoadHandler);
      }

      if (this.props.wheel) {
        if (window.hasOwnProperty('onwheel')) {
          on(window, 'wheel', lazyLoadHandler);
        }
        else {
          on(window, 'mousewheel', lazyLoadHandler);
        }
      }

      if (this.props.resize) {
        on(window, 'resize', lazyLoadHandler);
      }
    }

    listeners.push(this);
    checkVisible(this);
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.visible;
  }

  componentWillUpdate(nextProps, nextState) {
    if (this.state.visible && nextState.visible && this._firstTimeVisible) {
      this._firstTimeVisible = false;
    }
  }

  componentWillUnmount() {
    const index = listeners.indexOf(this);
    if (index !== -1) {
      listeners.splice(index, 1);
    }

    if (listeners.length === 0) {
      off(window, 'wheel', lazyLoadHandler);
      off(window, 'mousewheel', lazyLoadHandler);
      off(window, 'resize', lazyLoadHandler);
      off(window, 'scroll', lazyLoadHandler);
    }
  }

  render() {
    /**
     * For components like images, they shouldn't be rendered until it appears
     * in the viewport.
     */
    if (this.props.once && !this.state.visible) {
      return null;
    }

    return React.cloneElement(this.props.children, {
      visible: this.state.visible,
      firstTimeVisible: this._firstTimeVisible
    });
  }
}

LazyLoad.propTypes = {
  once: PropTypes.bool,
  offset: PropTypes.oneOfType([PropTypes.number, PropTypes.arrayOf(PropTypes.number)]),
  scroll: PropTypes.bool,
  wheel: PropTypes.bool,
  resize: PropTypes.bool,
  children: PropTypes.node
};

LazyLoad.defaultProps = {
  once: false,
  offset: 0,
  scroll: true,
  wheel: false,
  resize: false,
};

export default LazyLoad;
<|endoftext|>


<commit_before>/**
 * class.js
 *
 * Defines the base class system used by Composer (can be standlone as well)
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	/**
	 * like typeof, but returns if it's an array or null
	 */
	var typeOf = function(obj)
	{
		if(obj == null) return 'null';
		var type = typeof(obj);
		if(type != 'object') return type;
		if(Array.isArray && Array.isArray(obj)) return 'array';
		else if(Object.prototype.toString.call(obj) === '[object Array]') return 'array';
		return type;
	};

	/**
	 * Merge object `from` into `into`
	 */
	var merge = function(into, from, options)
	{
		options || (options = {});
		for(var k in from)
		{
			if(!from.hasOwnProperty(k)) continue;
			if(options.transform) options.transform(into, from, k);
			into[k] = from[k];
		}
		return into;
	};

	/**
	 * Wraps an overriding method to track its state so get_parent() can pull
	 * out the right function.
	 */
	var extend_parent = function(to, from, k)
	{
		var extended = function()
		{
			if(!this.$state.parents[k]) this.$state.parents[k] = [];
			this.$state.parents[k].push(from);
			this.$state.fn.push(k);
			var val = to.apply(this, arguments);
			this.$state.fn.pop();
			this.$state.parents[k].pop();
			return val;
		};
		extended.$parent = from;
		return extended;
	};

	/**
	 * Takes care of "parentizing" overridden methods when merging prototypes
	 */
	var do_extend = function(to_prototype, from_prototype)
	{
		return merge(to_prototype, from_prototype, {
			transform: function(into, from, k) {
				if(typeof into[k] != 'function' || into[k].prototype.$parent || typeof from[k] != 'function' || from[k].prototype.$parent) return false;
				from[k] = extend_parent(from[k], into[k], k);
			}
		});
	};

	/**
	 * Given an object, copy the subobjects/subarrays recursively
	 */
	var copy = function(obj)
	{
		for(var k in obj)
		{
			var val = obj[k];
			switch(typeOf(val))
			{
			case 'object':
				obj[k] = copy(merge({}, val));
				break;
			case 'array':
				obj[k] = val.slice(0);
				break;
			}
		}
		return obj;
	}

	/**
	 * Create a new class prototype from the given base class.
	 */
	var create = function(base)
	{
		base.$initializing = true;
		var prototype = new base();
		delete base.$initializing;

		var cls = function Omni()
		{
			copy(this);
			if(cls.$initializing) return this;
			this.$state = {parents: {}, fn: []};
			if(this.initialize) return this.initialize.apply(this, arguments);
			else return this;
		};
		cls.$constructor = prototype.$constructor = cls;
		cls.prototype = prototype;
		cls.prototype.$parent = base;

		return cls;
	};

	/**
	 * Once base to rule them all (and in the darkness bind them)
	 */
	var Base = function() {};

	/**
	 * Main extension method, creates a new class from the given object
	 */
	Base.extend = function(obj)
	{
		var base = this;
		var cls = create(base);
		do_extend(cls.prototype, obj);
		cls.extend = Base.extend;

		cls.prototype.$get_parent = function()
		{
			var k = this.$state.fn[this.$state.fn.length - 1];
			if(!k) return false;
			var parents = this.$state.parents[k];
			var parent = parents[parents.length - 1];
			return parent || false;
		};
		cls.prototype.parent = function()
		{
			var fn = this.$get_parent();
			if(fn) return fn.apply(this, arguments);
			throw 'Class.js: Bad parent method: '+ this.$state.fn[this.$state.fn.length - 1];
		};

		return cls;
	};

	// wrap base class so we can call it directly or as .extend()
	function Class(obj) { return Base.extend(obj); };
	Class.extend = Class;

	this.Composer.exp0rt({ Class: Class });

}).apply((typeof exports != 'undefined') ? exports : this);

<commit_msg>small tweak to extend parent stuff<commit_after>/**
 * class.js
 *
 * Defines the base class system used by Composer (can be standlone as well)
 * -----------------------------------------------------------------------------
 *
 * Composer.js is an MVC framework for creating and organizing javascript
 * applications. For documentation, please visit:
 *
 *     http://lyonbros.github.com/composer.js/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2011, Lyon Bros Enterprises, LLC. (http://www.lyonbros.com)
 *
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
(function() {
	"use strict";

	/**
	 * like typeof, but returns if it's an array or null
	 */
	var typeOf = function(obj)
	{
		if(obj == null) return 'null';
		var type = typeof(obj);
		if(type != 'object') return type;
		if(Array.isArray && Array.isArray(obj)) return 'array';
		else if(Object.prototype.toString.call(obj) === '[object Array]') return 'array';
		return type;
	};

	/**
	 * Merge object `from` into `into`
	 */
	var merge = function(into, from, options)
	{
		options || (options = {});
		for(var k in from)
		{
			if(!from.hasOwnProperty(k)) continue;
			if(options.transform) options.transform(into, from, k);
			into[k] = from[k];
		}
		return into;
	};

	/**
	 * Wraps an overriding method to track its state so get_parent() can pull
	 * out the right function.
	 */
	var extend_parent = function(to, from, k)
	{
		return function()
		{
			if(!this.$state.parents[k]) this.$state.parents[k] = [];
			this.$state.parents[k].push(from);
			this.$state.fn.push(k);
			var val = to.apply(this, arguments);
			this.$state.fn.pop();
			this.$state.parents[k].pop();
			return val;
		};
	};

	/**
	 * Takes care of "parentizing" overridden methods when merging prototypes
	 */
	var do_extend = function(to_prototype, from_prototype)
	{
		return merge(to_prototype, from_prototype, {
			transform: function(into, from, k) {
				if(typeof into[k] != 'function' || into[k].prototype.$parent || typeof from[k] != 'function' || from[k].prototype.$parent) return false;
				from[k] = extend_parent(from[k], into[k], k);
				from[k].$parent = into[k];
			}
		});
	};

	/**
	 * Given an object, copy the subobjects/subarrays recursively
	 */
	var copy = function(obj)
	{
		for(var k in obj)
		{
			var val = obj[k];
			switch(typeOf(val))
			{
			case 'object':
				obj[k] = copy(merge({}, val));
				break;
			case 'array':
				obj[k] = val.slice(0);
				break;
			}
		}
		return obj;
	}

	/**
	 * Create a new class prototype from the given base class.
	 */
	var create = function(base)
	{
		base.$initializing = true;
		var prototype = new base();
		delete base.$initializing;

		var cls = function Omni()
		{
			copy(this);
			if(cls.$initializing) return this;
			this.$state = {parents: {}, fn: []};
			if(this.initialize) return this.initialize.apply(this, arguments);
			else return this;
		};
		cls.$constructor = prototype.$constructor = cls;
		cls.prototype = prototype;
		cls.prototype.$parent = base;

		return cls;
	};

	/**
	 * Once base to rule them all (and in the darkness bind them)
	 */
	var Base = function() {};

	/**
	 * Main extension method, creates a new class from the given object
	 */
	Base.extend = function(obj)
	{
		var base = this;
		var cls = create(base);
		do_extend(cls.prototype, obj);
		cls.extend = Base.extend;

		cls.prototype.$get_parent = function()
		{
			var k = this.$state.fn[this.$state.fn.length - 1];
			if(!k) return false;
			var parents = this.$state.parents[k];
			var parent = parents[parents.length - 1];
			return parent || false;
		};
		cls.prototype.parent = function()
		{
			var fn = this.$get_parent();
			if(fn) return fn.apply(this, arguments);
			throw 'Class.js: Bad parent method: '+ this.$state.fn[this.$state.fn.length - 1];
		};

		return cls;
	};

	// wrap base class so we can call it directly or as .extend()
	function Class(obj) { return Base.extend(obj); };
	Class.extend = Class;

	this.Composer.exp0rt({ Class: Class });

}).apply((typeof exports != 'undefined') ? exports : this);

<|endoftext|>


<commit_before>const { h } = require('preact')
const Plugin = require('../../core/Plugin')
const Translator = require('../../core/Translator')
const {
  getFileTypeExtension,
  canvasToBlob
} = require('../../core/Utils')
const supportsMediaRecorder = require('./supportsMediaRecorder')
const CameraIcon = require('./CameraIcon')
const CameraScreen = require('./CameraScreen')
const PermissionsScreen = require('./PermissionsScreen')

// Setup getUserMedia, with polyfill for older browsers
// Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
function getMediaDevices () {
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    return navigator.mediaDevices
  }

  const getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia
  if (!getUserMedia) {
    return null
  }

  return {
    getUserMedia (opts) {
      return new Promise((resolve, reject) => {
        getUserMedia.call(navigator, opts, resolve, reject)
      })
    }
  }
}

/**
 * Webcam
 */
module.exports = class Webcam extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.mediaDevices = getMediaDevices()
    this.supportsUserMedia = !!this.mediaDevices
    this.protocol = location.protocol.match(/https/i) ? 'https' : 'http'
    this.id = this.opts.id || 'Webcam'
    this.title = 'Camera'
    this.type = 'acquirer'
    this.icon = CameraIcon

    const defaultLocale = {
      strings: {
        smile: 'Smile!',
        takePicture: 'Take a picture',
        startRecording: 'Begin video recording',
        stopRecording: 'Stop video recording'
      }
    }

    // set default options
    const defaultOptions = {
      onBeforeSnapshot: () => Promise.resolve(),
      countdown: false,
      locale: defaultLocale,
      modes: [
        'video-audio',
        'video-only',
        'audio-only',
        'picture'
      ],
      mirror: true,
      facingMode: 'user'
    }

    // merge default options with the ones set by user
    this.opts = Object.assign({}, defaultOptions, opts)

    this.locale = Object.assign({}, defaultLocale, this.opts.locale)
    this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)

    // i18n
    this.translator = new Translator({locale: this.locale})
    this.i18n = this.translator.translate.bind(this.translator)

    this.install = this.install.bind(this)
    this.setPluginState = this.setPluginState.bind(this)

    this.render = this.render.bind(this)

    // Camera controls
    this.start = this.start.bind(this)
    this.stop = this.stop.bind(this)
    this.takeSnapshot = this.takeSnapshot.bind(this)
    this.startRecording = this.startRecording.bind(this)
    this.stopRecording = this.stopRecording.bind(this)
    this.oneTwoThreeSmile = this.oneTwoThreeSmile.bind(this)
    this.focus = this.focus.bind(this)

    this.webcamActive = false

    if (this.opts.countdown) {
      this.opts.onBeforeSnapshot = this.oneTwoThreeSmile
    }
  }

  isSupported () {
    return !!this.mediaDevices
  }

  getConstraints () {
    const acceptsAudio = this.opts.modes.indexOf('video-audio') !== -1 ||
      this.opts.modes.indexOf('audio-only') !== -1
    const acceptsVideo = this.opts.modes.indexOf('video-audio') !== -1 ||
      this.opts.modes.indexOf('video-only') !== -1 ||
      this.opts.modes.indexOf('picture') !== -1

    return {
      audio: acceptsAudio,
      video: acceptsVideo ? { facingMode: this.opts.facingMode } : false
    }
  }

  start () {
    if (!this.isSupported()) {
      return Promise.reject(new Error('Webcam access not supported'))
    }

    this.webcamActive = true

    const constraints = this.getConstraints()

    // ask user for access to their camera
    return this.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        this.stream = stream
        // this.streamSrc = URL.createObjectURL(this.stream)
        this.setPluginState({
          cameraReady: true
        })
      })
      .catch((err) => {
        this.setPluginState({
          cameraError: err
        })
      })
  }

  startRecording () {
    // TODO We can check here if any of the mime types listed in the
    // mimeToExtensions map in Utils.js are supported, and prefer to use one of
    // those.
    // Right now we let the browser pick a type that it deems appropriate.
    this.recorder = new MediaRecorder(this.stream)
    this.recordingChunks = []
    this.recorder.addEventListener('dataavailable', (event) => {
      this.recordingChunks.push(event.data)
    })
    this.recorder.start()

    this.setPluginState({
      isRecording: true
    })
  }

  stopRecording () {
    const stopped = new Promise((resolve, reject) => {
      this.recorder.addEventListener('stop', () => {
        resolve()
      })
      this.recorder.stop()
    })

    return stopped.then(() => {
      this.setPluginState({
        isRecording: false
      })
      return this.getVideo()
    })
    .then((file) => this.uppy.addFile(file))
    .then(() => {
      this.recordingChunks = null
      this.recorder = null
      const dashboard = this.uppy.getPlugin('Dashboard')
      if (dashboard) dashboard.hideAllPanels()
    }, (error) => {
      this.recordingChunks = null
      this.recorder = null
      throw error
    })
  }

  stop () {
    this.stream.getAudioTracks().forEach((track) => {
      track.stop()
    })
    this.stream.getVideoTracks().forEach((track) => {
      track.stop()
    })
    this.webcamActive = false
    this.stream = null
  }

  getVideoElement () {
    return this.el.querySelector('.uppy-Webcam-video')
  }

  oneTwoThreeSmile () {
    return new Promise((resolve, reject) => {
      let count = this.opts.countdown

      let countDown = setInterval(() => {
        if (!this.webcamActive) {
          clearInterval(countDown)
          this.captureInProgress = false
          return reject(new Error('Webcam is not active'))
        }

        if (count > 0) {
          this.uppy.info(`${count}...`, 'warning', 800)
          count--
        } else {
          clearInterval(countDown)
          this.uppy.info(this.i18n('smile'), 'success', 1500)
          setTimeout(() => resolve(), 1500)
        }
      }, 1000)
    })
  }

  takeSnapshot () {
    if (this.captureInProgress) return
    this.captureInProgress = true

    this.opts.onBeforeSnapshot().catch((err) => {
      const message = typeof err === 'object' ? err.message : err
      this.uppy.info(message, 'error', 5000)
      return Promise.reject(new Error(`onBeforeSnapshot: ${message}`))
    }).then(() => {
      return this.getImage()
    }).then((tagFile) => {
      this.captureInProgress = false
      const dashboard = this.uppy.getPlugin('Dashboard')
      if (dashboard) dashboard.hideAllPanels()
      return this.uppy.addFile(tagFile).catch(() => {
        // Ignore
      })
    }, (error) => {
      this.captureInProgress = false
      throw error
    })
  }

  getImage () {
    const video = this.getVideoElement()
    if (!video) {
      return Promise.reject(new Error('No video element found, likely due to the Webcam tab being closed.'))
    }

    const name = `webcam-${Date.now()}.jpg`
    const mimeType = 'image/jpeg'

    const width = video.videoWidth
    const height = video.videoHeight

    // const scaleH = this.opts.mirror ? -1 : 1 // Set horizontal scale to -1 if flip horizontal
    // const scaleV = 1
    // const posX = this.opts.mirror ? width * -1 : 0 // Set x position to -100% if flip horizontal
    // const posY = 0

    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height
    const ctx = canvas.getContext('2d')
    ctx.drawImage(video, 0, 0)
    // ctx.save() // Save the current state
    // ctx.scale(scaleH, scaleV) // Set scale to flip the image
    // ctx.drawImage(video, posX, posY, width, height) // draw the image
    // ctx.restore() // Restore the last saved state

    return canvasToBlob(canvas, mimeType).then((blob) => {
      return {
        source: this.id,
        name: name,
        data: new File([blob], name, { type: mimeType }),
        type: mimeType
      }
    })
  }

  getVideo () {
    const mimeType = this.recordingChunks[0].type
    const fileExtension = getFileTypeExtension(mimeType)

    if (!fileExtension) {
      return Promise.reject(new Error(`Could not retrieve recording: Unsupported media type "${mimeType}"`))
    }

    const name = `webcam-${Date.now()}.${fileExtension}`
    const blob = new Blob(this.recordingChunks, { type: mimeType })
    const file = {
      source: this.id,
      name: name,
      data: new File([blob], name, { type: mimeType }),
      type: mimeType
    }

    return Promise.resolve(file)
  }

  focus () {
    if (this.opts.countdown) return
    setTimeout(() => {
      this.uppy.info(this.i18n('smile'), 'success', 1500)
    }, 1000)
  }

  render (state) {
    if (!this.webcamActive) {
      this.start()
    }

    const webcamState = this.getPluginState()

    if (!webcamState.cameraReady) {
      return <PermissionsScreen icon={CameraIcon} />
    }

    return <CameraScreen
      {...webcamState}
      onSnapshot={this.takeSnapshot}
      onStartRecording={this.startRecording}
      onStopRecording={this.stopRecording}
      onFocus={this.focus}
      onStop={this.stop}
      i18n={this.i18n}
      modes={this.opts.modes}
      supportsRecording={supportsMediaRecorder()}
      recording={webcamState.isRecording}
      mirror={this.opts.mirror}
      src={this.stream} />
  }

  install () {
    this.setPluginState({
      cameraReady: false
    })

    const target = this.opts.target
    if (target) {
      this.mount(target, this)
    }
  }

  uninstall () {
    if (this.stream) {
      this.stop()
    }

    this.unmount()
  }
}
<commit_msg>remove catch(), because addFile is sync now<commit_after>const { h } = require('preact')
const Plugin = require('../../core/Plugin')
const Translator = require('../../core/Translator')
const {
  getFileTypeExtension,
  canvasToBlob
} = require('../../core/Utils')
const supportsMediaRecorder = require('./supportsMediaRecorder')
const CameraIcon = require('./CameraIcon')
const CameraScreen = require('./CameraScreen')
const PermissionsScreen = require('./PermissionsScreen')

// Setup getUserMedia, with polyfill for older browsers
// Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
function getMediaDevices () {
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    return navigator.mediaDevices
  }

  const getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia
  if (!getUserMedia) {
    return null
  }

  return {
    getUserMedia (opts) {
      return new Promise((resolve, reject) => {
        getUserMedia.call(navigator, opts, resolve, reject)
      })
    }
  }
}

/**
 * Webcam
 */
module.exports = class Webcam extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.mediaDevices = getMediaDevices()
    this.supportsUserMedia = !!this.mediaDevices
    this.protocol = location.protocol.match(/https/i) ? 'https' : 'http'
    this.id = this.opts.id || 'Webcam'
    this.title = 'Camera'
    this.type = 'acquirer'
    this.icon = CameraIcon

    const defaultLocale = {
      strings: {
        smile: 'Smile!',
        takePicture: 'Take a picture',
        startRecording: 'Begin video recording',
        stopRecording: 'Stop video recording'
      }
    }

    // set default options
    const defaultOptions = {
      onBeforeSnapshot: () => Promise.resolve(),
      countdown: false,
      locale: defaultLocale,
      modes: [
        'video-audio',
        'video-only',
        'audio-only',
        'picture'
      ],
      mirror: true,
      facingMode: 'user'
    }

    // merge default options with the ones set by user
    this.opts = Object.assign({}, defaultOptions, opts)

    this.locale = Object.assign({}, defaultLocale, this.opts.locale)
    this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)

    // i18n
    this.translator = new Translator({locale: this.locale})
    this.i18n = this.translator.translate.bind(this.translator)

    this.install = this.install.bind(this)
    this.setPluginState = this.setPluginState.bind(this)

    this.render = this.render.bind(this)

    // Camera controls
    this.start = this.start.bind(this)
    this.stop = this.stop.bind(this)
    this.takeSnapshot = this.takeSnapshot.bind(this)
    this.startRecording = this.startRecording.bind(this)
    this.stopRecording = this.stopRecording.bind(this)
    this.oneTwoThreeSmile = this.oneTwoThreeSmile.bind(this)
    this.focus = this.focus.bind(this)

    this.webcamActive = false

    if (this.opts.countdown) {
      this.opts.onBeforeSnapshot = this.oneTwoThreeSmile
    }
  }

  isSupported () {
    return !!this.mediaDevices
  }

  getConstraints () {
    const acceptsAudio = this.opts.modes.indexOf('video-audio') !== -1 ||
      this.opts.modes.indexOf('audio-only') !== -1
    const acceptsVideo = this.opts.modes.indexOf('video-audio') !== -1 ||
      this.opts.modes.indexOf('video-only') !== -1 ||
      this.opts.modes.indexOf('picture') !== -1

    return {
      audio: acceptsAudio,
      video: acceptsVideo ? { facingMode: this.opts.facingMode } : false
    }
  }

  start () {
    if (!this.isSupported()) {
      return Promise.reject(new Error('Webcam access not supported'))
    }

    this.webcamActive = true

    const constraints = this.getConstraints()

    // ask user for access to their camera
    return this.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        this.stream = stream
        // this.streamSrc = URL.createObjectURL(this.stream)
        this.setPluginState({
          cameraReady: true
        })
      })
      .catch((err) => {
        this.setPluginState({
          cameraError: err
        })
      })
  }

  startRecording () {
    // TODO We can check here if any of the mime types listed in the
    // mimeToExtensions map in Utils.js are supported, and prefer to use one of
    // those.
    // Right now we let the browser pick a type that it deems appropriate.
    this.recorder = new MediaRecorder(this.stream)
    this.recordingChunks = []
    this.recorder.addEventListener('dataavailable', (event) => {
      this.recordingChunks.push(event.data)
    })
    this.recorder.start()

    this.setPluginState({
      isRecording: true
    })
  }

  stopRecording () {
    const stopped = new Promise((resolve, reject) => {
      this.recorder.addEventListener('stop', () => {
        resolve()
      })
      this.recorder.stop()
    })

    return stopped.then(() => {
      this.setPluginState({
        isRecording: false
      })
      return this.getVideo()
    })
    .then((file) => this.uppy.addFile(file))
    .then(() => {
      this.recordingChunks = null
      this.recorder = null
      const dashboard = this.uppy.getPlugin('Dashboard')
      if (dashboard) dashboard.hideAllPanels()
    }, (error) => {
      this.recordingChunks = null
      this.recorder = null
      throw error
    })
  }

  stop () {
    this.stream.getAudioTracks().forEach((track) => {
      track.stop()
    })
    this.stream.getVideoTracks().forEach((track) => {
      track.stop()
    })
    this.webcamActive = false
    this.stream = null
  }

  getVideoElement () {
    return this.el.querySelector('.uppy-Webcam-video')
  }

  oneTwoThreeSmile () {
    return new Promise((resolve, reject) => {
      let count = this.opts.countdown

      let countDown = setInterval(() => {
        if (!this.webcamActive) {
          clearInterval(countDown)
          this.captureInProgress = false
          return reject(new Error('Webcam is not active'))
        }

        if (count > 0) {
          this.uppy.info(`${count}...`, 'warning', 800)
          count--
        } else {
          clearInterval(countDown)
          this.uppy.info(this.i18n('smile'), 'success', 1500)
          setTimeout(() => resolve(), 1500)
        }
      }, 1000)
    })
  }

  takeSnapshot () {
    if (this.captureInProgress) return
    this.captureInProgress = true

    this.opts.onBeforeSnapshot().catch((err) => {
      const message = typeof err === 'object' ? err.message : err
      this.uppy.info(message, 'error', 5000)
      return Promise.reject(new Error(`onBeforeSnapshot: ${message}`))
    }).then(() => {
      return this.getImage()
    }).then((tagFile) => {
      this.captureInProgress = false
      const dashboard = this.uppy.getPlugin('Dashboard')
      if (dashboard) dashboard.hideAllPanels()
      return this.uppy.addFile(tagFile)
    }, (error) => {
      this.captureInProgress = false
      throw error
    })
  }

  getImage () {
    const video = this.getVideoElement()
    if (!video) {
      return Promise.reject(new Error('No video element found, likely due to the Webcam tab being closed.'))
    }

    const name = `webcam-${Date.now()}.jpg`
    const mimeType = 'image/jpeg'

    const width = video.videoWidth
    const height = video.videoHeight

    // const scaleH = this.opts.mirror ? -1 : 1 // Set horizontal scale to -1 if flip horizontal
    // const scaleV = 1
    // const posX = this.opts.mirror ? width * -1 : 0 // Set x position to -100% if flip horizontal
    // const posY = 0

    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height
    const ctx = canvas.getContext('2d')
    ctx.drawImage(video, 0, 0)
    // ctx.save() // Save the current state
    // ctx.scale(scaleH, scaleV) // Set scale to flip the image
    // ctx.drawImage(video, posX, posY, width, height) // draw the image
    // ctx.restore() // Restore the last saved state

    return canvasToBlob(canvas, mimeType).then((blob) => {
      return {
        source: this.id,
        name: name,
        data: new File([blob], name, { type: mimeType }),
        type: mimeType
      }
    })
  }

  getVideo () {
    const mimeType = this.recordingChunks[0].type
    const fileExtension = getFileTypeExtension(mimeType)

    if (!fileExtension) {
      return Promise.reject(new Error(`Could not retrieve recording: Unsupported media type "${mimeType}"`))
    }

    const name = `webcam-${Date.now()}.${fileExtension}`
    const blob = new Blob(this.recordingChunks, { type: mimeType })
    const file = {
      source: this.id,
      name: name,
      data: new File([blob], name, { type: mimeType }),
      type: mimeType
    }

    return Promise.resolve(file)
  }

  focus () {
    if (this.opts.countdown) return
    setTimeout(() => {
      this.uppy.info(this.i18n('smile'), 'success', 1500)
    }, 1000)
  }

  render (state) {
    if (!this.webcamActive) {
      this.start()
    }

    const webcamState = this.getPluginState()

    if (!webcamState.cameraReady) {
      return <PermissionsScreen icon={CameraIcon} />
    }

    return <CameraScreen
      {...webcamState}
      onSnapshot={this.takeSnapshot}
      onStartRecording={this.startRecording}
      onStopRecording={this.stopRecording}
      onFocus={this.focus}
      onStop={this.stop}
      i18n={this.i18n}
      modes={this.opts.modes}
      supportsRecording={supportsMediaRecorder()}
      recording={webcamState.isRecording}
      mirror={this.opts.mirror}
      src={this.stream} />
  }

  install () {
    this.setPluginState({
      cameraReady: false
    })

    const target = this.opts.target
    if (target) {
      this.mount(target, this)
    }
  }

  uninstall () {
    if (this.stream) {
      this.stop()
    }

    this.unmount()
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  const OptionsPage = options.OptionsPage;
  const ArrayDataModel = cr.ui.ArrayDataModel;
  const ListSelectionModel = cr.ui.ListSelectionModel;

  //
  // BrowserOptions class
  // Encapsulated handling of browser options page.
  //
  function BrowserOptions() {
    OptionsPage.call(this, 'browser', templateData.browserPage, 'browserPage');
  }

  cr.addSingletonGetter(BrowserOptions);

  BrowserOptions.prototype = {
    // Inherit BrowserOptions from OptionsPage.
    __proto__: options.OptionsPage.prototype,

    homepage_pref_: {
      'name': 'homepage',
      'value': '',
      'managed': false
    },

    homepage_is_newtabpage_pref_: {
      'name': 'homepage_is_newtabpage',
      'value': true,
      'managed': false
    },

    /**
     * Initialize BrowserOptions page.
     */
    initializePage: function() {
      // Call base class implementation to start preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      // Wire up controls.
      $('startupUseCurrentButton').onclick = function(event) {
        chrome.send('setStartupPagesToCurrentPages');
      };
      $('startupPageManagerButton').onclick = function(event) {
        OptionsPage.showPageByName('startupPages');
      };
      $('defaultSearchManageEnginesButton').onclick = function(event) {
        OptionsPage.showPageByName('searchEngines');
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ManageSearchEngines']);
      };
      $('instantEnableCheckbox').onclick = function(event) {
        var alreadyConfirmed = $('instantDialogShown').checked;

        if (this.checked && !alreadyConfirmed) {
          // Leave disabled for now. The PrefCheckbox handler already set it to
          // true so undo that.
          Preferences.setBooleanPref(this.pref, false, this.metric);
          OptionsPage.showOverlay('instantConfirmOverlay');
        }
      };

      var homepageField = $('homepageURL');
      $('homepageUseNTPButton').onchange =
          this.handleHomepageUseNTPButtonChange_.bind(this);
      $('homepageUseURLButton').onchange =
          this.handleHomepageUseURLButtonChange_.bind(this);
      homepageField.onchange =
          this.handleHomepageURLChange_.bind(this);

      // Ensure that changes are committed when closing the page.
      window.addEventListener('unload', function() {
          if (document.activeElement == homepageField)
            homepageField.blur();
          });

      if (!cr.isChromeOS) {
        $('defaultBrowserUseAsDefaultButton').onclick = function(event) {
          chrome.send('becomeDefaultBrowser');
        };
      }

      var list = $('startupPagesShortList');
      options.browser_options.StartupPageList.decorate(list);
      list.autoExpands = true;
      list.selectionModel = new ListSelectionModel;

      // Check if we are in the guest mode.
      if (cr.commandLine.options['--bwsi']) {
        // Disable all controls under the startup section.
        var elements =
            $('startupSection').querySelectorAll('input, button, list');
        for (var i = 0; i < elements.length; i++)
          elements[i].disabled = true;
      } else {
        // Initialize control enabled states.
        Preferences.getInstance().addEventListener('session.restore_on_startup',
            this.updateCustomStartupPageControlStates_.bind(this));
        Preferences.getInstance().addEventListener('homepage_is_newtabpage',
            this.handleHomepageIsNewTabPageChange_.bind(this));
        Preferences.getInstance().addEventListener('homepage',
            this.handleHomepageChange_.bind(this));

        this.updateCustomStartupPageControlStates_();
      }
    },

    /**
     * Update the Default Browsers section based on the current state.
     * @private
     * @param {string} statusString Description of the current default state.
     * @param {boolean} isDefault Whether or not the browser is currently
     *     default.
     * @param {boolean} canBeDefault Whether or not the browser can be default.
     */
    updateDefaultBrowserState_: function(statusString, isDefault,
                                         canBeDefault) {
      var label = $('defaultBrowserState');
      label.textContent = statusString;

      $('defaultBrowserUseAsDefaultButton').disabled = !canBeDefault ||
                                                       isDefault;
    },

    /**
     * Clears the search engine popup.
     * @private
     */
    clearSearchEngines_: function() {
      $('defaultSearchEngine').textContent = '';
    },

    /**
     * Updates the search engine popup with the given entries.
     * @param {Array} engines List of available search engines.
     * @param {Integer} defaultValue The value of the current default engine.
     */
    updateSearchEngines_: function(engines, defaultValue) {
      this.clearSearchEngines_();
      engineSelect = $('defaultSearchEngine');
      engineCount = engines.length;
      var defaultIndex = -1;
      for (var i = 0; i < engineCount; i++) {
        var engine = engines[i];
        var option = new Option(engine['name'], engine['index']);
        if (defaultValue == option.value)
          defaultIndex = i;
        engineSelect.appendChild(option);
      }
      if (defaultIndex >= 0)
        engineSelect.selectedIndex = defaultIndex;
    },

    /**
     * Returns true if the custom startup page control block should
     * be enabled.
     * @private
     * @returns {boolean} Whether the startup page controls should be
     *     enabled.
     */
    shouldEnableCustomStartupPageControls_: function(pages) {
      return $('startupShowPagesButton').checked;
    },

    /**
     * Updates the startup pages list with the given entries.
     * @private
     * @param {Array} pages List of startup pages.
     */
    updateStartupPages_: function(pages) {
      var list = $('startupPagesShortList');
      list.dataModel = new ArrayDataModel(pages);
      if (pages.length > 0 && pages.length <= 10) {
        list.classList.remove("hidden");
        $('startupPageManagement').classList.add('settings-list');
        $('startupShowPagesLabel').textContent =
            localStrings.getStringWithoutAccelerator('startupShowPages');
      } else {
        list.classList.add("hidden");
        $('startupPageManagement').classList.remove('settings-list');
        $('startupShowPagesLabel').textContent =
            localStrings.getStringWithoutAccelerator('startupShowManyPages');
      }
    },

    /**
     * Handles change events of the radio button 'homepageUseURLButton'.
     * @private
     * @param {event} change event.
     */
    handleHomepageUseURLButtonChange_: function(event) {
      Preferences.setBooleanPref('homepage_is_newtabpage', false);
    },

    /**
     * Handles change events of the radio button 'homepageUseNTPButton'.
     * @private
     * @param {event} change event.
     */
    handleHomepageUseNTPButtonChange_: function(event) {
      Preferences.setBooleanPref('homepage_is_newtabpage', true);
    },

    /**
     * Handles change events of the text field 'homepageURL'.
     * @private
     * @param {event} change event.
     */
    handleHomepageURLChange_: function(event) {
      Preferences.setStringPref('homepage', $('homepageURL').value);
    },

    /**
     * Handle change events of the preference 'homepage'.
     * @private
     * @param {event} preference changed event.
     */
    handleHomepageChange_: function(event) {
      this.homepage_pref_.value = event.value['value'];
      this.homepage_pref_.managed = event.value['managed'];
      if (this.isHomepageURLNewTabPageURL_() && !this.homepage_pref_.managed &&
          !this.homepage_is_newtabpage_pref_.managed) {
        var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_();
        Preferences.setStringPref('homepage', '')
        Preferences.setBooleanPref('homepage_is_newtabpage', useNewTabPage)
      }
      this.updateHomepageControlStates_();
    },

    /**
     * Handle change events of the preference homepage_is_newtabpage.
     * @private
     * @param {event} preference changed event.
     */
    handleHomepageIsNewTabPageChange_: function(event) {
      this.homepage_is_newtabpage_pref_.value = event.value['value'];
      this.homepage_is_newtabpage_pref_.managed = event.value['managed'];
      this.updateHomepageControlStates_();
    },

    /**
     * Update homepage preference UI controls.  Here's a table describing the
     * desired characteristics of the homepage choice radio value, its enabled
     * state and the URL field enabled state. They depend on the values of the
     * managed bits for homepage (m_hp) and homepageIsNewTabPage (m_ntp)
     * preferences, as well as the value of the homepageIsNewTabPage preference
     * (ntp) and whether the homepage preference is equal to the new tab page
     * URL (hpisntp).
     *
     * m_hp m_ntp ntp hpisntp| choice value| choice enabled| URL field enabled
     * ------------------------------------------------------------------------
     * 0    0     0   0      | homepage    | 1             | 1
     * 0    0     0   1      | new tab page| 1             | 0
     * 0    0     1   0      | new tab page| 1             | 0
     * 0    0     1   1      | new tab page| 1             | 0
     * 0    1     0   0      | homepage    | 0             | 1
     * 0    1     0   1      | homepage    | 0             | 1
     * 0    1     1   0      | new tab page| 0             | 0
     * 0    1     1   1      | new tab page| 0             | 0
     * 1    0     0   0      | homepage    | 1             | 0
     * 1    0     0   1      | new tab page| 0             | 0
     * 1    0     1   0      | new tab page| 1             | 0
     * 1    0     1   1      | new tab page| 0             | 0
     * 1    1     0   0      | homepage    | 0             | 0
     * 1    1     0   1      | new tab page| 0             | 0
     * 1    1     1   0      | new tab page| 0             | 0
     * 1    1     1   1      | new tab page| 0             | 0
     *
     * thus, we have:
     *
     *    choice value is new tab page === ntp || (hpisntp && (m_hp || !m_ntp))
     *    choice enabled === !m_ntp && !(m_hp && hpisntp)
     *    URL field enabled === !ntp && !mhp && !(hpisntp && !m_ntp)
     *
     * which also make sense if you think about them.
     * @private
     */
    updateHomepageControlStates_: function() {
      var homepageField = $('homepageURL');
      homepageField.disabled = !this.isHomepageURLFieldEnabled_();
      homepageField.value = this.homepage_pref_.value;
      homepageField.style.backgroundImage = url('chrome://favicon/' +
                                                this.homepage_pref_.value);
      var disableChoice = !this.isHomepageChoiceEnabled_();
      $('homepageUseURLButton').disabled = disableChoice;
      $('homepageUseNTPButton').disabled = disableChoice;
      var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_();
      $('homepageUseNTPButton').checked = useNewTabPage;
      $('homepageUseURLButton').checked = !useNewTabPage;
    },

    /**
     * Tests whether the value of the 'homepage' preference equls the new tab
     * page url (chrome://newtab).
     * @private
     * @returns {boolean} True if the 'homepage' value equals the new tab page
     *     url.
     */
    isHomepageURLNewTabPageURL_ : function() {
      return (this.homepage_pref_.value.toLowerCase() == 'chrome://newtab');
    },

    /**
     * Tests whether the Homepage choice "Use New Tab Page" is selected.
     * @private
     * @returns {boolean} True if "Use New Tab Page" is selected.
     */
    isHomepageIsNewTabPageChoiceSelected_: function() {
      return (this.homepage_is_newtabpage_pref_.value ||
              (this.isHomepageURLNewTabPageURL_() &&
               (this.homepage_pref_.managed ||
                !this.homepage_is_newtabpage_pref_.managed)));
    },

    /**
     * Tests whether the home page choice controls are enabled.
     * @private
     * @returns {boolean} True if the home page choice controls are enabled.
     */
    isHomepageChoiceEnabled_: function() {
      return (!this.homepage_is_newtabpage_pref_.managed &&
              !(this.homepage_pref_.managed &&
                this.isHomepageURLNewTabPageURL_()));
    },

    /**
     * Checks whether the home page field should be enabled.
     * @private
     * @returns {boolean} True if the home page field should be enabled.
     */
    isHomepageURLFieldEnabled_: function() {
      return (!this.homepage_is_newtabpage_pref_.value &&
              !this.homepage_pref_.managed &&
              !(this.isHomepageURLNewTabPageURL_() &&
                !this.homepage_is_newtabpage_pref_.managed));
    },

    /**
     * Sets the enabled state of the custom startup page list controls
     * based on the current startup radio button selection.
     * @private
     */
    updateCustomStartupPageControlStates_: function() {
      var disable = !this.shouldEnableCustomStartupPageControls_();
      $('startupPagesShortList').disabled = disable;
      $('startupUseCurrentButton').disabled = disable;
      $('startupPageManagerButton').disabled = disable;
    },

    /**
     * Set the default search engine based on the popup selection.
     */
    setDefaultSearchEngine: function() {
      var engineSelect = $('defaultSearchEngine');
      var selectedIndex = engineSelect.selectedIndex;
      if (selectedIndex >= 0) {
        var selection = engineSelect.options[selectedIndex];
        chrome.send('setDefaultSearchEngine', [String(selection.value)]);
      }
    },
  };

  BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault,
                                                      canBeDefault) {
    if (!cr.isChromeOS) {
      BrowserOptions.getInstance().updateDefaultBrowserState_(statusString,
                                                              isDefault,
                                                              canBeDefault);
    }
  };

  BrowserOptions.updateSearchEngines = function(engines, defaultValue) {
    BrowserOptions.getInstance().updateSearchEngines_(engines, defaultValue);
  };

  BrowserOptions.updateStartupPages = function(pages) {
    BrowserOptions.getInstance().updateStartupPages_(pages);
    StartupPageManager.getInstance().updateStartupPages_(pages);
  };

  // Export
  return {
    BrowserOptions: BrowserOptions
  };

});
<commit_msg>Hide startup page selection section from settings UI for guest users.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {
  const OptionsPage = options.OptionsPage;
  const ArrayDataModel = cr.ui.ArrayDataModel;
  const ListSelectionModel = cr.ui.ListSelectionModel;

  //
  // BrowserOptions class
  // Encapsulated handling of browser options page.
  //
  function BrowserOptions() {
    OptionsPage.call(this, 'browser', templateData.browserPage, 'browserPage');
  }

  cr.addSingletonGetter(BrowserOptions);

  BrowserOptions.prototype = {
    // Inherit BrowserOptions from OptionsPage.
    __proto__: options.OptionsPage.prototype,

    homepage_pref_: {
      'name': 'homepage',
      'value': '',
      'managed': false
    },

    homepage_is_newtabpage_pref_: {
      'name': 'homepage_is_newtabpage',
      'value': true,
      'managed': false
    },

    /**
     * Initialize BrowserOptions page.
     */
    initializePage: function() {
      // Call base class implementation to start preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      // Wire up controls.
      $('startupUseCurrentButton').onclick = function(event) {
        chrome.send('setStartupPagesToCurrentPages');
      };
      $('startupPageManagerButton').onclick = function(event) {
        OptionsPage.showPageByName('startupPages');
      };
      $('defaultSearchManageEnginesButton').onclick = function(event) {
        OptionsPage.showPageByName('searchEngines');
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ManageSearchEngines']);
      };
      $('instantEnableCheckbox').onclick = function(event) {
        var alreadyConfirmed = $('instantDialogShown').checked;

        if (this.checked && !alreadyConfirmed) {
          // Leave disabled for now. The PrefCheckbox handler already set it to
          // true so undo that.
          Preferences.setBooleanPref(this.pref, false, this.metric);
          OptionsPage.showOverlay('instantConfirmOverlay');
        }
      };

      var homepageField = $('homepageURL');
      $('homepageUseNTPButton').onchange =
          this.handleHomepageUseNTPButtonChange_.bind(this);
      $('homepageUseURLButton').onchange =
          this.handleHomepageUseURLButtonChange_.bind(this);
      homepageField.onchange =
          this.handleHomepageURLChange_.bind(this);

      // Ensure that changes are committed when closing the page.
      window.addEventListener('unload', function() {
          if (document.activeElement == homepageField)
            homepageField.blur();
          });

      if (!cr.isChromeOS) {
        $('defaultBrowserUseAsDefaultButton').onclick = function(event) {
          chrome.send('becomeDefaultBrowser');
        };
      }

      var list = $('startupPagesShortList');
      options.browser_options.StartupPageList.decorate(list);
      list.autoExpands = true;
      list.selectionModel = new ListSelectionModel;

      // Check if we are in the guest mode.
      if (cr.commandLine.options['--bwsi']) {
        // Hide the startup section.
        $('startupSection').classList.add('hidden');
      } else {
        // Initialize control enabled states.
        Preferences.getInstance().addEventListener('session.restore_on_startup',
            this.updateCustomStartupPageControlStates_.bind(this));
        Preferences.getInstance().addEventListener('homepage_is_newtabpage',
            this.handleHomepageIsNewTabPageChange_.bind(this));
        Preferences.getInstance().addEventListener('homepage',
            this.handleHomepageChange_.bind(this));

        this.updateCustomStartupPageControlStates_();
      }
    },

    /**
     * Update the Default Browsers section based on the current state.
     * @private
     * @param {string} statusString Description of the current default state.
     * @param {boolean} isDefault Whether or not the browser is currently
     *     default.
     * @param {boolean} canBeDefault Whether or not the browser can be default.
     */
    updateDefaultBrowserState_: function(statusString, isDefault,
                                         canBeDefault) {
      var label = $('defaultBrowserState');
      label.textContent = statusString;

      $('defaultBrowserUseAsDefaultButton').disabled = !canBeDefault ||
                                                       isDefault;
    },

    /**
     * Clears the search engine popup.
     * @private
     */
    clearSearchEngines_: function() {
      $('defaultSearchEngine').textContent = '';
    },

    /**
     * Updates the search engine popup with the given entries.
     * @param {Array} engines List of available search engines.
     * @param {Integer} defaultValue The value of the current default engine.
     */
    updateSearchEngines_: function(engines, defaultValue) {
      this.clearSearchEngines_();
      engineSelect = $('defaultSearchEngine');
      engineCount = engines.length;
      var defaultIndex = -1;
      for (var i = 0; i < engineCount; i++) {
        var engine = engines[i];
        var option = new Option(engine['name'], engine['index']);
        if (defaultValue == option.value)
          defaultIndex = i;
        engineSelect.appendChild(option);
      }
      if (defaultIndex >= 0)
        engineSelect.selectedIndex = defaultIndex;
    },

    /**
     * Returns true if the custom startup page control block should
     * be enabled.
     * @private
     * @returns {boolean} Whether the startup page controls should be
     *     enabled.
     */
    shouldEnableCustomStartupPageControls_: function(pages) {
      return $('startupShowPagesButton').checked;
    },

    /**
     * Updates the startup pages list with the given entries.
     * @private
     * @param {Array} pages List of startup pages.
     */
    updateStartupPages_: function(pages) {
      var list = $('startupPagesShortList');
      list.dataModel = new ArrayDataModel(pages);
      if (pages.length > 0 && pages.length <= 10) {
        list.classList.remove("hidden");
        $('startupPageManagement').classList.add('settings-list');
        $('startupShowPagesLabel').textContent =
            localStrings.getStringWithoutAccelerator('startupShowPages');
      } else {
        list.classList.add("hidden");
        $('startupPageManagement').classList.remove('settings-list');
        $('startupShowPagesLabel').textContent =
            localStrings.getStringWithoutAccelerator('startupShowManyPages');
      }
    },

    /**
     * Handles change events of the radio button 'homepageUseURLButton'.
     * @private
     * @param {event} change event.
     */
    handleHomepageUseURLButtonChange_: function(event) {
      Preferences.setBooleanPref('homepage_is_newtabpage', false);
    },

    /**
     * Handles change events of the radio button 'homepageUseNTPButton'.
     * @private
     * @param {event} change event.
     */
    handleHomepageUseNTPButtonChange_: function(event) {
      Preferences.setBooleanPref('homepage_is_newtabpage', true);
    },

    /**
     * Handles change events of the text field 'homepageURL'.
     * @private
     * @param {event} change event.
     */
    handleHomepageURLChange_: function(event) {
      Preferences.setStringPref('homepage', $('homepageURL').value);
    },

    /**
     * Handle change events of the preference 'homepage'.
     * @private
     * @param {event} preference changed event.
     */
    handleHomepageChange_: function(event) {
      this.homepage_pref_.value = event.value['value'];
      this.homepage_pref_.managed = event.value['managed'];
      if (this.isHomepageURLNewTabPageURL_() && !this.homepage_pref_.managed &&
          !this.homepage_is_newtabpage_pref_.managed) {
        var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_();
        Preferences.setStringPref('homepage', '')
        Preferences.setBooleanPref('homepage_is_newtabpage', useNewTabPage)
      }
      this.updateHomepageControlStates_();
    },

    /**
     * Handle change events of the preference homepage_is_newtabpage.
     * @private
     * @param {event} preference changed event.
     */
    handleHomepageIsNewTabPageChange_: function(event) {
      this.homepage_is_newtabpage_pref_.value = event.value['value'];
      this.homepage_is_newtabpage_pref_.managed = event.value['managed'];
      this.updateHomepageControlStates_();
    },

    /**
     * Update homepage preference UI controls.  Here's a table describing the
     * desired characteristics of the homepage choice radio value, its enabled
     * state and the URL field enabled state. They depend on the values of the
     * managed bits for homepage (m_hp) and homepageIsNewTabPage (m_ntp)
     * preferences, as well as the value of the homepageIsNewTabPage preference
     * (ntp) and whether the homepage preference is equal to the new tab page
     * URL (hpisntp).
     *
     * m_hp m_ntp ntp hpisntp| choice value| choice enabled| URL field enabled
     * ------------------------------------------------------------------------
     * 0    0     0   0      | homepage    | 1             | 1
     * 0    0     0   1      | new tab page| 1             | 0
     * 0    0     1   0      | new tab page| 1             | 0
     * 0    0     1   1      | new tab page| 1             | 0
     * 0    1     0   0      | homepage    | 0             | 1
     * 0    1     0   1      | homepage    | 0             | 1
     * 0    1     1   0      | new tab page| 0             | 0
     * 0    1     1   1      | new tab page| 0             | 0
     * 1    0     0   0      | homepage    | 1             | 0
     * 1    0     0   1      | new tab page| 0             | 0
     * 1    0     1   0      | new tab page| 1             | 0
     * 1    0     1   1      | new tab page| 0             | 0
     * 1    1     0   0      | homepage    | 0             | 0
     * 1    1     0   1      | new tab page| 0             | 0
     * 1    1     1   0      | new tab page| 0             | 0
     * 1    1     1   1      | new tab page| 0             | 0
     *
     * thus, we have:
     *
     *    choice value is new tab page === ntp || (hpisntp && (m_hp || !m_ntp))
     *    choice enabled === !m_ntp && !(m_hp && hpisntp)
     *    URL field enabled === !ntp && !mhp && !(hpisntp && !m_ntp)
     *
     * which also make sense if you think about them.
     * @private
     */
    updateHomepageControlStates_: function() {
      var homepageField = $('homepageURL');
      homepageField.disabled = !this.isHomepageURLFieldEnabled_();
      homepageField.value = this.homepage_pref_.value;
      homepageField.style.backgroundImage = url('chrome://favicon/' +
                                                this.homepage_pref_.value);
      var disableChoice = !this.isHomepageChoiceEnabled_();
      $('homepageUseURLButton').disabled = disableChoice;
      $('homepageUseNTPButton').disabled = disableChoice;
      var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_();
      $('homepageUseNTPButton').checked = useNewTabPage;
      $('homepageUseURLButton').checked = !useNewTabPage;
    },

    /**
     * Tests whether the value of the 'homepage' preference equls the new tab
     * page url (chrome://newtab).
     * @private
     * @returns {boolean} True if the 'homepage' value equals the new tab page
     *     url.
     */
    isHomepageURLNewTabPageURL_ : function() {
      return (this.homepage_pref_.value.toLowerCase() == 'chrome://newtab');
    },

    /**
     * Tests whether the Homepage choice "Use New Tab Page" is selected.
     * @private
     * @returns {boolean} True if "Use New Tab Page" is selected.
     */
    isHomepageIsNewTabPageChoiceSelected_: function() {
      return (this.homepage_is_newtabpage_pref_.value ||
              (this.isHomepageURLNewTabPageURL_() &&
               (this.homepage_pref_.managed ||
                !this.homepage_is_newtabpage_pref_.managed)));
    },

    /**
     * Tests whether the home page choice controls are enabled.
     * @private
     * @returns {boolean} True if the home page choice controls are enabled.
     */
    isHomepageChoiceEnabled_: function() {
      return (!this.homepage_is_newtabpage_pref_.managed &&
              !(this.homepage_pref_.managed &&
                this.isHomepageURLNewTabPageURL_()));
    },

    /**
     * Checks whether the home page field should be enabled.
     * @private
     * @returns {boolean} True if the home page field should be enabled.
     */
    isHomepageURLFieldEnabled_: function() {
      return (!this.homepage_is_newtabpage_pref_.value &&
              !this.homepage_pref_.managed &&
              !(this.isHomepageURLNewTabPageURL_() &&
                !this.homepage_is_newtabpage_pref_.managed));
    },

    /**
     * Sets the enabled state of the custom startup page list controls
     * based on the current startup radio button selection.
     * @private
     */
    updateCustomStartupPageControlStates_: function() {
      var disable = !this.shouldEnableCustomStartupPageControls_();
      $('startupPagesShortList').disabled = disable;
      $('startupUseCurrentButton').disabled = disable;
      $('startupPageManagerButton').disabled = disable;
    },

    /**
     * Set the default search engine based on the popup selection.
     */
    setDefaultSearchEngine: function() {
      var engineSelect = $('defaultSearchEngine');
      var selectedIndex = engineSelect.selectedIndex;
      if (selectedIndex >= 0) {
        var selection = engineSelect.options[selectedIndex];
        chrome.send('setDefaultSearchEngine', [String(selection.value)]);
      }
    },
  };

  BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault,
                                                      canBeDefault) {
    if (!cr.isChromeOS) {
      BrowserOptions.getInstance().updateDefaultBrowserState_(statusString,
                                                              isDefault,
                                                              canBeDefault);
    }
  };

  BrowserOptions.updateSearchEngines = function(engines, defaultValue) {
    BrowserOptions.getInstance().updateSearchEngines_(engines, defaultValue);
  };

  BrowserOptions.updateStartupPages = function(pages) {
    BrowserOptions.getInstance().updateStartupPages_(pages);
    StartupPageManager.getInstance().updateStartupPages_(pages);
  };

  // Export
  return {
    BrowserOptions: BrowserOptions
  };

});
<|endoftext|>


<commit_before>// core
import React, { PureComponent } from 'react'
import { View, Image } from 'react-native'
import PropTypes from 'prop-types'
// libs
import Svg, { Rect, Path } from 'react-native-svg'
import genMatrix from './genMatrix'

/**
 * A simple component for displaying QR Code using svg
 */
export default class QRCode extends PureComponent {
  static propTypes = {
    /* what the qr code stands for */
    value: PropTypes.string,
    /* the whole component size */
    size: PropTypes.number,
    /* the color of the cell */
    color: PropTypes.string,
    /* the color of the background */
    backgroundColor: PropTypes.string,
    /* an image source object. example {uri: 'base64string'} or {require('pathToImage')} */
    logo: Image.propTypes.source,
    /* logo width in pixels */
    logoSize: PropTypes.number,
    /* the logo gets a filled rectangular background with this color. Use 'transparent'
         if your logo already has its own backdrop. Default = same as backgroundColor */
    logoBackgroundColor: PropTypes.string,
    /* logo's distance to its wrapper */
    logoMargin: PropTypes.number,
    /* the border-radius of logo image */
    logoBorderRadius: PropTypes.number,
    /* get svg ref for further usage */
    getRef: PropTypes.func,
    /* error correction level */
    ecl: PropTypes.oneOf(['L', 'M', 'Q', 'H'])
  };
  static defaultProps = {
    value: 'This is a QR Code.',
    size: 100,
    color: 'black',
    backgroundColor: 'white',
    logoMargin: 2,
    ecl: 'M'
  };
  constructor (props) {
    super(props)
    this._matrix = null
    this._cellSize = null
    this._path = null
    this.setMatrix(props)
  }
  componentWillUpdate (nextProps) {
    // if value has changed, re-setMatrix
    if (nextProps.value !== this.props.value) {
      this.setMatrix(nextProps)
    }
  }
  /* calculate the size of the cell and draw the path */
  setMatrix (props) {
    const { value, size, ecl } = props
    this._matrix = genMatrix(value, ecl)
    this._cellSize = size / (this._matrix.length + 2)
    this._path = this.transformMatrixIntoPath()
  }
  /* project the matrix into path draw */
  transformMatrixIntoPath () {
    const matrix = this._matrix
    const cellSize = this._cellSize
    // adjust origin
    const oY = cellSize * 1.5
    const oX = cellSize
    let d = ''
    matrix.forEach((row, i) => {
      let needDraw = false
      row.forEach((column, j) => {
        if (column) {
          if (!needDraw) {
            d += `M${oX + cellSize * j} ${oY + cellSize * i} `
            needDraw = true
          }
          if (needDraw && j === matrix.length - 1) {
            d += `L${oX + cellSize * (j + 1)} ${oY + cellSize * i} `
          }
        } else {
          if (needDraw) {
            d += `L${oX + cellSize * j} ${oY + cellSize * i} `
            needDraw = false
          }
        }
      })
    })
    return d
  }
  renderLogo () {
    const { size, backgroundColor, logo, logoBackgroundColor = backgroundColor,
      logoSize = size * 0.2, logoMargin, logoBorderRadius } = this.props
    const wrapSize = logoSize + logoMargin * 2
    const position = size / 2 - logoSize / 2 - logoMargin

    const viewStyle = {
      backgroundColor: logoBackgroundColor,
      width: wrapSize,
      height: wrapSize,
      position: 'absolute',
      left: position,
      top: position,
      padding: logoMargin,
      borderRadius: logoBorderRadius,
      overflow: 'hidden'
    }

    const imageStyle = {
      width: logoSize,
      height: logoSize
    }

    return (
      <View style={viewStyle}>
        <Image
          style={imageStyle}
          source={logo}
          resizeMode='contain'
        />
      </View>
    )
  }

  render () {
    const { size, color, backgroundColor, logo, getRef } = this.props

    return (
      <View>
        <Svg ref={getRef} width={size} height={size}>
          <Rect
            x={this._cellSize}
            y={this._cellSize}
            width={size - 2 * this._cellSize}
            height={size - 2 * this._cellSize}
            fill={backgroundColor}
          />
          <Path
            d={this._path}
            stroke={color}
            strokeWidth={this._cellSize}
          />
        </Svg>
        {logo && this.renderLogo()}
      </View>
    )
  }
}
<commit_msg>remove border of qrcode image<commit_after>// core
import React, { PureComponent } from 'react'
import { View, Image } from 'react-native'
import PropTypes from 'prop-types'
// libs
import Svg, { Rect, Path } from 'react-native-svg'
import genMatrix from './genMatrix'

/**
 * A simple component for displaying QR Code using svg
 */
export default class QRCode extends PureComponent {
  static propTypes = {
    /* what the qr code stands for */
    value: PropTypes.string,
    /* the whole component size */
    size: PropTypes.number,
    /* the color of the cell */
    color: PropTypes.string,
    /* the color of the background */
    backgroundColor: PropTypes.string,
    /* an image source object. example {uri: 'base64string'} or {require('pathToImage')} */
    logo: Image.propTypes.source,
    /* logo width in pixels */
    logoSize: PropTypes.number,
    /* the logo gets a filled rectangular background with this color. Use 'transparent'
         if your logo already has its own backdrop. Default = same as backgroundColor */
    logoBackgroundColor: PropTypes.string,
    /* logo's distance to its wrapper */
    logoMargin: PropTypes.number,
    /* the border-radius of logo image */
    logoBorderRadius: PropTypes.number,
    /* get svg ref for further usage */
    getRef: PropTypes.func,
    /* error correction level */
    ecl: PropTypes.oneOf(['L', 'M', 'Q', 'H'])
  };
  static defaultProps = {
    value: 'This is a QR Code.',
    size: 100,
    color: 'black',
    backgroundColor: 'white',
    logoMargin: 2,
    ecl: 'M'
  };
  constructor (props) {
    super(props)
    this._matrix = null
    this._cellSize = null
    this._path = null
    this.setMatrix(props)
  }
  componentWillUpdate (nextProps) {
    // if value has changed, re-setMatrix
    if (nextProps.value !== this.props.value) {
      this.setMatrix(nextProps)
    }
  }
  /* calculate the size of the cell and draw the path */
  setMatrix (props) {
    const { value, size, ecl } = props
    this._matrix = genMatrix(value, ecl)
    this._cellSize = size / this._matrix.length
    this._path = this.transformMatrixIntoPath()
  }
  /* project the matrix into path draw */
  transformMatrixIntoPath () {
    const matrix = this._matrix
    const cellSize = this._cellSize
    // adjust origin
    let d = ''
    matrix.forEach((row, i) => {
      let needDraw = false
      row.forEach((column, j) => {
        if (column) {
          if (!needDraw) {
            d += `M${cellSize * j} ${cellSize / 2 + cellSize * i} `
            needDraw = true
          }
          if (needDraw && j === matrix.length - 1) {
            d += `L${cellSize * (j + 1)} ${cellSize / 2 + cellSize * i} `
          }
        } else {
          if (needDraw) {
            d += `L${cellSize * j} ${cellSize / 2 + cellSize * i} `
            needDraw = false
          }
        }
      })
    })
    return d
  }
  renderLogo () {
    const { size, backgroundColor, logo, logoBackgroundColor = backgroundColor,
      logoSize = size * 0.2, logoMargin, logoBorderRadius } = this.props
    const wrapSize = logoSize + logoMargin * 2
    const position = size / 2 - logoSize / 2 - logoMargin

    const viewStyle = {
      backgroundColor: logoBackgroundColor,
      width: wrapSize,
      height: wrapSize,
      position: 'absolute',
      left: position,
      top: position,
      padding: logoMargin,
      borderRadius: logoBorderRadius,
      overflow: 'hidden'
    }

    const imageStyle = {
      width: logoSize,
      height: logoSize
    }

    return (
      <View style={viewStyle}>
        <Image
          style={imageStyle}
          source={logo}
          resizeMode='contain'
        />
      </View>
    )
  }

  render () {
    const { size, color, backgroundColor, logo, getRef } = this.props

    return (
      <View>
        <Svg ref={getRef} width={size} height={size}>
          <Rect
            width={size}
            height={size}
            fill={backgroundColor}
          />
          <Path
            d={this._path}
            stroke={color}
            strokeWidth={this._cellSize}
          />
        </Svg>
        {logo && this.renderLogo()}
      </View>
    )
  }
}
<|endoftext|>


<commit_before>const path = require("path");
const fs = require("fs");
const User = require("../models/user");

exports.postAPIPixel = (req, res, next) => {
    if (fs.existsSync(path.join(__dirname, "../util/", "legit.js"))) {
        const legit = require("../util/legit");
        if (!legit.verify(req)) return res.status(403).json({ success: false, error: { message: "You cannot do that.", code: "unauthorized" } });
    }
    function paintWithUser(user) {
        if (!user.canPlace(req.place)) return res.status(429).json({ success: false, error: { message: "You cannot place yet.", code: "slow_down" } });
        if (!req.body.x || !req.body.y || !req.body.colour) return res.status(400).json({ success: false, error: { message: "You need to include all paramaters", code: "invalid_parameters" } });
        var x = Number.parseInt(req.body.x), y = Number.parseInt(req.body.y);
        if(Number.isNaN(x) || Number.isNaN(y)) return res.status(400).json({ success: false, error: { message: "Your coordinates were incorrectly formatted", code: "invalid_parameters" } });
        var rgb = req.place.paintingManager.getColourRGB(req.body.colour);
        if (!rgb) return res.status(400).json({ success: false, error: { message: "Invalid color code specified.", code: "invalid_parameters" } });
        req.place.paintingManager.doPaint(rgb, x, y, user).then((pixel) => {
            return User.findById(user.id).then((user) => {
                var seconds = user.getPlaceSecondsRemaining(req.place);
                var countData = { canPlace: seconds <= 0, seconds: seconds };
                return res.json({ success: true, timer: countData })
            }).catch((err) => res.json({ success: true }));
        }).catch((err) => {
            req.place.reportError("Error placing pixel: " + err);
            res.status(500).json({ success: false, error: err })
        });
    }
    paintWithUser(req.user);
};

exports.getAPITimer = (req, res, next) => {
    function getTimerPayload(user) {
        var seconds = user.getPlaceSecondsRemaining(req.place);
        var countData = { canPlace: seconds <= 0, seconds: seconds };
        return { success: true, timer: countData };
    }
    return res.json(getTimerPayload(req.user));
};<commit_msg>This is GREAT BRITAIN<commit_after>const path = require("path");
const fs = require("fs");
const User = require("../models/user");

exports.postAPIPixel = (req, res, next) => {
    if (fs.existsSync(path.join(__dirname, "../util/", "legit.js"))) {
        const legit = require("../util/legit");
        if (!legit.verify(req)) return res.status(403).json({ success: false, error: { message: "You cannot do that.", code: "unauthorized" } });
    }
    function paintWithUser(user) {
        if (!user.canPlace(req.place)) return res.status(429).json({ success: false, error: { message: "You cannot place yet.", code: "slow_down" } });
        if (!req.body.x || !req.body.y || !req.body.colour) return res.status(400).json({ success: false, error: { message: "You need to include all paramaters", code: "invalid_parameters" } });
        var x = Number.parseInt(req.body.x), y = Number.parseInt(req.body.y);
        if(Number.isNaN(x) || Number.isNaN(y)) return res.status(400).json({ success: false, error: { message: "Your coordinates were incorrectly formatted", code: "invalid_parameters" } });
        var rgb = req.place.paintingManager.getColourRGB(req.body.colour);
        if (!rgb) return res.status(400).json({ success: false, error: { message: "Invalid colour code specified.", code: "invalid_parameters" } });
        req.place.paintingManager.doPaint(rgb, x, y, user).then((pixel) => {
            return User.findById(user.id).then((user) => {
                var seconds = user.getPlaceSecondsRemaining(req.place);
                var countData = { canPlace: seconds <= 0, seconds: seconds };
                return res.json({ success: true, timer: countData })
            }).catch((err) => res.json({ success: true }));
        }).catch((err) => {
            req.place.reportError("Error placing pixel: " + err);
            res.status(500).json({ success: false, error: err })
        });
    }
    paintWithUser(req.user);
};

exports.getAPITimer = (req, res, next) => {
    function getTimerPayload(user) {
        var seconds = user.getPlaceSecondsRemaining(req.place);
        var countData = { canPlace: seconds <= 0, seconds: seconds };
        return { success: true, timer: countData };
    }
    return res.json(getTimerPayload(req.user));
};
<|endoftext|>