<commit_before>// Copyright (c) 2009 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.

/**
 * @fileoverview Stub implementation of the InspectorController API.
 * This stub class is supposed to make front-end a standalone WebApp
 * that can be implemented/refactored in isolation from the Web browser
 * backend. Clients need to subclass it in order to wire calls to the
 * non-stub backends.
 */
goog.provide('devtools.InspectorController');

/**
 * Creates inspector controller stub instance.
 * @constructor.
 */
devtools.InspectorController = function() {
  /**
   * @type {boolean}
   */
  this.searchingForNode_ = false;

  /**
   * @type {boolean}
   */
  this.windowVisible_ = true;

  /**
   * @type {number}
   */
  this.attachedWindowHeight_ = 0;

  /**
   * @type {boolean}
   */
  this.debuggerEnabled_ = true;

  /**
   * @type {boolean}
   */
  this.profilerEnabled_ = true;

  /**
   * @type {boolean}
   */
  this.resourceTrackingEnabled_ = false;

  /**
   * @type {boolean}
   */
  this.timelineEnabled_ = false;

  /**
   * @type {Object}
   */
  this.settings_ = {};
};

/**
 * Wraps javascript callback.
 * @param {function():undefined} func The callback to wrap.
 * @return {function():undefined} Callback wrapper.
 */
devtools.InspectorController.prototype.wrapCallback = function f(func) {
  // Just return as is.
  return func;
};

/**
 * @return {boolean} True iff inspector window is currently visible.
 */
devtools.InspectorController.prototype.isWindowVisible = function() {
  return this.windowVisible_;
};

/**
 * @return {string} Platform identifier.
 */
devtools.InspectorController.prototype.platform = function() {
  return 'windows';
};

/**
 * Closes inspector window.
 */
devtools.InspectorController.prototype.closeWindow =  function() {
  this.windowVisible_ = false;
};

/**
 * Attaches frontend to the backend.
 */
devtools.InspectorController.prototype.attach = function() {
};

/**
 * Detaches frontend from the backend.
 */
devtools.InspectorController.prototype.detach = function() {
};

/**
 * Tell host that the active panel has changed.
 * @param {string} panel Panel name that was last active.
 */
devtools.InspectorController.prototype.storeLastActivePanel = function(panel) {
};

/**
 * Clears console message log in the backend.
 */
devtools.InspectorController.prototype.clearMessages = function() {
};

/**
 * Returns true iff browser is currently in the search for node mode.
 * @return {boolean} True is currently searching for a node.
 */
devtools.InspectorController.prototype.searchingForNode = function() {
  return this.searchingForNode_;
};

/**
 * Initiates search for a given query starting on a given row.
 * @param {number} sourceRow Row to start searching from.
 * @param {string} query Query string for search for.
 */
devtools.InspectorController.prototype.search = function(sourceRow, query) {
};

/**
 * Toggles node search mode on/off.
 */
devtools.InspectorController.prototype.toggleNodeSearch = function() {
  this.searchingForNode_ = !this.searchingForNode_;
};

/**
 * Sets the inspector window height while in the attached mode.
 * @param {number} height Window height being set.
 */
devtools.InspectorController.prototype.setAttachedWindowHeight =
    function(height) {
  this.attachedWindowHeight_ = height;
};

/**
 * Moves window by the given offset.
 * @param {number} x X offset.
 * @param {number} y Y offset.
 */
devtools.InspectorController.prototype.moveByUnrestricted = function(x, y) {
};

/**
 * Adds resource with given identifier into the given iframe element.
 * @param {number} identifier Identifier of the resource to add into the frame.
 * @param {Element} element Element to add resource content to.
 */
devtools.InspectorController.prototype.addResourceSourceToFrame =
    function(identifier, element) {
};

/**
 * Adds given source of a given mimeType into the given iframe element.
 * @param {string} mimeType MIME type of the content to be added.
 * @param {string} source String content to be added.
 * @param {Element} element Element to add resource content to.
 */
devtools.InspectorController.prototype.addSourceToFrame =
    function(mimeType, source, element) {
  return false;
};

/**
 * Returns document node corresponding to the resource with given id.
 * @return {Node} Node containing the resource.
 */
devtools.InspectorController.prototype.getResourceDocumentNode =
    function(identifier) {
  return undefined;
};

/**
 * Highlights the given node on the page.
 * @param {Node} node Node to highlight.
 */
devtools.InspectorController.prototype.highlightDOMNode = function(node) {
  // Does nothing in stub.
};

/**
 * Clears current highlight.
 */
devtools.InspectorController.prototype.hideDOMNodeHighlight = function() {
  // Does nothing in stub.
};

/**
 * @return {window} Inspectable window instance.
 */
devtools.InspectorController.prototype.inspectedWindow = function() {
  return window;
};

/**
 * Notifies backend that the frontend has been successfully loaded.
 */
devtools.InspectorController.prototype.loaded = function() {
  // Does nothing in stub.
};

/**
 * @return {string} Url of the i18n-ed strings map.
 */
devtools.InspectorController.prototype.localizedStringsURL = function() {
  return undefined;
};

/**
 * @return {boolean} True iff window is currently unloading.
 */
devtools.InspectorController.prototype.windowUnloading = function() {
  return false;
};

/**
 * @return {string} Identifiers of the panels that should be hidden.
 */
devtools.InspectorController.prototype.hiddenPanels = function() {
  return '';
};

/**
 * @return {boolean} True iff debugger is enabled.
 */
devtools.InspectorController.prototype.debuggerEnabled = function() {
  return this.debuggerEnabled_;
};

/**
 * Enables resource tracking.
 */
devtools.InspectorController.prototype.enableResourceTracking = function() {
  this.resourceTrackingEnabled_ = true;
  WebInspector.resourceTrackingWasEnabled();
};

/**
 * Disables resource tracking.
 */
devtools.InspectorController.prototype.disableResourceTracking = function() {
  this.resourceTrackingEnabled_ = false;
  WebInspector.resourceTrackingWasDisabled();
};

/**
 * @return {boolean} True iff resource tracking is enabled.
 */
devtools.InspectorController.prototype.resourceTrackingEnabled = function() {
  return this.resourceTrackingEnabled_;
};

/**
 * Enables timeline.
 */
devtools.InspectorController.prototype.enableTimeline = function() {
  this.timelineEnabled_ = true;
  WebInspector.timelineWasEnabled();
};

/**
 * Disables timeline.
 */
devtools.InspectorController.prototype.disableTimeline = function() {
  this.timelineEnabled_ = false;
  WebInspector.timelineWasDisabled();
};

/**
 * @return {boolean} True iff timeline is enabled.
 */
devtools.InspectorController.prototype.timelineEnabled = function() {
  return this.timelineEnabled_;
};

/**
 * Enables debugger.
 */
devtools.InspectorController.prototype.enableDebugger = function() {
  this.debuggerEnabled_ = true;
};

/**
 * Disables debugger.
 */
devtools.InspectorController.prototype.disableDebugger = function() {
  this.debuggerEnabled_ = false;
};

/**
 * Adds breakpoint to the given line of the source with given ID.
 * @param {string} sourceID Source Id to add breakpoint to.
 * @param {number} line Line number to add breakpoint to.
 * @param {?string} condition The breakpoint condition.
 */
devtools.InspectorController.prototype.addBreakpoint =
    function(sourceID, line, condition) {
};

/**
 * Removes breakpoint from the given line of the source with given ID.
 * @param {string} sourceID Source Id to remove breakpoint from.
 * @param {number} line Line number to remove breakpoint from.
 */
devtools.InspectorController.prototype.removeBreakpoint =
    function(sourceID, line) {
};

/**
 * Sets a breakpoint condition given a line of the source and an ID.
 * @param {string} sourceID Source Id to remove breakpoint from.
 * @param {number} line Line number to remove breakpoint from.
 * @param {?string} condition New breakpoint condition.
 */
devtools.InspectorController.prototype.updateBreakpoint =
    function(sourceID, line, condition) {
};

/**
 * Tells backend to pause in the debugger.
 */
devtools.InspectorController.prototype.pauseInDebugger = function() {
  // Does nothing in stub.
};

/**
 * @return {boolean} True iff the debugger will pause execution on the
 * exceptions.
 */
devtools.InspectorController.prototype.pauseOnExceptions = function() {
  // Does nothing in stub.
  return false;
};

/**
 * Tells whether to pause in the debugger on the exceptions or not.
 * @param {boolean} value True iff execution should be stopped in the debugger
 * on the exceptions.
 */
devtools.InspectorController.prototype.setPauseOnExceptions = function(value) {
};

/**
 * Tells backend to resume execution.
 */
devtools.InspectorController.prototype.resumeDebugger = function() {
};

/**
 * @return {boolean} True iff profiler is enabled.
 */
devtools.InspectorController.prototype.profilerEnabled = function() {
  return true;
};

/**
 * Enables profiler.
 */
devtools.InspectorController.prototype.enableProfiler = function() {
  this.profilerEnabled_ = true;
};

/**
 * Disables profiler.
 */
devtools.InspectorController.prototype.disableProfiler = function() {
  this.profilerEnabled_ = false;
};

/**
 * Returns given callframe while on a debugger break.
 * @return {Object} Current call frame.
 */
devtools.InspectorController.prototype.currentCallFrame = function() {
  return undefined;
};

/**
 * Tells backend to start collecting profiler data.
 */
devtools.InspectorController.prototype.startProfiling = function() {
};

/**
 * Tells backend to stop collecting profiler data.
 */
devtools.InspectorController.prototype.stopProfiling = function() {
};

/**
 * @return {Array.<Object>} Profile snapshots array.
 */
devtools.InspectorController.prototype.profiles = function() {
  return [];
};

/**
 * Tells backend to create a heap snapshot.
 */
devtools.InspectorController.prototype.takeHeapSnapshot = function() {
};

/**
 * @return {Array.<string>} Database table names available offline.
 */
devtools.InspectorController.prototype.databaseTableNames =
    function(database) {
  return [];
};

/**
 * Tells backend to step into the function in debugger.
 */
devtools.InspectorController.prototype.stepIntoStatementInDebugger =
    function() {
};

/**
 * Tells backend to step out of the function in debugger.
 */
devtools.InspectorController.prototype.stepOutOfFunctionInDebugger =
    function() {};

/**
 * Tells backend to step over the statement in debugger.
 */
devtools.InspectorController.prototype.stepOverStatementInDebugger =
    function() {
};

/**
 * Sets a setting value in backend.
 */
devtools.InspectorController.prototype.setSetting =
    function(setting, value) {
  this.settings_[setting] = value;
};

/**
 * Retrieves a setting value stored in backend.
 */
devtools.InspectorController.prototype.setting =
    function(setting) {
  return this.settings_[setting];
};

var InspectorController = new devtools.InspectorController();
<commit_msg>DevTools: add methods to our InspectorController stub to prepare for a change in WebKit.<commit_after>// Copyright (c) 2009 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.

/**
 * @fileoverview Stub implementation of the InspectorController API.
 * This stub class is supposed to make front-end a standalone WebApp
 * that can be implemented/refactored in isolation from the Web browser
 * backend. Clients need to subclass it in order to wire calls to the
 * non-stub backends.
 */
goog.provide('devtools.InspectorController');

/**
 * Creates inspector controller stub instance.
 * @constructor.
 */
devtools.InspectorController = function() {
  /**
   * @type {boolean}
   */
  this.searchingForNode_ = false;

  /**
   * @type {boolean}
   */
  this.windowVisible_ = true;

  /**
   * @type {number}
   */
  this.attachedWindowHeight_ = 0;

  /**
   * @type {boolean}
   */
  this.debuggerEnabled_ = true;

  /**
   * @type {boolean}
   */
  this.profilerEnabled_ = true;

  /**
   * @type {boolean}
   */
  this.resourceTrackingEnabled_ = false;

  /**
   * @type {boolean}
   */
  this.timelineEnabled_ = false;

  /**
   * @type {Object}
   */
  this.settings_ = {};
};

/**
 * Wraps javascript callback.
 * @param {function():undefined} func The callback to wrap.
 * @return {function():undefined} Callback wrapper.
 */
devtools.InspectorController.prototype.wrapCallback = function f(func) {
  // Just return as is.
  return func;
};

/**
 * @return {boolean} True iff inspector window is currently visible.
 */
devtools.InspectorController.prototype.isWindowVisible = function() {
  return this.windowVisible_;
};

/**
 * @return {string} Platform identifier.
 */
devtools.InspectorController.prototype.platform = function() {
  return 'windows';
};

/**
 * Closes inspector window.
 */
devtools.InspectorController.prototype.closeWindow =  function() {
  this.windowVisible_ = false;
};

/**
 * Attaches frontend to the backend.
 */
devtools.InspectorController.prototype.attach = function() {
};

/**
 * Detaches frontend from the backend.
 */
devtools.InspectorController.prototype.detach = function() {
};

/**
 * Tell host that the active panel has changed.
 * @param {string} panel Panel name that was last active.
 */
devtools.InspectorController.prototype.storeLastActivePanel = function(panel) {
};

/**
 * Clears console message log in the backend.
 */
devtools.InspectorController.prototype.clearMessages = function() {
};

/**
 * Returns true iff browser is currently in the search for node mode.
 * @return {boolean} True is currently searching for a node.
 */
devtools.InspectorController.prototype.searchingForNode = function() {
  return this.searchingForNode_;
};

/**
 * Initiates search for a given query starting on a given row.
 * @param {number} sourceRow Row to start searching from.
 * @param {string} query Query string for search for.
 */
devtools.InspectorController.prototype.search = function(sourceRow, query) {
};

/**
 * Toggles node search mode on/off.
 */
devtools.InspectorController.prototype.toggleNodeSearch = function() {
  this.searchingForNode_ = !this.searchingForNode_;
};

/**
 * Sets the inspector window height while in the attached mode.
 * @param {number} height Window height being set.
 */
devtools.InspectorController.prototype.setAttachedWindowHeight =
    function(height) {
  this.attachedWindowHeight_ = height;
};

/**
 * Moves window by the given offset.
 * @param {number} x X offset.
 * @param {number} y Y offset.
 */
devtools.InspectorController.prototype.moveByUnrestricted = function(x, y) {
};

/**
 * Adds resource with given identifier into the given iframe element.
 * @param {number} identifier Identifier of the resource to add into the frame.
 * @param {Element} element Element to add resource content to.
 */
devtools.InspectorController.prototype.addResourceSourceToFrame =
    function(identifier, element) {
};

/**
 * Adds given source of a given mimeType into the given iframe element.
 * @param {string} mimeType MIME type of the content to be added.
 * @param {string} source String content to be added.
 * @param {Element} element Element to add resource content to.
 */
devtools.InspectorController.prototype.addSourceToFrame =
    function(mimeType, source, element) {
  return false;
};

/**
 * Returns document node corresponding to the resource with given id.
 * @return {Node} Node containing the resource.
 */
devtools.InspectorController.prototype.getResourceDocumentNode =
    function(identifier) {
  return undefined;
};

/**
 * Highlights the given node on the page.
 * @param {Node} node Node to highlight.
 */
devtools.InspectorController.prototype.highlightDOMNode = function(node) {
  // Does nothing in stub.
};

/**
 * Clears current highlight.
 */
devtools.InspectorController.prototype.hideDOMNodeHighlight = function() {
  // Does nothing in stub.
};

/**
 * @return {window} Inspectable window instance.
 */
devtools.InspectorController.prototype.inspectedWindow = function() {
  return window;
};

/**
 * Notifies backend that the frontend has been successfully loaded.
 */
devtools.InspectorController.prototype.loaded = function() {
  // Does nothing in stub.
};

/**
 * @return {string} Url of the i18n-ed strings map.
 */
devtools.InspectorController.prototype.localizedStringsURL = function() {
  return undefined;
};

/**
 * @return {boolean} True iff window is currently unloading.
 */
devtools.InspectorController.prototype.windowUnloading = function() {
  return false;
};

/**
 * @return {string} Identifiers of the panels that should be hidden.
 */
devtools.InspectorController.prototype.hiddenPanels = function() {
  return '';
};

/**
 * @return {boolean} True iff debugger is enabled.
 */
devtools.InspectorController.prototype.debuggerEnabled = function() {
  return this.debuggerEnabled_;
};

/**
 * Enables resource tracking.
 */
devtools.InspectorController.prototype.enableResourceTracking = function() {
  this.resourceTrackingEnabled_ = true;
  WebInspector.resourceTrackingWasEnabled();
};

/**
 * Disables resource tracking.
 */
devtools.InspectorController.prototype.disableResourceTracking = function() {
  this.resourceTrackingEnabled_ = false;
  WebInspector.resourceTrackingWasDisabled();
};

/**
 * @return {boolean} True iff resource tracking is enabled.
 */
devtools.InspectorController.prototype.resourceTrackingEnabled = function() {
  return this.resourceTrackingEnabled_;
};

/**
 * Enables timeline.
 */
devtools.InspectorController.prototype.enableTimeline = function() {
  this.timelineEnabled_ = true;
  WebInspector.timelineWasEnabled();
};

/**
 * Disables timeline.
 */
devtools.InspectorController.prototype.disableTimeline = function() {
  this.timelineEnabled_ = false;
  WebInspector.timelineWasDisabled();
};

/**
 * @return {boolean} True iff timeline is enabled.
 */
devtools.InspectorController.prototype.timelineEnabled = function() {
  return this.timelineEnabled_;
};

/**
 * Enables debugger.
 */
devtools.InspectorController.prototype.enableDebugger = function() {
  this.debuggerEnabled_ = true;
};

/**
 * Disables debugger.
 */
devtools.InspectorController.prototype.disableDebugger = function() {
  this.debuggerEnabled_ = false;
};

/**
 * Adds breakpoint to the given line of the source with given ID.
 * @param {string} sourceID Source Id to add breakpoint to.
 * @param {number} line Line number to add breakpoint to.
 * @param {?string} condition The breakpoint condition.
 */
devtools.InspectorController.prototype.addBreakpoint =
    function(sourceID, line, condition) {
};

/**
 * Removes breakpoint from the given line of the source with given ID.
 * @param {string} sourceID Source Id to remove breakpoint from.
 * @param {number} line Line number to remove breakpoint from.
 */
devtools.InspectorController.prototype.removeBreakpoint =
    function(sourceID, line) {
};

/**
 * Sets a breakpoint condition given a line of the source and an ID.
 * @param {string} sourceID Source Id to remove breakpoint from.
 * @param {number} line Line number to remove breakpoint from.
 * @param {?string} condition New breakpoint condition.
 */
devtools.InspectorController.prototype.updateBreakpoint =
    function(sourceID, line, condition) {
};

/**
 * Tells backend to pause in the debugger.
 */
devtools.InspectorController.prototype.pauseInDebugger = function() {
  // Does nothing in stub.
};

/**
 * @return {boolean} True iff the debugger will pause execution on the
 * exceptions.
 */
devtools.InspectorController.prototype.pauseOnExceptions = function() {
  // Does nothing in stub.
  return false;
};

/**
 * Tells whether to pause in the debugger on the exceptions or not.
 * @param {boolean} value True iff execution should be stopped in the debugger
 * on the exceptions.
 */
devtools.InspectorController.prototype.setPauseOnExceptions = function(value) {
};

/**
 * Tells backend to resume execution.
 */
devtools.InspectorController.prototype.resumeDebugger = function() {
};

/**
 * @return {boolean} True iff profiler is enabled.
 */
devtools.InspectorController.prototype.profilerEnabled = function() {
  return true;
};

/**
 * Enables profiler.
 */
devtools.InspectorController.prototype.enableProfiler = function() {
  this.profilerEnabled_ = true;
};

/**
 * Disables profiler.
 */
devtools.InspectorController.prototype.disableProfiler = function() {
  this.profilerEnabled_ = false;
};

/**
 * Returns given callframe while on a debugger break.
 * @return {Object} Current call frame.
 */
devtools.InspectorController.prototype.currentCallFrame = function() {
  return undefined;
};

/**
 * Tells backend to start collecting profiler data.
 */
devtools.InspectorController.prototype.startProfiling = function() {
};

/**
 * Tells backend to stop collecting profiler data.
 */
devtools.InspectorController.prototype.stopProfiling = function() {
};

/**
 * TODO(mnaganov): Remove after injected script change landing in WebKit.
 * @return {Array.<Object>} Profile snapshots array.
 */
devtools.InspectorController.prototype.profiles = function() {
  return [];
};

/**
 * Async function for retrieving headers of existing profiles.
 */
devtools.InspectorController.prototype.getProfileHeaders = function(callId) {
  WebInspector.didGetProfileHeaders(callId, []);
};

/**
 * Async function for lazy loading an existing profile.
 */
devtools.InspectorController.prototype.getProfile = function(callId, uid) {
};

/**
 * Tells backend to create a heap snapshot.
 */
devtools.InspectorController.prototype.takeHeapSnapshot = function() {
};

/**
 * @return {Array.<string>} Database table names available offline.
 */
devtools.InspectorController.prototype.databaseTableNames =
    function(database) {
  return [];
};

/**
 * Tells backend to step into the function in debugger.
 */
devtools.InspectorController.prototype.stepIntoStatementInDebugger =
    function() {
};

/**
 * Tells backend to step out of the function in debugger.
 */
devtools.InspectorController.prototype.stepOutOfFunctionInDebugger =
    function() {};

/**
 * Tells backend to step over the statement in debugger.
 */
devtools.InspectorController.prototype.stepOverStatementInDebugger =
    function() {
};

/**
 * Sets a setting value in backend.
 */
devtools.InspectorController.prototype.setSetting =
    function(setting, value) {
  this.settings_[setting] = value;
};

/**
 * Retrieves a setting value stored in backend.
 */
devtools.InspectorController.prototype.setting =
    function(setting) {
  return this.settings_[setting];
};

var InspectorController = new devtools.InspectorController();
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

// Duration of a long press in ms
const LONG_PRESS_DURATION = 500;

function withLongPress(WrappedComponent) {
    class WithLongPressComponent extends React.Component {
        constructor(props) {
            super(props);

            this.element = null;
            this.timer = null;
            this.pressStart = 0;

            this.onPressStart = this.onPressStart.bind(this);
            this.onPressEnd = this.onPressEnd.bind(this);
            this.onContextMenu = this.onContextMenu.bind(this);
        }

        onContextMenu(event) {
            event.preventDefault();
            event.stopPropagation();
        }

        onPressStart(event) {
            clearTimeout(this.timer);
            this.pressStart = Date.now();
            this.timer = setTimeout(this.props.onLongPress, LONG_PRESS_DURATION);
            event.target.addEventListener('touchend', this.onPressEnd);
            event.target.addEventListener('touchmove', this.onPressEnd);
            event.target.addEventListener('touchcancel', this.onPressEnd);
            event.target.addEventListener('contextmenu', this.onContextMenu);
        }

        onPressEnd(event) {
            // Prevent clicks to happen after a long press
            if (event.type === 'touchend' && Date.now() - this.pressStart > LONG_PRESS_DURATION) {
                event.preventDefault();
            }

            event.target.removeEventListener('touchend', this.onPressEnd);
            event.target.removeEventListener('touchmove', this.onPressEnd);
            event.target.removeEventListener('touchcancel', this.onPressEnd);
            event.target.removeEventListener('contextmenu', this.onContextMenu);

            clearTimeout(this.timer);
            this.pressStart = 0;
        }

        componentDidMount() {
            ReactDOM.findDOMNode(this.element).addEventListener('touchstart', this.onPressStart);
        }

        componentWillUnMount() {
            let domElement = ReactDOM.findDOMNode(this.element);
            domElement.removeEventListener('touchstart', this.onPressStart);
            domElement.removeEventListener('touchend', this.onPressEnd);
            domElement.removeEventListener('touchmove', this.onPressEnd);
            domElement.removeEventListener('touchcancel', this.onPressEnd);
            domElement.removeEventListener('contextmenu', this.onContextMenu);
        }

        render() {
            let refComponent = node => {
                this.element = node;
            };

            return <WrappedComponent {...this.props} ref={refComponent} />;
        }
    }

    WithLongPressComponent.propTypes = {
        // The callback called when a longpress occurred on the component.
        onLongPress: PropTypes.func.isRequired
    };

    return WithLongPressComponent;
}

export default withLongPress;
<commit_msg>Add a test in the withLongPress HOC, so that we do not try to pass it a functional component.<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

import { assert } from '../../helpers';

// Duration of a long press in ms
const LONG_PRESS_DURATION = 500;

function withLongPress(WrappedComponent) {
    assert(
        WrappedComponent.prototype && WrappedComponent.prototype.isReactComponent,
        `WrappedComponent (${WrappedComponent.name}) cannot be a functional component`
    );

    class WithLongPressComponent extends React.Component {
        constructor(props) {
            super(props);

            this.element = null;
            this.timer = null;
            this.pressStart = 0;

            this.onPressStart = this.onPressStart.bind(this);
            this.onPressEnd = this.onPressEnd.bind(this);
            this.onContextMenu = this.onContextMenu.bind(this);
        }

        onContextMenu(event) {
            event.preventDefault();
            event.stopPropagation();
        }

        onPressStart(event) {
            clearTimeout(this.timer);
            this.pressStart = Date.now();
            this.timer = setTimeout(this.props.onLongPress, LONG_PRESS_DURATION);
            event.target.addEventListener('touchend', this.onPressEnd);
            event.target.addEventListener('touchmove', this.onPressEnd);
            event.target.addEventListener('touchcancel', this.onPressEnd);
            event.target.addEventListener('contextmenu', this.onContextMenu);
        }

        onPressEnd(event) {
            // Prevent clicks to happen after a long press
            if (event.type === 'touchend' && Date.now() - this.pressStart > LONG_PRESS_DURATION) {
                event.preventDefault();
            }

            event.target.removeEventListener('touchend', this.onPressEnd);
            event.target.removeEventListener('touchmove', this.onPressEnd);
            event.target.removeEventListener('touchcancel', this.onPressEnd);
            event.target.removeEventListener('contextmenu', this.onContextMenu);

            clearTimeout(this.timer);
            this.pressStart = 0;
        }

        componentDidMount() {
            ReactDOM.findDOMNode(this.element).addEventListener('touchstart', this.onPressStart);
        }

        componentWillUnMount() {
            let domElement = ReactDOM.findDOMNode(this.element);
            domElement.removeEventListener('touchstart', this.onPressStart);
            domElement.removeEventListener('touchend', this.onPressEnd);
            domElement.removeEventListener('touchmove', this.onPressEnd);
            domElement.removeEventListener('touchcancel', this.onPressEnd);
            domElement.removeEventListener('contextmenu', this.onContextMenu);
        }

        render() {
            let refComponent = node => {
                this.element = node;
            };

            return <WrappedComponent {...this.props} ref={refComponent} />;
        }
    }

    WithLongPressComponent.propTypes = {
        // The callback called when a longpress occurred on the component.
        onLongPress: PropTypes.func.isRequired
    };

    return WithLongPressComponent;
}

export default withLongPress;
<|endoftext|>


<commit_before>zeit.cms.declare_namespace('zeit.content.gallery');

zeit.content.gallery.Uploader = gocept.Class.extend({

    construct: function(options) {
        var self = this;
        self.options = options;
        var d = self.get_ticket()
        d.addCallback(function(ticket) {
            self.init_uploader(ticket);
        });
    },

    get_ticket: function() {
        var d = MochiKit.Async.doSimpleXMLHttpRequest(
            application_url + '/@@get-ticket');
        d.addCallback(function(result) {
            return result.responseText;
        });
        return d;
    },

    get_upload_url: function(ticket) {
        var context = context_url.substr(application_url.length);
        var url = application_url + '/++ticket++' + ticket + context +
            '/@@upload-image';
        return url;
    },

    init_uploader: function(ticket) {
        var self = this;
        self.swfupload = new SWFUpload({
            flash_url: self.options.resource_base_url
                  + '/SWFUpload/Flash/swfupload.swf',
            upload_url: self.get_upload_url(ticket),
            http_success: [201],
            button_placeholder_id: 'image-upload',
            prevent_swf_caching: false,
            button_cursor : SWFUpload.CURSOR.HAND,
            button_width: 17,
            button_height: 18,
            button_image_url: self.options.resource_base_url +
                '/upload-icon.png',
            button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT,

            file_post_name: 'form.blob',
            post_params: {
                'form.actions.add': 'Add',
            },
            file_queue_limit: 0,  // no limit
            file_size_limit: 0,  // no limit
            file_types: '*.jpg;*.tif;*.gif;*.png',
            file_dialog_start_handler: function() {
                self.file_dialog_start();
            },
            file_queued_handler: function(file) {
                self.file_queued(file);
            },
            file_dialog_complete_handler: function(
                selected, queued, total_queued) {
                self.file_dialog_complete(selected, queued, total_queued);
            },
            upload_start_handler: function(file) {
                self.upload_start(file);
            },
            upload_progress_handler: function(file, uploaded, total) {
                self.upload_progress(file, uploaded, total);
            },
            upload_success_handler: function(file) {
                self.upload_success(file);
            },
            upload_error_handler: function(file, error_code, message) {
                self.upload_error(file, error_code, message);
            },
            upload_complete_handler: function(file) {
                self.upload_complete(file);
            },
        });
    },

    get_id: function(file) {
        return 'file-' + file.id;
    },

    set_progress: function(file, progress) {
        var self = this;
        var div = $(self.get_id(file));
        var progress_div = MochiKit.DOM.getFirstElementByTagAndClassName(
            'div', 'progress', div);
        progress_div.innerHTML = progress;
    },

    make_active: function(file) {
        var self = this;
        var divs = MochiKit.DOM.getElementsByTagAndClassName(
            'div', 'upload', self.lightbox.content_box);
        forEach(divs, function(div) {
            MochiKit.DOM.removeElementClass(div, 'active');
        });
        if (!isUndefinedOrNull(file)) {
            MochiKit.DOM.addElementClass($(self.get_id(file)), 'active');
        }
    },

    sync_and_reload: function() {
        var self = this;
        self.make_active(null);
        self.lightbox.content_box.appendChild(
            DIV({'class': 'upload active'},
                DIV({'class': 'filename'},
                    "Creating thumbnails and reloading …")));
        // We're making another async call here because the synchronize takes a
        // while. When we'd set document.location immeadiately the animated
        // busy indicator would stop until everything is processes.
        var d = MochiKit.Async.doSimpleXMLHttpRequest(
            context_url + '/@@synchronise-with-image-folder?redirect=false');
        d.addCallback(function(result) {
            document.location = result.responseText;
        });
    },

    file_dialog_start: function() {
        var self = this;
        self.lightbox = new gocept.Lightbox($('body'));
        self.lightbox.content_box.appendChild(
            H1({}, "Uploading images …"));
        return true;
    },

    file_queued: function(file) {
        var self = this;
        var id = self.get_id(file);
        var filename_contents = file.name + ' (' + file.size + ' Bytes)';
        self.lightbox.content_box.appendChild(
            DIV({'id': id, 'class': 'upload'},
                DIV({'class': 'filename'}, filename_contents),
                DIV({'class': 'progress'}, '0')));
        return true;
    },

    file_dialog_complete: function(selected, queued, total_queued) {
        var self = this;
        if (selected) {
            self.swfupload.startUpload();
        } else {
            self.lightbox.close();
        }
    },

    upload_start: function(file) {
        var self = this;
        self.swfupload.addFileParam(file.id, 'form.__name__', file.name);
        self.make_active(file);
        return true;
    },

    upload_progress: function(file, uploaded, total) {
        var self = this;
        self.set_progress(file, Math.ceil(uploaded/total*100));
        return true;
    },

    upload_success: function(file) {
        var self = this;
        self.set_progress(file, 100);
        return true;
    },

    upload_error: function(file, error_code, message) {
        var self = this;
        self.set_progress(file, 'ERR');
        logError(message, error_code);
        return true;
    },

    upload_complete: function(file) {
        var self = this;
        var stats = self.swfupload.getStats();
        if (stats.files_queued) {
            self.swfupload.startUpload();
        } else {
            self.sync_and_reload();
        }
        return true;
    },
});
<commit_msg>added error handler when we cannot get the ticket<commit_after>zeit.cms.declare_namespace('zeit.content.gallery');

zeit.content.gallery.Uploader = gocept.Class.extend({

    construct: function(options) {
        var self = this;
        self.options = options;
        var d = self.get_ticket()
        d.addCallback(function(ticket) {
            self.init_uploader(ticket);
        });
    },

    get_ticket: function() {
        var d = MochiKit.Async.doSimpleXMLHttpRequest(
            application_url + '/@@get-ticket');
        d.addCallbacks(function(result) {
            return result.responseText;
        },
        zeit.cms.log_error);
        return d;
    },

    get_upload_url: function(ticket) {
        var context = context_url.substr(application_url.length);
        var url = application_url + '/++ticket++' + ticket + context +
            '/@@upload-image';
        return url;
    },

    init_uploader: function(ticket) {
        var self = this;
        self.swfupload = new SWFUpload({
            flash_url: self.options.resource_base_url
                  + '/SWFUpload/Flash/swfupload.swf',
            upload_url: self.get_upload_url(ticket),
            http_success: [201],
            button_placeholder_id: 'image-upload',
            prevent_swf_caching: false,
            button_cursor : SWFUpload.CURSOR.HAND,
            button_width: 17,
            button_height: 18,
            button_image_url: self.options.resource_base_url +
                '/upload-icon.png',
            button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT,

            file_post_name: 'form.blob',
            post_params: {
                'form.actions.add': 'Add',
            },
            file_queue_limit: 0,  // no limit
            file_size_limit: 0,  // no limit
            file_types: '*.jpg;*.tif;*.gif;*.png',
            file_dialog_start_handler: function() {
                self.file_dialog_start();
            },
            file_queued_handler: function(file) {
                self.file_queued(file);
            },
            file_dialog_complete_handler: function(
                selected, queued, total_queued) {
                self.file_dialog_complete(selected, queued, total_queued);
            },
            upload_start_handler: function(file) {
                self.upload_start(file);
            },
            upload_progress_handler: function(file, uploaded, total) {
                self.upload_progress(file, uploaded, total);
            },
            upload_success_handler: function(file) {
                self.upload_success(file);
            },
            upload_error_handler: function(file, error_code, message) {
                self.upload_error(file, error_code, message);
            },
            upload_complete_handler: function(file) {
                self.upload_complete(file);
            },
        });
    },

    get_id: function(file) {
        return 'file-' + file.id;
    },

    set_progress: function(file, progress) {
        var self = this;
        var div = $(self.get_id(file));
        var progress_div = MochiKit.DOM.getFirstElementByTagAndClassName(
            'div', 'progress', div);
        progress_div.innerHTML = progress;
    },

    make_active: function(file) {
        var self = this;
        var divs = MochiKit.DOM.getElementsByTagAndClassName(
            'div', 'upload', self.lightbox.content_box);
        forEach(divs, function(div) {
            MochiKit.DOM.removeElementClass(div, 'active');
        });
        if (!isUndefinedOrNull(file)) {
            MochiKit.DOM.addElementClass($(self.get_id(file)), 'active');
        }
    },

    sync_and_reload: function() {
        var self = this;
        self.make_active(null);
        self.lightbox.content_box.appendChild(
            DIV({'class': 'upload active'},
                DIV({'class': 'filename'},
                    "Creating thumbnails and reloading …")));
        // We're making another async call here because the synchronize takes a
        // while. When we'd set document.location immeadiately the animated
        // busy indicator would stop until everything is processes.
        var d = MochiKit.Async.doSimpleXMLHttpRequest(
            context_url + '/@@synchronise-with-image-folder?redirect=false');
        d.addCallback(function(result) {
            document.location = result.responseText;
        });
    },

    file_dialog_start: function() {
        var self = this;
        self.lightbox = new gocept.Lightbox($('body'));
        self.lightbox.content_box.appendChild(
            H1({}, "Uploading images …"));
        return true;
    },

    file_queued: function(file) {
        var self = this;
        var id = self.get_id(file);
        var filename_contents = file.name + ' (' + file.size + ' Bytes)';
        self.lightbox.content_box.appendChild(
            DIV({'id': id, 'class': 'upload'},
                DIV({'class': 'filename'}, filename_contents),
                DIV({'class': 'progress'}, '0')));
        return true;
    },

    file_dialog_complete: function(selected, queued, total_queued) {
        var self = this;
        if (selected) {
            self.swfupload.startUpload();
        } else {
            self.lightbox.close();
        }
    },

    upload_start: function(file) {
        var self = this;
        self.swfupload.addFileParam(file.id, 'form.__name__', file.name);
        self.make_active(file);
        return true;
    },

    upload_progress: function(file, uploaded, total) {
        var self = this;
        self.set_progress(file, Math.ceil(uploaded/total*100));
        return true;
    },

    upload_success: function(file) {
        var self = this;
        self.set_progress(file, 100);
        return true;
    },

    upload_error: function(file, error_code, message) {
        var self = this;
        self.set_progress(file, 'ERR');
        logError(message, error_code);
        return true;
    },

    upload_complete: function(file) {
        var self = this;
        var stats = self.swfupload.getStats();
        if (stats.files_queued) {
            self.swfupload.startUpload();
        } else {
            self.sync_and_reload();
        }
        return true;
    },
});
<|endoftext|>


<commit_before>var apiInstitutes = "http://localhost:8080/secunity-backend/api/institutions";
var apiInstitute = "http://localhost:8080/secunity-backend/api/institution";
var apiPerson = "http://localhost:8080/secunity-backend/api/person/";

/* Handle creation of new institution */
$("#addInstForm").submit(function(e){
    e.preventDefault();

    var data = {}
    var Form = this;

    //Gather data and remove undefined attributes
    $.each(this.elements, function(i, v) {
        var input = $(v);
        data[input.attr("name")] = input.val();
        delete data["undefined"];
    });

    //Validate data
    var has_name = data['akts:has-pretty-name'];
    if (!has_name) {
    	//TODO Display proper error message
        console.log("Name missing");
    }

    // Post data
    createInstitute(
        has_name,
        data,
        function(callback){
            //Where $(this) => context == FORM
            document.querySelector('#modal_add_inst').close();
            resetForm($( '#addInstForm' ));
        },
        function(){
            $(this).html("Error!");
        }
        );
});

function resetForm(form) {
    form.find('input:text, input:password, input:file, select, textarea').val('');
    form.find('input:radio, input:checkbox').removeAttr('checked').removeAttr('selected');
}

/* ---------------------------------- */
/* 			REST functions	    	  */
/* ---------------------------------- */

/* Return institute data */ //TODO return Promise
function getInstitute(inst, done, fail) {
  $.getJSON( apiInstitute+"/" + encodeURIComponent(inst))
    .done(function( data ) {
    	if (done)
    		done(data);
    })
	.fail( function(d, textStatus, error) {
        if (fail)
        	fail(d,textStatus,error);
    });
}

/* List institutes */
function getInstitutes(limit, offset, done, fail) {
  $.getJSON( apiInstitutes + '?limit='+limit+'&offset='+offset )
    .done(function( data ) {
    	if (done)
    		done(data);
    })
	.fail( function(d, textStatus, error) {
        if (fail)
        	fail(d,textStatus,error);
        else
        	console.log(textStatus + ", " + error);
    });
}

/* Create new institute */
function createInstitute(name, map, success, fail) {
    //Save form data
    $.ajax({
        cache: false,
        url : apiInstitute + "/" + name,
        type: "POST",
        dataType : "json",
        contentType: "application/json; charset=UTF-8",
        data : JSON.stringify(data),
        context : Form,
        success : success(callback),
        error : fail()
    });
}

<commit_msg>More generic access to the REST interface<commit_after>// So that the hostname will adapt and be correct assuming that both, frontend server and rest-server are running on the same machine
var hostname = window.location.hostname;
hostname = "localhost";
var apiInstitutes = "http://" + hostname + ":8080/secunity-backend/api/institutions";
var apiInstitute = "http://" + hostname + ":8080/secunity-backend/api/institution";
var apiPerson = "http://" + hostname + ":8080/secunity-backend/api/person/";

/* Handle creation of new institution */
$("#addInstForm").submit(function(e){
    e.preventDefault();

    var data = {}
    var Form = this;

    //Gather data and remove undefined attributes
    $.each(this.elements, function(i, v) {
        var input = $(v);
        data[input.attr("name")] = input.val();
        delete data["undefined"];
    });

    //Validate data
    var has_name = data['akts:has-pretty-name'];
    if (!has_name) {
    	//TODO Display proper error message
        console.log("Name missing");
    }

    // Post data
    createInstitute(
        has_name,
        data,
        function(callback){
            //Where $(this) => context == FORM
            document.querySelector('#modal_add_inst').close();
            resetForm($( '#addInstForm' ));
        },
        function(){
            $(this).html("Error!");
        }
        );
});

function resetForm(form) {
    form.find('input:text, input:password, input:file, select, textarea').val('');
    form.find('input:radio, input:checkbox').removeAttr('checked').removeAttr('selected');
}

/* ---------------------------------- */
/* 			REST functions	    	  */
/* ---------------------------------- */

/* Return institute data */ //TODO return Promise
function getInstitute(inst, done, fail) {
  $.getJSON( apiInstitute+"/" + encodeURIComponent(inst))
    .done(function( data ) {
    	if (done)
    		done(data);
    })
	.fail( function(d, textStatus, error) {
        if (fail)
        	fail(d,textStatus,error);
    });
}

/* List institutes */
function getInstitutes(limit, offset, done, fail) {
  $.getJSON( apiInstitutes + '?limit='+limit+'&offset='+offset )
    .done(function( data ) {
    	if (done)
    		done(data);
    })
	.fail( function(d, textStatus, error) {
        if (fail)
        	fail(d,textStatus,error);
        else
        	console.log(textStatus + ", " + error);
    });
}

/* Create new institute */
function createInstitute(name, map, success, fail) {
    //Save form data
    $.ajax({
        cache: false,
        url : apiInstitute + "/" + name,
        type: "POST",
        dataType : "json",
        contentType: "application/json; charset=UTF-8",
        data : JSON.stringify(data),
        context : Form,
        success : success(callback),
        error : fail()
    });
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Factory for SecureDocument objects.
 *
 * @public
 *
 * @param {Object}
 *            doc - the DOM document
 * @param {Object}
 *            key - the key to apply to the secure document
 */
function SecureDocument(doc, key) {
    "use strict";

    function trust(st, el) {
        $A.lockerService.trust(st, el);
        return SecureElement(el, key);
    }

    function createElement(tag, namespace) {
    	// Insure that no object to string coercion tricks can be applied to evade tag name based logic
        tag = tag + "";
        switch (tag.toLowerCase()) {
            case "script":
                return SecureScriptElement(key);

            default:
                return trust(o, doc.createElementNS(namespace, tag));
        }
    }

    var o = Object.create(null, {
        toString: {
            value: function() {
                return "SecureDocument: " + doc + "{ key: " + JSON.stringify(key) + " }";
            }
        },
        createElement: {
            value: function(tag) {
                return createElement(tag, "http://www.w3.org/1999/xhtml");
            }
        },
        createElementNS: {
            value: function(namespace, tag) {
                return createElement(tag, namespace);
            }
        },
        createDocumentFragment: {
            value: function() {
                return trust(o, doc.createDocumentFragment());
            }
        },
        createTextNode: {
            value: function(text) {
                return trust(o, doc.createTextNode(text));
            }
        },
        createComment: {
            value: function(data) {
                return trust(o, doc.createComment(data));
            }
        },
        documentElement: {
        	enumerable: true,
    		get : function() {
                return trust(o, doc.documentElement.cloneNode());
            }
        },
        querySelector: {
            value: function(selector) {
                return SecureElement.secureQuerySelector(o, doc, key, selector);
            }
        }
    });

	SecureElement.addSecureGlobalEventHandlers(o, doc, key);
	SecureElement.addEventTargetMethods(o, doc, key);

    Object.defineProperties(o, {
        body: SecureObject.createFilteredProperty(o, doc, "body"),
        head: SecureObject.createFilteredProperty(o, doc, "head"),

        createEvent: SecureObject.createFilteredMethod(o, doc, "createEvent"),

        childNodes: SecureObject.createFilteredProperty(o, doc, "childNodes", { filterOpaque: true }),

        defaultView: SecureObject.createFilteredProperty(o, doc, "defaultView"),
        nodeType: SecureObject.createFilteredProperty(o, doc, "nodeType"),

        getElementById: SecureObject.createFilteredMethod(o, doc, "getElementById", { filterOpaque: true }),
        getElementsByClassName: SecureObject.createFilteredMethod(o, doc, "getElementsByClassName", { filterOpaque: true }),
        getElementsByName: SecureObject.createFilteredMethod(o, doc, "getElementsByName", { filterOpaque: true }),
        getElementsByTagName: SecureObject.createFilteredMethod(o, doc, "getElementsByTagName", { filterOpaque: true }),
        getElementsByTagNameNS: SecureObject.createFilteredMethod(o, doc, "getElementsByTagNameNS", { filterOpaque: true }),

        querySelectorAll: SecureObject.createFilteredMethod(o, doc, "querySelectorAll", { filterOpaque: true }),

        title: SecureObject.createFilteredProperty(o, doc, "title"),

        cookie: SecureObject.createFilteredProperty(o, doc, "cookie", {
            writable: false
        })
    });

    setLockerSecret(o, "key", key);
    setLockerSecret(o, "ref", doc);

    return o;
}
<commit_msg>Expose document.location @bug W-3232443@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Factory for SecureDocument objects.
 *
 * @public
 *
 * @param {Object}
 *            doc - the DOM document
 * @param {Object}
 *            key - the key to apply to the secure document
 */
function SecureDocument(doc, key) {
    "use strict";

    function trust(st, el) {
        $A.lockerService.trust(st, el);
        return SecureElement(el, key);
    }

    function createElement(tag, namespace) {
    	// Insure that no object to string coercion tricks can be applied to evade tag name based logic
        tag = tag + "";
        switch (tag.toLowerCase()) {
            case "script":
                return SecureScriptElement(key);

            default:
                return trust(o, doc.createElementNS(namespace, tag));
        }
    }

    var o = Object.create(null, {
        toString: {
            value: function() {
                return "SecureDocument: " + doc + "{ key: " + JSON.stringify(key) + " }";
            }
        },
        createElement: {
            value: function(tag) {
                return createElement(tag, "http://www.w3.org/1999/xhtml");
            }
        },
        createElementNS: {
            value: function(namespace, tag) {
                return createElement(tag, namespace);
            }
        },
        createDocumentFragment: {
            value: function() {
                return trust(o, doc.createDocumentFragment());
            }
        },
        createTextNode: {
            value: function(text) {
                return trust(o, doc.createTextNode(text));
            }
        },
        createComment: {
            value: function(data) {
                return trust(o, doc.createComment(data));
            }
        },
        documentElement: {
        	enumerable: true,
    		get : function() {
                return trust(o, doc.documentElement.cloneNode());
            }
        },
        querySelector: {
            value: function(selector) {
                return SecureElement.secureQuerySelector(o, doc, key, selector);
            }
        }
    });

	SecureElement.addSecureGlobalEventHandlers(o, doc, key);
	SecureElement.addEventTargetMethods(o, doc, key);

    Object.defineProperties(o, {
        body: SecureObject.createFilteredProperty(o, doc, "body"),
        head: SecureObject.createFilteredProperty(o, doc, "head"),

        createEvent: SecureObject.createFilteredMethod(o, doc, "createEvent"),

        childNodes: SecureObject.createFilteredProperty(o, doc, "childNodes", { filterOpaque: true }),

        defaultView: SecureObject.createFilteredProperty(o, doc, "defaultView"),
        nodeType: SecureObject.createFilteredProperty(o, doc, "nodeType"),

        getElementById: SecureObject.createFilteredMethod(o, doc, "getElementById", { filterOpaque: true }),
        getElementsByClassName: SecureObject.createFilteredMethod(o, doc, "getElementsByClassName", { filterOpaque: true }),
        getElementsByName: SecureObject.createFilteredMethod(o, doc, "getElementsByName", { filterOpaque: true }),
        getElementsByTagName: SecureObject.createFilteredMethod(o, doc, "getElementsByTagName", { filterOpaque: true }),
        getElementsByTagNameNS: SecureObject.createFilteredMethod(o, doc, "getElementsByTagNameNS", { filterOpaque: true }),

        querySelectorAll: SecureObject.createFilteredMethod(o, doc, "querySelectorAll", { filterOpaque: true }),

        title: SecureObject.createFilteredProperty(o, doc, "title"),

        cookie: SecureObject.createFilteredProperty(o, doc, "cookie", {
            writable: false
        })
    });

    ["location"].forEach(function(name) {
        // These are direct passthrough's and should never be wrapped in a SecureObject
        Object.defineProperty(o, name, {
            enumerable: true,
            value: doc[name]
        });
    });

    setLockerSecret(o, "key", key);
    setLockerSecret(o, "ref", doc);

    return o;
}
<|endoftext|>


<commit_before>/**
 * Button component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';
import useMergedRef from '@react-hook/merged-ref';

/**
 * WordPress dependencies
 */
import { forwardRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import { MDCRipple } from '../material-components';

const Button = forwardRef( ( {
	children,
	href,
	text,
	className,
	danger,
	disabled,
	target,
	icon,
	trailingIcon,
	...extraProps
}, ref ) => {
	const buttonRef = useCallback( ( el ) => {
		if ( el !== null ) {
			MDCRipple.attachTo( el );
		}
	}, [] );
	const mergedRefs = useMergedRef( ref, buttonRef );

	// Use a button if disabled, even if a href is provided to ensure expected behavior.
	const SemanticButton = ( href && ! disabled ) ? 'a' : 'button';

	return (
		<SemanticButton
			className={ classnames(
				'mdc-button',
				className,
				{
					'mdc-button--raised': ! text,
					'mdc-button--danger': danger,
				}
			) }
			href={ disabled ? undefined : href }
			ref={ mergedRefs }
			disabled={ !! disabled }
			target={ target || '_self' }
			role={ 'a' === SemanticButton ? 'button' : undefined }
			{ ...extraProps }
		>
			{ icon }
			{ children }
			{ trailingIcon }
		</SemanticButton>
	);
} );

Button.displayName = 'Button';

Button.propTypes = {
	onClick: PropTypes.func,
	children: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.node ),
		PropTypes.node,
	] ),
	href: PropTypes.string,
	text: PropTypes.bool,
	className: PropTypes.string,
	danger: PropTypes.bool,
	disabled: PropTypes.bool,
	icon: PropTypes.element,
	trailingIcon: PropTypes.element,
};

Button.defaultProps = {
	onClick: null,
	href: null,
	text: false,
	className: '',
	danger: false,
	disabled: false,
	icon: null,
	trailingIcon: null,
};

export default Button;
<commit_msg>Fix redundant prop type, node includes array of nodes.<commit_after>/**
 * Button component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';
import useMergedRef from '@react-hook/merged-ref';

/**
 * WordPress dependencies
 */
import { forwardRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import { MDCRipple } from '../material-components';

const Button = forwardRef( ( {
	children,
	href,
	text,
	className,
	danger,
	disabled,
	target,
	icon,
	trailingIcon,
	...extraProps
}, ref ) => {
	const buttonRef = useCallback( ( el ) => {
		if ( el !== null ) {
			MDCRipple.attachTo( el );
		}
	}, [] );
	const mergedRefs = useMergedRef( ref, buttonRef );

	// Use a button if disabled, even if a href is provided to ensure expected behavior.
	const SemanticButton = ( href && ! disabled ) ? 'a' : 'button';

	return (
		<SemanticButton
			className={ classnames(
				'mdc-button',
				className,
				{
					'mdc-button--raised': ! text,
					'mdc-button--danger': danger,
				}
			) }
			href={ disabled ? undefined : href }
			ref={ mergedRefs }
			disabled={ !! disabled }
			target={ target || '_self' }
			role={ 'a' === SemanticButton ? 'button' : undefined }
			{ ...extraProps }
		>
			{ icon }
			{ children }
			{ trailingIcon }
		</SemanticButton>
	);
} );

Button.displayName = 'Button';

Button.propTypes = {
	onClick: PropTypes.func,
	children: PropTypes.node,
	href: PropTypes.string,
	text: PropTypes.bool,
	className: PropTypes.string,
	danger: PropTypes.bool,
	disabled: PropTypes.bool,
	icon: PropTypes.element,
	trailingIcon: PropTypes.element,
};

Button.defaultProps = {
	onClick: null,
	href: null,
	text: false,
	className: '',
	danger: false,
	disabled: false,
	icon: null,
	trailingIcon: null,
};

export default Button;
<|endoftext|>


<commit_before>'use strict';

let angular = require('angular');

module.exports = angular.module('spinnaker.titus.serverGroupCommandBuilder.service', [
  require('../../../core/cache/deckCacheFactory.js'),
  require('../../../core/account/account.service.js'),
  require('../../../core/naming/naming.service.js')
])
  .factory('titusServerGroupCommandBuilder', function (settings, $q,
                                                     accountService, namingService) {
    function buildNewServerGroupCommand(application, defaults) {
      defaults = defaults || {};

      var defaultCredentials = defaults.account || settings.providers.titus.defaults.account;
      var defaultRegion = defaults.region || settings.providers.titus.defaults.region;
      var defaultZone = defaults.zone || settings.providers.titus.defaults.zone;

      var command = {
        application: application.name,
        credentials: defaultCredentials,
        region: defaultRegion,
        zone: defaultZone,
        network: 'default',
        inService: true,
        strategy: '',
        capacity: {
          min: 1,
          max: 1,
          desired: 1
        },
        env: {},
        labels: {},
        cloudProvider: 'titus',
        selectedProvider: 'titus',
        viewState: {
          useSimpleCapacity: true,
          usePreferredZones: true,
          mode: defaults.mode || 'create',
        }
      };

      return $q.when(command);
  }

    // Only used to prepare view requiring template selecting
    function buildNewServerGroupCommandForPipeline() {
      return $q.when({
        viewState: {
          requiresTemplateSelection: true,
        }
      });
    }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode) {
      mode = mode || 'clone';

      var serverGroupName = namingService.parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        strategy: '',
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        account: serverGroup.account,
        credentials: serverGroup.account,
        region: serverGroup.region,
        env: serverGroup.env,
        labels: serverGroup.labels,
        entryPoint: serverGroup.entryPoint,
        iamProfile: serverGroup.iamProfile,
        securityGroups: serverGroup.securityGroups,
        hardConstraints: serverGroup.hardConstraints.join(),
        softConstraints: serverGroup.softConstraints.join(),
        inService: serverGroup.disabled ? false : true,
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          asgName: serverGroup.name,
        },
        resources: {
          cpu: serverGroup.resources.cpu,
          memory: serverGroup.resources.memory,
          disk: serverGroup.resources.disk,
          ports: serverGroup.resources.ports,
          allocateIpAddress: serverGroup.resources.allocateIpAddress,
        },
        capacity: {
          min: serverGroup.capacity.min,
          max: serverGroup.capacity.max,
          desired: serverGroup.capacity.desired
        },
        cloudProvider: 'titus',
        selectedProvider: 'titus',
        viewState: {
          useSimpleCapacity: true,
          mode: mode,
        },
      };

      if (mode !== 'editPipeline') {
        command.imageId = serverGroup.image.dockerImageName + ':' + serverGroup.image.dockerImageVersion;
      }

      return $q.when(command);
    }

    function buildServerGroupCommandFromPipeline(application, originalCluster) {

      var pipelineCluster = _.cloneDeep(originalCluster);
      var commandOptions = { account: pipelineCluster.account, region: pipelineCluster.region };
      var asyncLoader = $q.all({command: buildNewServerGroupCommand(application, commandOptions)});

      return asyncLoader.then(function(asyncData) {
        var command = asyncData.command;
        command.hardConstraints = command.hardConstraints.join();
        command.softConstraints = command.softConstraints.join();

        var viewState = {
          disableImageSelection: true,
          useSimpleCapacity: true,
          mode: 'editPipeline',
          submitButtonLabel: 'Done',
        };

        var viewOverrides = {
          region: pipelineCluster.region,
          credentials: pipelineCluster.account,
          viewState: viewState,
        };

        pipelineCluster.strategy = pipelineCluster.strategy || '';
        var extendedCommand = angular.extend({}, command, pipelineCluster, viewOverrides);
        return extendedCommand;
      });

    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildNewServerGroupCommandForPipeline: buildNewServerGroupCommandForPipeline,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,
      buildServerGroupCommandFromPipeline: buildServerGroupCommandFromPipeline,
    };
});

<commit_msg>(titus): corner case for constraints<commit_after>'use strict';

let angular = require('angular');

module.exports = angular.module('spinnaker.titus.serverGroupCommandBuilder.service', [
  require('../../../core/cache/deckCacheFactory.js'),
  require('../../../core/account/account.service.js'),
  require('../../../core/naming/naming.service.js')
])
  .factory('titusServerGroupCommandBuilder', function (settings, $q,
                                                     accountService, namingService) {
    function buildNewServerGroupCommand(application, defaults) {
      defaults = defaults || {};

      var defaultCredentials = defaults.account || settings.providers.titus.defaults.account;
      var defaultRegion = defaults.region || settings.providers.titus.defaults.region;
      var defaultZone = defaults.zone || settings.providers.titus.defaults.zone;

      var command = {
        application: application.name,
        credentials: defaultCredentials,
        region: defaultRegion,
        zone: defaultZone,
        network: 'default',
        inService: true,
        strategy: '',
        capacity: {
          min: 1,
          max: 1,
          desired: 1
        },
        env: {},
        labels: {},
        cloudProvider: 'titus',
        selectedProvider: 'titus',
        viewState: {
          useSimpleCapacity: true,
          usePreferredZones: true,
          mode: defaults.mode || 'create',
        }
      };

      return $q.when(command);
  }

    // Only used to prepare view requiring template selecting
    function buildNewServerGroupCommandForPipeline() {
      return $q.when({
        viewState: {
          requiresTemplateSelection: true,
        }
      });
    }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode) {
      mode = mode || 'clone';

      var serverGroupName = namingService.parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        strategy: '',
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        account: serverGroup.account,
        credentials: serverGroup.account,
        region: serverGroup.region,
        env: serverGroup.env,
        labels: serverGroup.labels,
        entryPoint: serverGroup.entryPoint,
        iamProfile: serverGroup.iamProfile,
        securityGroups: serverGroup.securityGroups,
        hardConstraints: (serverGroup.hardConstraints || []).join(),
        softConstraints: (serverGroup.softConstraints || []).join(),
        inService: serverGroup.disabled ? false : true,
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          asgName: serverGroup.name,
        },
        resources: {
          cpu: serverGroup.resources.cpu,
          memory: serverGroup.resources.memory,
          disk: serverGroup.resources.disk,
          ports: serverGroup.resources.ports,
          allocateIpAddress: serverGroup.resources.allocateIpAddress,
        },
        capacity: {
          min: serverGroup.capacity.min,
          max: serverGroup.capacity.max,
          desired: serverGroup.capacity.desired
        },
        cloudProvider: 'titus',
        selectedProvider: 'titus',
        viewState: {
          useSimpleCapacity: true,
          mode: mode,
        },
      };

      if (mode !== 'editPipeline') {
        command.imageId = serverGroup.image.dockerImageName + ':' + serverGroup.image.dockerImageVersion;
      }

      return $q.when(command);
    }

    function buildServerGroupCommandFromPipeline(application, originalCluster) {

      var pipelineCluster = _.cloneDeep(originalCluster);
      var commandOptions = { account: pipelineCluster.account, region: pipelineCluster.region };
      var asyncLoader = $q.all({command: buildNewServerGroupCommand(application, commandOptions)});

      return asyncLoader.then(function(asyncData) {
        var command = asyncData.command;
        command.hardConstraints = (command.hardConstraints || []).join();
        command.softConstraints = (command.softConstraints || []).join();

        var viewState = {
          disableImageSelection: true,
          useSimpleCapacity: true,
          mode: 'editPipeline',
          submitButtonLabel: 'Done',
        };

        var viewOverrides = {
          region: pipelineCluster.region,
          credentials: pipelineCluster.account,
          viewState: viewState,
        };

        pipelineCluster.strategy = pipelineCluster.strategy || '';
        var extendedCommand = angular.extend({}, command, pipelineCluster, viewOverrides);
        return extendedCommand;
      });

    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildNewServerGroupCommandForPipeline: buildNewServerGroupCommandForPipeline,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,
      buildServerGroupCommandFromPipeline: buildServerGroupCommandFromPipeline,
    };
});

<|endoftext|>


<commit_before>import assert from 'assert';
import React from 'react';
import { renderToString } from 'react-dom/server';

import GenePage from './index';

describe('GenePage', () => {
  it('should be able to render to an HTML string', () => {
    let htmlString = renderToString(<GenePage params={{geneId: 5}} />);
    assert.equal(typeof htmlString, 'string');
  });
});
<commit_msg>Fix unit test<commit_after>import assert from 'assert';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { createMemoryHistory } from 'react-router';

import configureStore from '../../lib/configureStore';

import GenePage from './index';

let historyObj = createMemoryHistory('/gene/WBGene00197647');

describe('GenePage', () => {
  it('should be able to render to an HTML string', () => {
    let store = configureStore(historyObj);
    let htmlString = renderToString(
      <Provider store={store}>
        <GenePage params={{geneId: 'WBGene00197647'}} />
      </Provider>
    );
    assert.equal(typeof htmlString, 'string');
  });
});
<|endoftext|>


<commit_before>/*
*  Name: Labor Statistics Dashboard Custom Slider
*  Author: John Denielle Hernandez
*  Desc: Custom slider component similar to input of type range with some
*    additional features such as multiple values and automatic orientation
*    detection.
*/

/*
*  TODO: Configurable handles example
*
*  TODO: Apply prop validation
*/

/*
*  LsdSliderHandle React Component
*  States:
*    dragging:  [boolean] Needed to be checked if the handle needs to be moved
*               because the mouse listener is declared globally.
*    position:  [JSON object] {
*      top: [float] Changed when a vertical slider handle is being dragged.
*      left: [float] Changed when a horizontal slider handle is being dragged.
*    }
*    dimension:  [JSON object] Offset dimension of the handle. {
*	   width: [float] Obtained from offsetWidth HTML element property.
*      height: [float] Obtained from offsetHeight HTML element property.
*    }
*    borderWidth: [float] Used for offset
*  Props:
*    computeHandlePosition= [function] Used to get new position when dragging.
*    computeHandleOffset= [function] Uses the offset height/width of handle.
*    orientation: [string] "x" | "y" Determined by LsdSlider React Component.
*    initialValue: [float] Used to show multiple handles evenly distributed
*                  across the slider initially.
*/
var LsdSliderHandle = React.createClass({
  /*
  *  TODO: Fix warning -> "getInitialState was defined on LsdSlider, a plain
  *  JavaScript class. This is only supported for classes created using
  *  React.createClass. Did you mean to define a state property instead?".
  *
  *  TODO: Fix bug, resizing window breaks offset of handle in vertical slider.
  *  The horizontal slider seems to be clear of this bug.
  *
  *  TODO: Check if clientHeight/Width or scrollHeight/Width can replace the
  *        handle offset computation using the borderWidth state.
  *
  *  TODO: Refactor all code that relies on orientation. Eliminate redundancy.
  *
  *  TODO: Try Using ReactLink
  */
  getInitialState: function() {
    return {
      dragging: false,
      position: {
        top: 0,
        left: 0
      },
      dimension: {
        width: 0,
        height: 0
      },
      borderWidth: 0
    };
  },
  componentDidMount: function() {
  	/*
    *  Binding dragStart to mousedown should also be here but:
    *  onMouseDown > refs (by simplicity).
    *  Take note that I add the event listener to the document element because:
    *  1. The mousemove relies on the mouse's coordinates relative to the
    *     document, not the handle. Otherwise, the handle will move only if the
    *     mouse is moved inside the handle.
    *  2. If the mouse is released outside the handle, the drag will stop since
    *     the document, and not the handle, listens to that event.
    */
    document.addEventListener("mousemove", this.dragEvent);
    document.addEventListener("mouseup", this.dragStop);

    /*
  	*  Get the real value of the handle element. It factors in the width of the
  	*  border and padding.
  	*/
    var newDimension = {
      width: this.componentInstance.offsetWidth,
      height: this.componentInstance.offsetHeight
    };

    var handleOffset = this.props.computeHandleOffset(newDimension);

    var newPosition =
      (this.props.orientation == "x")?
        {
          top: -handleOffset,
          left: this.props.initialValue-handleOffset
        }:
        {
          top: this.props.initialValue-handleOffset,
          left: -handleOffset
        };

    this.setState({
      dimension: newDimension,
      position: newPosition,
      borderWidth: parseInt(getComputedStyle(this.componentInstance).getPropertyValue("border-width"))
    });
  },
  componentWillUnmount: function(){
  	document.removeEventListener("mousemove", this.dragEvent);
    document.removeEventListener("mouseup", this.dragStop);
  },
  dragStart: function() {
    this.setState ({
      dragging: true
    });
  },
  dragStop: function() {
    this.setState ({
      dragging: false
    });
  },
  dragEvent: function(event) {
    if (this.state.dragging) {
      /*
      *  Prevents the cursor to select elements while dragging the handle
      */
      if(event.stopPropagation) event.stopPropagation();
      if(event.preventDefault) event.preventDefault();

      var handlePos = this.props.computeHandlePosition(
        {
          x: event.pageX,
          y: event.pageY
        }, this.state.dimension);

      if(this.props.orientation == "x") {
        this.setState({
          position: {
            left: handlePos.offsetValue
          }
        });
      }
      else {
        this.setState({
          position: {
            top: handlePos.offsetValue
          }
        });
      }
    }
  },
  render: function() {
    /*
  	*  The long computation is for centering the handle with respect to the
  	*  slider's orientation.
  	*/
    var style = (this.props.orientation == "x")?
      ({
        left: this.state.position.left + "%",
        top: -(this.state.dimension.height-this.state.borderWidth)/2 + "px"
      }):
      ({
        top: this.state.position.top + "%",
        left: -(this.state.dimension.width-this.state.borderWidth)/2 + "px"
      });

    return (

 this.componentInstance = ref}>

    );
  }
});

/*
*  LsdSliderRange React Component
*  States:
*
*  Props:
*
*  NOTE: LsdSliderRange must only be shown when there are more than 1 handle.
*/

var LsdSliderRange = React.createClass({
  render: function() {
    return (

    );
  }
});

/*
*  LsdSlider React Component
*  States:
*    position: [JSON object] {
*      top: [float]
*      left: [float]
*    orientation: [string]
*    }
*  Props:
*    width: [float] Used in normalization of mouse coords - horizontal.
*    height: [float] Used in normalization of mouse coords - vertical.
*    min: [float]
*    max: [float]
*    multiple: [integer] Determines the number of handles in the slider.
*
*  TODO: Fix handle offset computation when slider width is not 5px. uhmm. nvm
*        Do this instead, receive alignment prop with values:
*        left/top, middle, right/bottom. default is left/top.
*/
var LsdSlider = React.createClass({
  getInitialState: function() {
    return {
      position: {
        top: 0,
        left: 0
      },
      dimension: {
      	width: 0,
      	height: 0
      },
      orientation: ""
    };
  },
  componentWillMount: function() {
  	if(!(this.props.width || this.props.height)){
      console.error("Warning: LsdSlider's width and height properties are both null. Please declare at least one property.");
  	}

  	var correctWidth = parseInt(this.props.width) || 5;
  	var correctHeight = parseInt(this.props.height) || 5;

    /*
    *  Automatic orientation identification lmao.
    *  This state is passed to LsdSliderHandle.
    */
    var orientation = (correctWidth>correctHeight)?"x":"y";

    this.setState({
      dimension: {
      	width: correctWidth,
      	height: correctHeight
      },
      orientation: orientation
    });
  },
  componentDidMount: function() {
    /*
    *  Identify the position of this component after it has been rendered on
    *  the DOM. This state is passed to LsdSliderHandle.
    */
    var componentPosition = cumulativeOffset(this.componentInstance);

    this.setState({
      position: {
      	top: componentPosition.top,
        left: componentPosition.left
      }
    });
  },
  /*
  *  Normalization of mouse coordinates relative to the slider.
  */
  normalizeMouse: function(mouseCoords, handleDimension) {
    if(this.state.orientation == "x")
      return ((mouseCoords.x-this.state.position.left-handleDimension.width/2)/this.state.dimension.width)*100;
    else
      return ((mouseCoords.y-this.state.position.top-handleDimension.height/2)/this.state.dimension.height)*100;
  },
  /*
  *  Forces a threshold to the drag value to prevent handle from going
  *  outside the slider.
  */
  computeHandleOffset: function(handleDimension) {
    if(this.state.orientation == "x")
      return ((handleDimension.width/2)/this.state.dimension.width)*100;
    else
      return ((handleDimension.height/2)/this.state.dimension.height)*100;
  },
  applyThreshold: function(value) {
  	/*
  	*  Percentage only in here that's why min == 0 and max == 100.
  	*  Actual value with respect to the min/max parameters would be computed
  	*  somewhere else.
  	*/
    return (value<0)?0:((value>100)?100:value);
  },
  computeHandlePosition: function(mouseCoords, handleDimension) {
  	/*
  	*  NOTE: When adding support for min/max parameters, compute it here.
  	*/
    var realValue = this.normalizeMouse(mouseCoords, handleDimension);
    realValue = this.applyThreshold(realValue);

    var offsetValue = realValue-this.computeHandleOffset(handleDimension);

    return {realValue, offsetValue};
  },
  render: function() {
    /*
    *  Sets orientation based on dimension.
    *  By default, a slider's rail is 5px thick.
    *
    *  TODO:
    */
    var style = (this.state.orientation == "x")?
      ({width: this.props.width + "px", height: this.state.dimension.height + "px"}):
      ({height: this.props.height + "px", width: this.state.dimension.width + "px"});

    var handleCount = this.props.multiple || 1;
    var handles = [];
    var percentInterval = 100/(handleCount-1);

    for(var i=0; i<handleCount; i++){
      handles.push(
        <LsdSliderHandle
          key={i}
          computeHandlePosition={this.computeHandlePosition}
          computeHandleOffset={this.computeHandleOffset}
          orientation={this.state.orientation}
          initialValue={percentInterval*i}/>
      );
    }

    return (

 this.componentInstance = ref}> {/*Refs! Must be a pro.*/}
        <LsdSliderRange />
        {handles}

    );
  }
});

ReactDOM.render(
  <LsdSlider key="1" width="300" multiple="2" min="1" max="8"/>,
  document.getElementById('lsd-slider-1')
);

ReactDOM.render(
  <LsdSlider key="2" height="240"/>,
  document.getElementById('lsd-slider-2')
);<commit_msg>Slider handle values are now tracked by LsdSlider component.<commit_after>/*
*  Name: Labor Statistics Dashboard Custom Slider
*  Author: John Denielle Hernandez
*  Desc: Custom slider component similar to input of type range with some
*    additional features such as multiple values and automatic orientation
*    detection.
*/

/*
*  TODO: Configurable handles example
*
*  TODO: Apply prop validation
*/

/*
*  LsdSliderHandle React Component
*  States:
*    dragging:  [boolean] Needed to be checked if the handle needs to be moved
*               because the mouse listener is declared globally.
*    position:  [JSON object] {
*      top: [float] Changed when a vertical slider handle is being dragged.
*      left: [float] Changed when a horizontal slider handle is being dragged.
*    }
*    dimension:  [JSON object] Offset dimension of the handle. {
*	   width: [float] Obtained from offsetWidth HTML element property.
*      height: [float] Obtained from offsetHeight HTML element property.
*    }
*    borderWidth: [float] Used for offset
*  Props:
*    computeHandlePosition= [function] Used to get new position when dragging.
*    computeHandleOffset= [function] Uses the offset height/width of handle.
*    orientation: [string] "x" | "y" Determined by LsdSlider React Component.
*    initialValue: [float] Used to show multiple handles evenly distributed
*                  across the slider initially.
*/
var LsdSliderHandle = React.createClass({
  /*
  *  TODO: Fix warning -> "getInitialState was defined on LsdSlider, a plain
  *  JavaScript class. This is only supported for classes created using
  *  React.createClass. Did you mean to define a state property instead?".
  *
  *  TODO: Fix bug, resizing window breaks offset of handle in vertical slider.
  *  The horizontal slider seems to be clear of this bug.
  *
  *  TODO: Check if clientHeight/Width or scrollHeight/Width can replace the
  *        handle offset computation using the borderWidth state.
  *
  *  TODO: Refactor all code that relies on orientation. Eliminate redundancy.
  *
  *  TODO: Try Using ReactLink
  */
  getInitialState: function() {
    return {
      dragging: false,
      position: {
        top: 0,
        left: 0
      },
      dimension: {
        width: 0,
        height: 0
      },
      borderWidth: 0
    };
  },
  componentDidMount: function() {
  	/*
    *  Binding dragStart to mousedown should also be here but:
    *  onMouseDown > refs (by simplicity).
    *  Take note that I add the event listener to the document element because:
    *  1. The mousemove relies on the mouse's coordinates relative to the
    *     document, not the handle. Otherwise, the handle will move only if the
    *     mouse is moved inside the handle.
    *  2. If the mouse is released outside the handle, the drag will stop since
    *     the document, and not the handle, listens to that event.
    */
    document.addEventListener("mousemove", this.dragEvent);
    document.addEventListener("mouseup", this.dragStop);

    /*
  	*  Get the real value of the handle element. It factors in the width of the
  	*  border and padding.
  	*/
    var newDimension = {
      width: this.componentInstance.offsetWidth,
      height: this.componentInstance.offsetHeight
    };

    var handleOffset = this.props.computeHandleOffset(newDimension);

    var newPosition =
      (this.props.orientation == "x")?
        {
          top: -handleOffset,
          left: this.props.initialValue-handleOffset
        }:
        {
          top: this.props.initialValue-handleOffset,
          left: -handleOffset
        };

    this.setState({
      dimension: newDimension,
      position: newPosition,
      borderWidth: parseInt(getComputedStyle(this.componentInstance).getPropertyValue("border-width"))
    });
  },
  componentWillUnmount: function(){
  	document.removeEventListener("mousemove", this.dragEvent);
    document.removeEventListener("mouseup", this.dragStop);
  },
  dragStart: function() {
    this.setState ({
      dragging: true
    });
  },
  dragStop: function() {
    this.setState ({
      dragging: false
    });
  },
  dragEvent: function(event) {
    if (this.state.dragging) {
      /*
      *  Prevents the cursor to select elements while dragging the handle
      */
      if(event.stopPropagation) event.stopPropagation();
      if(event.preventDefault) event.preventDefault();

      var handlePos = this.props.computeHandlePosition(
        {
          x: event.pageX,
          y: event.pageY
        }, this.state.dimension);

      if(this.props.orientation == "x") {
        this.setState({
          position: {
            left: handlePos.offsetValue
          }
        });
      }
      else {
        this.setState({
          position: {
            top: handlePos.offsetValue
          }
        });
      }

      this.props.updateHandleValue(this.props.id, handlePos.realValue);
    }
  },
  render: function() {
    /*
  	*  The long computation is for centering the handle with respect to the
  	*  slider's orientation.
  	*/
    var style = (this.props.orientation == "x")?
      ({
        left: this.state.position.left + "%",
        top: -(this.state.dimension.height-this.state.borderWidth)/2 + "px"
      }):
      ({
        top: this.state.position.top + "%",
        left: -(this.state.dimension.width-this.state.borderWidth)/2 + "px"
      });

    return (

 this.componentInstance = ref}>

    );
  }
});

/*
*  LsdSliderRange React Component
*  States:
*
*  Props:
*
*  NOTE: LsdSliderRange must only be shown when there are more than 1 handle.
*/

var LsdSliderRange = React.createClass({
  render: function() {
    return (

    );
  }
});

/*
*  LsdSlider React Component
*  States:
*    position: [JSON object] {
*      top: [float]
*      left: [float]
*    orientation: [string]
*    }
*  Props:
*    width: [float] Used in normalization of mouse coords - horizontal.
*    height: [float] Used in normalization of mouse coords - vertical.
*    min: [float]
*    max: [float]
*    multiple: [integer] Determines the number of handles in the slider.
*
*  TODO: Fix handle offset computation when slider width is not 5px. uhmm. nvm
*        Do this instead, receive alignment prop with values:
*        left/top, middle, right/bottom. default is left/top.
*/
var LsdSlider = React.createClass({
  getInitialState: function() {
    return {
      position: {
        top: 0,
        left: 0
      },
      dimension: {
      	width: 0,
      	height: 0
      },
      orientation: "",
      values: []
    };
  },
  componentWillMount: function() {
  	if(!(this.props.width || this.props.height)){
      console.error("Warning: LsdSlider's width and height properties are both null. Please declare at least one property.");
  	}

  	var correctWidth = parseInt(this.props.width) || 5;
  	var correctHeight = parseInt(this.props.height) || 5;

    /*
    *  Computation for distributing multiple handles evenly along the slider.
    */
  	var handleCount = this.props.multiple || 1;
  	var percentInterval = (handleCount > 1)?100/(handleCount-1):0;
  	var values = [];

  	for(var i=0; i<handleCount; i++){
  		values.push(percentInterval*i);
  	}

    /*
    *  Automatic orientation identification lmao.
    *  This state is passed to LsdSliderHandle.
    */
    var orientation = (correctWidth>correctHeight)?"x":"y";

    this.setState({
      dimension: {
      	width: correctWidth,
      	height: correctHeight
      },
      orientation: orientation,
      handleCount: handleCount,
      values: values
    });
  },
  componentDidMount: function() {
    /*
    *  Identify the position of this component after it has been rendered on
    *  the DOM. This state is passed to LsdSliderHandle.
    */
    var componentPosition = cumulativeOffset(this.componentInstance);

    this.setState({
      position: {
      	top: componentPosition.top,
        left: componentPosition.left
      }
    });
  },
  /*
  *  Normalization of mouse coordinates relative to the slider.
  */
  normalizeMouse: function(mouseCoords, handleDimension) {
    if(this.state.orientation == "x")
      return ((mouseCoords.x-this.state.position.left-handleDimension.width/2)/this.state.dimension.width)*100;
    else
      return ((mouseCoords.y-this.state.position.top-handleDimension.height/2)/this.state.dimension.height)*100;
  },
  /*
  *  Forces a threshold to the drag value to prevent handle from going
  *  outside the slider.
  */
  computeHandleOffset: function(handleDimension) {
    if(this.state.orientation == "x")
      return ((handleDimension.width/2)/this.state.dimension.width)*100;
    else
      return ((handleDimension.height/2)/this.state.dimension.height)*100;
  },
  applyThreshold: function(value) {
  	/*
  	*  Percentage only in here that's why min == 0 and max == 100.
  	*  Actual value with respect to the min/max parameters would be computed
  	*  somewhere else.
  	*/
    return (value<0)?0:((value>100)?100:value);
  },
  computeHandlePosition: function(mouseCoords, handleDimension) {
  	/*
  	*  NOTE: When adding support for min/max parameters, compute it here.
  	*/
    var realValue = this.normalizeMouse(mouseCoords, handleDimension);
    realValue = this.applyThreshold(realValue);

    var offsetValue = realValue-this.computeHandleOffset(handleDimension);

    return {realValue, offsetValue};
  },
  updateHandleValue: function(handleId, value) {
  	var values = this.state.values;

  	values[handleId] = value;

  	this.setState({
  	  values: values
  	});
  },
  render: function() {
    /*
    *  Sets orientation based on dimension.
    *  By default, a slider's rail is 5px thick.
    *
    *  TODO:
    */
    var style = (this.state.orientation == "x")?
      ({width: this.props.width + "px", height: this.state.dimension.height + "px"}):
      ({height: this.props.height + "px", width: this.state.dimension.width + "px"});

    var handles = [];

    console.log(this.state.values);

    for(var i=0; i<this.state.handleCount; i++){
      handles.push(
        <LsdSliderHandle
          key={i}
          id={i}
          computeHandlePosition={this.computeHandlePosition}
          computeHandleOffset={this.computeHandleOffset}
          orientation={this.state.orientation}
          initialValue={this.state.values[i]}
          updateHandleValue={this.updateHandleValue}/>
      );
    }

    return (

 this.componentInstance = ref}> {/*Refs! Must be a pro.*/}
        <LsdSliderRange />
        {handles}

    );
  }
});

ReactDOM.render(
  <LsdSlider key="1" width="300" multiple="2" min="1" max="8"/>,
  document.getElementById('lsd-slider-1')
);

ReactDOM.render(
  <LsdSlider key="2" height="240"/>,
  document.getElementById('lsd-slider-2')
);<|endoftext|>