<commit_before>define('app/views/backend_add', [
    'app/models/backend',
    'text!app/templates/backend_add.html',
    'ember'],
    /**
     *
     * Add Backend Dialog
     *
     * @returns Class
     */
    function(Backend, backend_add_html) {

        return Ember.View.extend({

            template: Ember.Handlebars.compile(backend_add_html),

            pendingCreation: false,

            pendingCreationObserver: function() {
                if (this.pendingCreation) {
                    $('#create-backend-ok').addClass('ui-disabled');
                } else {
                    $('#create-backend-ok').removeClass('ui-disabled');
                }
            }.observes('pendingCreation'),

            keyDown: function(event) {
                if (event.keyCode == 13) { // Enter
                    if (event.preventDefault) {
                        event.preventDefault();
                    }
                    if (Mist.backendAddController.newBackendReady) {
                        warn('yeay!');
                        this.addButtonClick();
                    }
                } else if (event.keyCode == 27) { // Esc
                    this.backClicked();
                }
            },

            selectBackend: function(event) {
                if (event.target.title.indexOf("rackspace") != -1 || event.target.title.indexOf("linode") != -1 || event.target.title.indexOf("softlayer") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. API Key:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("nephoscale") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. Password:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("digitalocean") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Client ID:');
                    $('#ApiSecretlabel').text('3. API Key:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("openstack") != -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. Password:');
                    $('#addBackendOpenstack').show();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("bare_metal") != -1) {
                    $('#addBackendInfo').hide();
                    $('#addBackendBareMetal').show();
                    $('#addBackendOpenstack').hide();
                } else {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. API Key:');
                    $('#ApiSecretlabel').text('3. API Secret:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                }
                $('.select-backend-collapsible').collapsible('option','collapsedIcon','check');
                $('.select-backend-collapsible span.ui-btn-text').text(event.target.text);
                Mist.backendAddController.set('newBackendProvider',
                    {provider: $(event.target).attr('title'),
                     title: event.target.text
                    }
                );
                $('.select-backend-collapsible').trigger('collapse');

                Mist.backendAddController.set('newBackendKey', '');
                Mist.backendAddController.set('newBackendSecret', '');
                /* OpenStack support
                Mist.backendAddController.set('newBackendUrl', '');
                Mist.backendAddController.set('newBackendTenant', '');
                */
                for (var b = 0; b < Mist.backendsController.content.length; b++) {
                    var backend = Mist.backendsController.content[b];
                    if (event.target.title.split('_')[0] == 'ec2' && backend.provider.split('_')[0] == 'ec2') {
                        //Autocomplete
                        Mist.backendAddController.set('newBackendKey', backend.apikey);
                        Mist.backendAddController.set('newBackendSecret', 'getsecretfromdb');
                        break;
                    } else if (event.target.title.substr(0,9) == 'rackspace' && backend.provider.substr(0,9) == 'rackspace') {
                        Mist.backendAddController.set('newBackendKey', backend.apikey);
                        Mist.backendAddController.set('newBackendSecret', 'getsecretfromdb');
                        break;
                    }
                }
            },

            addBackend: function() {
                $('.select-listmenu li').on('click', this.selectBackend);
                $('#add-backend').panel('open');
            },

            addKey: function() {
                $('.select-key-listmenu li').on('click', this.selectKey);
            },

            selectKey: function(key){
                $('.select-key-collapsible').collapsible('option','collapsedIcon','check');
                $('.select-key-collapsible span.ui-btn-text').text(key.name);
                Mist.backendAddController.set('newBareServerKey', key.name);
                $('.select-key-collapsible').trigger('collapse');
            },

            backClicked: function() {
                $("#add-backend").panel("close");
                $('.select-listmenu li').off('click', this.selectBackend);
                Mist.backendAddController.newBackendClear();
            },

            addButtonClick: function() {
                var that = this;
                that.set('pendingCreation', true);
                var payload = {
                    "title": Mist.backendAddController.newBackendProvider.title,
                    "provider": Mist.backendAddController.newBackendProvider.provider,
                    "apikey" : Mist.backendAddController.newBackendKey,
                    "apisecret": Mist.backendAddController.newBackendSecret,
                    "apiurl": Mist.backendAddController.newBackendUrl,
                    "tenant_name": Mist.backendAddController.newBackendTenant,
                    "machine_name": Mist.backendAddController.newBareServerName,
                    "machine_ip_address": Mist.backendAddController.newBareServeIp,
                    "machine_key": Mist.backendAddController.newBareServerKey,
                    "machine_user": Mist.backendAddController.newBareServerUser
                };
                $.ajax({
                    url: '/backends',
                    type: "POST",
                    contentType: "application/json",
                    dataType: "json",
                    headers: { "cache-control": "no-cache" },
                    data: JSON.stringify(payload),
                    success: function(result) {
                        that.set('pendingCreation', false);
                        Mist.backendAddController.newBackendClear();
                        $("#add-backend").panel("close");
                        $('.select-listmenu li').off('click', this.selectBackend);
                        info('added backend ' + result.id);

                        if (result.provider == 'bare_metal') {
                            if (!result.exists) {
                                Mist.backendsController.pushObject(Backend.create(result));
                            }
                            Ember.run.later(function() {
                                //Mist.backendsController.getBackendById(result.id).machines.refresh();
                                $('#home-menu li').eq(0).find('a').click(); // Manually click machines button
                            }, 500);
                        } else {
                            Mist.backendsController.pushObject(Backend.create(result));
                        }
                    },
                    error: function(request){
                        that.set('pendingCreation', false);
                        Mist.notificationController.notify(request.responseText);
                    }
                });
            },

            createBareMetalKeyClicked: function() {
                $('#create-key-dialog').popup('open');
            },

            providerList: function() {
                return SUPPORTED_PROVIDERS;
            }.property('providerList')
        });
    }
);
<commit_msg>refresh machines on bare metal add<commit_after>define('app/views/backend_add', [
    'app/models/backend',
    'text!app/templates/backend_add.html',
    'ember'],
    /**
     *
     * Add Backend Dialog
     *
     * @returns Class
     */
    function(Backend, backend_add_html) {

        return Ember.View.extend({

            template: Ember.Handlebars.compile(backend_add_html),

            pendingCreation: false,

            pendingCreationObserver: function() {
                if (this.pendingCreation) {
                    $('#create-backend-ok').addClass('ui-disabled');
                } else {
                    $('#create-backend-ok').removeClass('ui-disabled');
                }
            }.observes('pendingCreation'),

            keyDown: function(event) {
                if (event.keyCode == 13) { // Enter
                    if (event.preventDefault) {
                        event.preventDefault();
                    }
                    if (Mist.backendAddController.newBackendReady) {
                        warn('yeay!');
                        this.addButtonClick();
                    }
                } else if (event.keyCode == 27) { // Esc
                    this.backClicked();
                }
            },

            selectBackend: function(event) {
                if (event.target.title.indexOf("rackspace") != -1 || event.target.title.indexOf("linode") != -1 || event.target.title.indexOf("softlayer") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. API Key:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("nephoscale") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. Password:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("digitalocean") !== -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Client ID:');
                    $('#ApiSecretlabel').text('3. API Key:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("openstack") != -1) {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. Username:');
                    $('#ApiSecretlabel').text('3. Password:');
                    $('#addBackendOpenstack').show();
                    $('#addBackendBareMetal').hide();
                } else if (event.target.title.indexOf("bare_metal") != -1) {
                    $('#addBackendInfo').hide();
                    $('#addBackendBareMetal').show();
                    $('#addBackendOpenstack').hide();
                } else {
                    $('#addBackendInfo').show();
                    $('#ApiKeylabel').text('2. API Key:');
                    $('#ApiSecretlabel').text('3. API Secret:');
                    $('#addBackendOpenstack').hide();
                    $('#addBackendBareMetal').hide();
                }
                $('.select-backend-collapsible').collapsible('option','collapsedIcon','check');
                $('.select-backend-collapsible span.ui-btn-text').text(event.target.text);
                Mist.backendAddController.set('newBackendProvider',
                    {provider: $(event.target).attr('title'),
                     title: event.target.text
                    }
                );
                $('.select-backend-collapsible').trigger('collapse');

                Mist.backendAddController.set('newBackendKey', '');
                Mist.backendAddController.set('newBackendSecret', '');
                /* OpenStack support
                Mist.backendAddController.set('newBackendUrl', '');
                Mist.backendAddController.set('newBackendTenant', '');
                */
                for (var b = 0; b < Mist.backendsController.content.length; b++) {
                    var backend = Mist.backendsController.content[b];
                    if (event.target.title.split('_')[0] == 'ec2' && backend.provider.split('_')[0] == 'ec2') {
                        //Autocomplete
                        Mist.backendAddController.set('newBackendKey', backend.apikey);
                        Mist.backendAddController.set('newBackendSecret', 'getsecretfromdb');
                        break;
                    } else if (event.target.title.substr(0,9) == 'rackspace' && backend.provider.substr(0,9) == 'rackspace') {
                        Mist.backendAddController.set('newBackendKey', backend.apikey);
                        Mist.backendAddController.set('newBackendSecret', 'getsecretfromdb');
                        break;
                    }
                }
            },

            addBackend: function() {
                $('.select-listmenu li').on('click', this.selectBackend);
                $('#add-backend').panel('open');
            },

            addKey: function() {
                $('.select-key-listmenu li').on('click', this.selectKey);
            },

            selectKey: function(key){
                $('.select-key-collapsible').collapsible('option','collapsedIcon','check');
                $('.select-key-collapsible span.ui-btn-text').text(key.name);
                Mist.backendAddController.set('newBareServerKey', key.name);
                $('.select-key-collapsible').trigger('collapse');
            },

            backClicked: function() {
                $("#add-backend").panel("close");
                $('.select-listmenu li').off('click', this.selectBackend);
                Mist.backendAddController.newBackendClear();
            },

            addButtonClick: function() {
                var that = this;
                that.set('pendingCreation', true);
                var payload = {
                    "title": Mist.backendAddController.newBackendProvider.title,
                    "provider": Mist.backendAddController.newBackendProvider.provider,
                    "apikey" : Mist.backendAddController.newBackendKey,
                    "apisecret": Mist.backendAddController.newBackendSecret,
                    "apiurl": Mist.backendAddController.newBackendUrl,
                    "tenant_name": Mist.backendAddController.newBackendTenant,
                    "machine_name": Mist.backendAddController.newBareServerName,
                    "machine_ip_address": Mist.backendAddController.newBareServeIp,
                    "machine_key": Mist.backendAddController.newBareServerKey,
                    "machine_user": Mist.backendAddController.newBareServerUser
                };
                $.ajax({
                    url: '/backends',
                    type: "POST",
                    contentType: "application/json",
                    dataType: "json",
                    headers: { "cache-control": "no-cache" },
                    data: JSON.stringify(payload),
                    success: function(result) {
                        that.set('pendingCreation', false);
                        Mist.backendAddController.newBackendClear();
                        $("#add-backend").panel("close");
                        $('.select-listmenu li').off('click', this.selectBackend);
                        info('added backend ' + result.id);

                        if (result.provider == 'bare_metal') {
                            if (!result.exists) {
                                Mist.backendsController.pushObject(Backend.create(result));
                            }
                            Ember.run.later(function() {
                                Mist.backendsController.getBackendById(result.id).machines.refresh();
                                $('#home-menu li').eq(0).find('a').click(); // Manually click machines button
                            }, 500);
                        } else {
                            Mist.backendsController.pushObject(Backend.create(result));
                        }
                    },
                    error: function(request){
                        that.set('pendingCreation', false);
                        Mist.notificationController.notify(request.responseText);
                    }
                });
            },

            createBareMetalKeyClicked: function() {
                $('#create-key-dialog').popup('open');
            },

            providerList: function() {
                return SUPPORTED_PROVIDERS;
            }.property('providerList')
        });
    }
);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ScrollView
 * @flow
 */
'use strict';

var EdgeInsetsPropType = require('EdgeInsetsPropType');
var Platform = require('Platform');
var PointPropType = require('PointPropType');
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
var RCTScrollViewConsts = RCTScrollView.Constants;
var React = require('React');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTUIManager = require('NativeModules').UIManager;
var ScrollResponder = require('ScrollResponder');
var StyleSheet = require('StyleSheet');
var StyleSheetPropType = require('StyleSheetPropType');
var View = require('View');
var ViewStylePropTypes = require('ViewStylePropTypes');

var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var flattenStyle = require('flattenStyle');
var insetsDiffer = require('insetsDiffer');
var invariant = require('invariant');
var pointsDiffer = require('pointsDiffer');
var requireNativeComponent = require('requireNativeComponent');

var PropTypes = React.PropTypes;

var SCROLLVIEW = 'ScrollView';
var INNERVIEW = 'InnerScrollView';

/**
 * Component that wraps platform ScrollView while providing
 * integration with touch locking "responder" system.
 *
 * Doesn't yet support other contained responders from blocking this scroll
 * view from becoming the responder.
 */

var ScrollView = React.createClass({
  propTypes: {
    automaticallyAdjustContentInsets: PropTypes.bool, // true
    contentInset: EdgeInsetsPropType, // zeros
    contentOffset: PointPropType, // zeros
    onScroll: PropTypes.func,
    onScrollAnimationEnd: PropTypes.func,
    scrollEnabled: PropTypes.bool, // true
    scrollIndicatorInsets: EdgeInsetsPropType, // zeros
    showsHorizontalScrollIndicator: PropTypes.bool,
    showsVerticalScrollIndicator: PropTypes.bool,
    style: StyleSheetPropType(ViewStylePropTypes),
    scrollEventThrottle: PropTypes.number, // null

    /**
     * When true, the scroll view bounces when it reaches the end of the
     * content if the content is larger then the scroll view along the axis of
     * the scroll direction. When false, it disables all bouncing even if
     * the `alwaysBounce*` props are true. The default value is true.
     */
    bounces: PropTypes.bool,
    /**
     * When true, gestures can drive zoom past min/max and the zoom will animate
     * to the min/max value at gesture end, otherwise the zoom will not exceed
     * the limits.
     */
    bouncesZoom: PropTypes.bool,
    /**
     * When true, the scroll view bounces horizontally when it reaches the end
     * even if the content is smaller than the scroll view itself. The default
     * value is true when `horizontal={true}` and false otherwise.
     */
    alwaysBounceHorizontal: PropTypes.bool,
    /**
     * When true, the scroll view bounces vertically when it reaches the end
     * even if the content is smaller than the scroll view itself. The default
     * value is false when `horizontal={true}` and true otherwise.
     */
    alwaysBounceVertical: PropTypes.bool,
    /**
     * When true, the scroll view automatically centers the content when the
     * content is smaller than the scroll view bounds; when the content is
     * larger than the scroll view, this property has no effect. The default
     * value is false.
     */
    centerContent: PropTypes.bool,
    /**
     * These styles will be applied to the scroll view content container which
     * wraps all of the child views. Example:
     *
     *   return (
     *     <ScrollView contentContainerStyle={styles.contentContainer}>
     *     </ScrollView>
     *   );
     *   ...
     *   var styles = StyleSheet.create({
     *     contentContainer: {
     *       paddingVertical: 20
     *     }
     *   });
     */
    contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
    /**
     * A floating-point number that determines how quickly the scroll view
     * decelerates after the user lifts their finger. Reasonable choices include
     *   - Normal: 0.998 (the default)
     *   - Fast: 0.9
     */
    decelerationRate: PropTypes.number,
    /**
     * When true, the scroll view's children are arranged horizontally in a row
     * instead of vertically in a column. The default value is false.
     */
    horizontal: PropTypes.bool,
    /**
     * When true, the ScrollView will try to lock to only vertical or horizontal
     * scrolling while dragging.  The default value is false.
     */
    directionalLockEnabled: PropTypes.bool,
    /**
     * When false, once tracking starts, won't try to drag if the touch moves.
     * The default value is true.
     */
    canCancelContentTouches: PropTypes.bool,
    /**
     * Determines whether the keyboard gets dismissed in response to a drag.
     *   - 'none' (the default), drags do not dismiss the keyboard.
     *   - 'onDrag', the keyboard is dismissed when a drag begins.
     *   - 'interactive', the keyboard is dismissed interactively with the drag
     *     and moves in synchrony with the touch; dragging upwards cancels the
     *     dismissal.
     */
    keyboardDismissMode: PropTypes.oneOf([
      'none', // default
      'interactive',
      'on-drag',
    ]),
    /**
     * When false, tapping outside of the focused text input when the keyboard
     * is up dismisses the keyboard. When true, the scroll view will not catch
     * taps, and the keyboard will not dismiss automatically. The default value
     * is false.
     */
    keyboardShouldPersistTaps: PropTypes.bool,
    /**
     * The maximum allowed zoom scale. The default value is 1.0.
     */
    maximumZoomScale: PropTypes.number,
    /**
     * The minimum allowed zoom scale. The default value is 1.0.
     */
    minimumZoomScale: PropTypes.number,
    /**
     * When true, the scroll view stops on multiples of the scroll view's size
     * when scrolling. This can be used for horizontal pagination. The default
     * value is false.
     */
    pagingEnabled: PropTypes.bool,
    /**
     * When true, the scroll view scrolls to top when the status bar is tapped.
     * The default value is true.
     */
    scrollsToTop: PropTypes.bool,
    /**
     * An array of child indices determining which children get docked to the
     * top of the screen when scrolling. For example, passing
     * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
     * top of the scroll view. This property is not supported in conjunction
     * with `horizontal={true}`.
     */
    stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
    /**
     * Experimental: When true, offscreen child views (whose `overflow` value is
     * `hidden`) are removed from their native backing superview when offscreen.
     * This can improve scrolling performance on long lists. The default value is
     * false.
     */
    removeClippedSubviews: PropTypes.bool,
    /**
     * The current scale of the scroll view content. The default value is 1.0.
     */
    zoomScale: PropTypes.number,
  },

  mixins: [ScrollResponder.Mixin],

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

  setNativeProps: function(props: Object) {
    this.refs[SCROLLVIEW].setNativeProps(props);
  },

  getInnerViewNode: function(): any {
    return React.findNodeHandle(this.refs[INNERVIEW]);
  },

  scrollTo: function(destY?: number, destX?: number) {
    if (Platform.OS === 'android') {
      RCTUIManager.dispatchViewManagerCommand(
        React.findNodeHandle(this),
        RCTUIManager.RCTScrollView.Commands.scrollTo,
        [destX || 0, destY || 0]
      );
    } else {
      RCTUIManager.scrollTo(
        React.findNodeHandle(this),
        destX || 0,
        destY || 0
      );
    }
  },

  scrollWithoutAnimationTo: function(destY?: number, destX?: number) {
    RCTUIManager.scrollWithoutAnimationTo(
      React.findNodeHandle(this),
      destX || 0,
      destY || 0
    );
  },

  render: function() {
    var contentContainerStyle = [
      this.props.horizontal && styles.contentContainerHorizontal,
      this.props.contentContainerStyle,
    ];
    if (__DEV__ && this.props.style) {
      var style = flattenStyle(this.props.style);
      var childLayoutProps = ['alignItems', 'justifyContent']
        .filter((prop) => style && style[prop] !== undefined);
      invariant(
        childLayoutProps.length === 0,
        'ScrollView child layout (' + JSON.stringify(childLayoutProps) +
          ') must by applied through the contentContainerStyle prop.'
      );
    }
    if (__DEV__) {
      if (this.props.onScroll && !this.props.scrollEventThrottle) {
        var onScroll = this.props.onScroll;
        this.props.onScroll = function() {
          console.log(
            'You specified `onScroll` on a <ScrollView> but not ' +
            '`scrollEventThrottle`. You will only receive one event. ' +
            'Using `16` you get all the events but be aware that it may ' +
            'cause frame drops, use a bigger number if you don\'t need as ' +
            'much precision.'
          );
          onScroll.apply(this, arguments);
        };
      }
    }

    var contentContainer =
      <View
        ref={INNERVIEW}
        style={contentContainerStyle}
        removeClippedSubviews={this.props.removeClippedSubviews}>
        {this.props.children}
      </View>;

    var alwaysBounceHorizontal =
      this.props.alwaysBounceHorizontal !== undefined ?
        this.props.alwaysBounceHorizontal :
        this.props.horizontal;

    var alwaysBounceVertical =
      this.props.alwaysBounceVertical !== undefined ?
        this.props.alwaysBounceVertical :
        !this.props.horizontal;

    var props = {
      ...this.props,
      alwaysBounceHorizontal,
      alwaysBounceVertical,
      style: ([styles.base, this.props.style]: ?Array<any>),
      onTouchStart: this.scrollResponderHandleTouchStart,
      onTouchMove: this.scrollResponderHandleTouchMove,
      onTouchEnd: this.scrollResponderHandleTouchEnd,
      onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
      onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
      onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
      onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
      onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
      onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
      onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
      onScroll: this.scrollResponderHandleScroll,
      onResponderGrant: this.scrollResponderHandleResponderGrant,
      onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
      onResponderTerminate: this.scrollResponderHandleTerminate,
      onResponderRelease: this.scrollResponderHandleResponderRelease,
      onResponderReject: this.scrollResponderHandleResponderReject,
    };

    var ScrollViewClass;
    if (Platform.OS === 'ios') {
      ScrollViewClass = RCTScrollView;
    } else if (Platform.OS === 'android') {
      if (this.props.horizontal) {
        ScrollViewClass = AndroidHorizontalScrollView;
      } else {
        ScrollViewClass = AndroidScrollView;
      }
      var keyboardDismissModeConstants = {
        'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
        'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
        'on-drag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
      };
      props.keyboardDismissMode = props.keyboardDismissMode ?
        keyboardDismissModeConstants[props.keyboardDismissMode] : undefined;
    }
    invariant(
      ScrollViewClass !== undefined,
      'ScrollViewClass must not be undefined'
    );

    return (
      <ScrollViewClass {...props} ref={SCROLLVIEW}>
        {contentContainer}
      </ScrollViewClass>
    );
  }
});

var styles = StyleSheet.create({
  base: {
    flex: 1,
  },
  contentContainerHorizontal: {
    alignSelf: 'flex-start',
    flexDirection: 'row',
  },
});

var validAttributes = {
  ...ReactNativeViewAttributes.UIView,
  alwaysBounceHorizontal: true,
  alwaysBounceVertical: true,
  automaticallyAdjustContentInsets: true,
  bounces: true,
  centerContent: true,
  contentInset: {diff: insetsDiffer},
  contentOffset: {diff: pointsDiffer},
  decelerationRate: true,
  horizontal: true,
  keyboardDismissMode: true,
  keyboardShouldPersistTaps: true,
  maximumZoomScale: true,
  minimumZoomScale: true,
  pagingEnabled: true,
  removeClippedSubviews: true,
  scrollEnabled: true,
  scrollIndicatorInsets: {diff: insetsDiffer},
  scrollsToTop: true,
  showsHorizontalScrollIndicator: true,
  showsVerticalScrollIndicator: true,
  stickyHeaderIndices: {diff: deepDiffer},
  scrollEventThrottle: true,
  zoomScale: true,
};

if (Platform.OS === 'android') {
  var AndroidScrollView = createReactNativeComponentClass({
    validAttributes: validAttributes,
    uiViewClassName: 'RCTScrollView',
  });
  var AndroidHorizontalScrollView = createReactNativeComponentClass({
    validAttributes: validAttributes,
    uiViewClassName: 'AndroidHorizontalScrollView',
  });
} else if (Platform.OS === 'ios') {
  var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
}

module.exports = ScrollView;
<commit_msg>[Idea: ScrollView] Add `getScrollResponder` to ScrollView for composition<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ScrollView
 * @flow
 */
'use strict';

var EdgeInsetsPropType = require('EdgeInsetsPropType');
var Platform = require('Platform');
var PointPropType = require('PointPropType');
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
var RCTScrollViewConsts = RCTScrollView.Constants;
var React = require('React');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTUIManager = require('NativeModules').UIManager;
var ScrollResponder = require('ScrollResponder');
var StyleSheet = require('StyleSheet');
var StyleSheetPropType = require('StyleSheetPropType');
var View = require('View');
var ViewStylePropTypes = require('ViewStylePropTypes');

var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var flattenStyle = require('flattenStyle');
var insetsDiffer = require('insetsDiffer');
var invariant = require('invariant');
var pointsDiffer = require('pointsDiffer');
var requireNativeComponent = require('requireNativeComponent');

var PropTypes = React.PropTypes;

var SCROLLVIEW = 'ScrollView';
var INNERVIEW = 'InnerScrollView';

/**
 * Component that wraps platform ScrollView while providing
 * integration with touch locking "responder" system.
 *
 * Doesn't yet support other contained responders from blocking this scroll
 * view from becoming the responder.
 */

var ScrollView = React.createClass({
  propTypes: {
    automaticallyAdjustContentInsets: PropTypes.bool, // true
    contentInset: EdgeInsetsPropType, // zeros
    contentOffset: PointPropType, // zeros
    onScroll: PropTypes.func,
    onScrollAnimationEnd: PropTypes.func,
    scrollEnabled: PropTypes.bool, // true
    scrollIndicatorInsets: EdgeInsetsPropType, // zeros
    showsHorizontalScrollIndicator: PropTypes.bool,
    showsVerticalScrollIndicator: PropTypes.bool,
    style: StyleSheetPropType(ViewStylePropTypes),
    scrollEventThrottle: PropTypes.number, // null

    /**
     * When true, the scroll view bounces when it reaches the end of the
     * content if the content is larger then the scroll view along the axis of
     * the scroll direction. When false, it disables all bouncing even if
     * the `alwaysBounce*` props are true. The default value is true.
     */
    bounces: PropTypes.bool,
    /**
     * When true, gestures can drive zoom past min/max and the zoom will animate
     * to the min/max value at gesture end, otherwise the zoom will not exceed
     * the limits.
     */
    bouncesZoom: PropTypes.bool,
    /**
     * When true, the scroll view bounces horizontally when it reaches the end
     * even if the content is smaller than the scroll view itself. The default
     * value is true when `horizontal={true}` and false otherwise.
     */
    alwaysBounceHorizontal: PropTypes.bool,
    /**
     * When true, the scroll view bounces vertically when it reaches the end
     * even if the content is smaller than the scroll view itself. The default
     * value is false when `horizontal={true}` and true otherwise.
     */
    alwaysBounceVertical: PropTypes.bool,
    /**
     * When true, the scroll view automatically centers the content when the
     * content is smaller than the scroll view bounds; when the content is
     * larger than the scroll view, this property has no effect. The default
     * value is false.
     */
    centerContent: PropTypes.bool,
    /**
     * These styles will be applied to the scroll view content container which
     * wraps all of the child views. Example:
     *
     *   return (
     *     <ScrollView contentContainerStyle={styles.contentContainer}>
     *     </ScrollView>
     *   );
     *   ...
     *   var styles = StyleSheet.create({
     *     contentContainer: {
     *       paddingVertical: 20
     *     }
     *   });
     */
    contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
    /**
     * A floating-point number that determines how quickly the scroll view
     * decelerates after the user lifts their finger. Reasonable choices include
     *   - Normal: 0.998 (the default)
     *   - Fast: 0.9
     */
    decelerationRate: PropTypes.number,
    /**
     * When true, the scroll view's children are arranged horizontally in a row
     * instead of vertically in a column. The default value is false.
     */
    horizontal: PropTypes.bool,
    /**
     * When true, the ScrollView will try to lock to only vertical or horizontal
     * scrolling while dragging.  The default value is false.
     */
    directionalLockEnabled: PropTypes.bool,
    /**
     * When false, once tracking starts, won't try to drag if the touch moves.
     * The default value is true.
     */
    canCancelContentTouches: PropTypes.bool,
    /**
     * Determines whether the keyboard gets dismissed in response to a drag.
     *   - 'none' (the default), drags do not dismiss the keyboard.
     *   - 'onDrag', the keyboard is dismissed when a drag begins.
     *   - 'interactive', the keyboard is dismissed interactively with the drag
     *     and moves in synchrony with the touch; dragging upwards cancels the
     *     dismissal.
     */
    keyboardDismissMode: PropTypes.oneOf([
      'none', // default
      'interactive',
      'on-drag',
    ]),
    /**
     * When false, tapping outside of the focused text input when the keyboard
     * is up dismisses the keyboard. When true, the scroll view will not catch
     * taps, and the keyboard will not dismiss automatically. The default value
     * is false.
     */
    keyboardShouldPersistTaps: PropTypes.bool,
    /**
     * The maximum allowed zoom scale. The default value is 1.0.
     */
    maximumZoomScale: PropTypes.number,
    /**
     * The minimum allowed zoom scale. The default value is 1.0.
     */
    minimumZoomScale: PropTypes.number,
    /**
     * When true, the scroll view stops on multiples of the scroll view's size
     * when scrolling. This can be used for horizontal pagination. The default
     * value is false.
     */
    pagingEnabled: PropTypes.bool,
    /**
     * When true, the scroll view scrolls to top when the status bar is tapped.
     * The default value is true.
     */
    scrollsToTop: PropTypes.bool,
    /**
     * An array of child indices determining which children get docked to the
     * top of the screen when scrolling. For example, passing
     * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
     * top of the scroll view. This property is not supported in conjunction
     * with `horizontal={true}`.
     */
    stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
    /**
     * Experimental: When true, offscreen child views (whose `overflow` value is
     * `hidden`) are removed from their native backing superview when offscreen.
     * This can improve scrolling performance on long lists. The default value is
     * false.
     */
    removeClippedSubviews: PropTypes.bool,
    /**
     * The current scale of the scroll view content. The default value is 1.0.
     */
    zoomScale: PropTypes.number,
  },

  mixins: [ScrollResponder.Mixin],

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

  setNativeProps: function(props: Object) {
    this.refs[SCROLLVIEW].setNativeProps(props);
  },

  /**
   * Returns a reference to the underlying scroll responder, which supports
   * operations like `scrollTo`. All ScrollView-like components should
   * implement this method so that they can be composed while providing access
   * to the underlying scroll responder's methods.
   */
  getScrollResponder: function(): ReactComponent {
    return this;
  },

  getInnerViewNode: function(): any {
    return React.findNodeHandle(this.refs[INNERVIEW]);
  },

  scrollTo: function(destY?: number, destX?: number) {
    if (Platform.OS === 'android') {
      RCTUIManager.dispatchViewManagerCommand(
        React.findNodeHandle(this),
        RCTUIManager.RCTScrollView.Commands.scrollTo,
        [destX || 0, destY || 0]
      );
    } else {
      RCTUIManager.scrollTo(
        React.findNodeHandle(this),
        destX || 0,
        destY || 0
      );
    }
  },

  scrollWithoutAnimationTo: function(destY?: number, destX?: number) {
    RCTUIManager.scrollWithoutAnimationTo(
      React.findNodeHandle(this),
      destX || 0,
      destY || 0
    );
  },

  render: function() {
    var contentContainerStyle = [
      this.props.horizontal && styles.contentContainerHorizontal,
      this.props.contentContainerStyle,
    ];
    if (__DEV__ && this.props.style) {
      var style = flattenStyle(this.props.style);
      var childLayoutProps = ['alignItems', 'justifyContent']
        .filter((prop) => style && style[prop] !== undefined);
      invariant(
        childLayoutProps.length === 0,
        'ScrollView child layout (' + JSON.stringify(childLayoutProps) +
          ') must by applied through the contentContainerStyle prop.'
      );
    }
    if (__DEV__) {
      if (this.props.onScroll && !this.props.scrollEventThrottle) {
        var onScroll = this.props.onScroll;
        this.props.onScroll = function() {
          console.log(
            'You specified `onScroll` on a <ScrollView> but not ' +
            '`scrollEventThrottle`. You will only receive one event. ' +
            'Using `16` you get all the events but be aware that it may ' +
            'cause frame drops, use a bigger number if you don\'t need as ' +
            'much precision.'
          );
          onScroll.apply(this, arguments);
        };
      }
    }

    var contentContainer =
      <View
        ref={INNERVIEW}
        style={contentContainerStyle}
        removeClippedSubviews={this.props.removeClippedSubviews}>
        {this.props.children}
      </View>;

    var alwaysBounceHorizontal =
      this.props.alwaysBounceHorizontal !== undefined ?
        this.props.alwaysBounceHorizontal :
        this.props.horizontal;

    var alwaysBounceVertical =
      this.props.alwaysBounceVertical !== undefined ?
        this.props.alwaysBounceVertical :
        !this.props.horizontal;

    var props = {
      ...this.props,
      alwaysBounceHorizontal,
      alwaysBounceVertical,
      style: ([styles.base, this.props.style]: ?Array<any>),
      onTouchStart: this.scrollResponderHandleTouchStart,
      onTouchMove: this.scrollResponderHandleTouchMove,
      onTouchEnd: this.scrollResponderHandleTouchEnd,
      onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
      onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
      onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
      onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
      onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
      onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
      onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
      onScroll: this.scrollResponderHandleScroll,
      onResponderGrant: this.scrollResponderHandleResponderGrant,
      onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
      onResponderTerminate: this.scrollResponderHandleTerminate,
      onResponderRelease: this.scrollResponderHandleResponderRelease,
      onResponderReject: this.scrollResponderHandleResponderReject,
    };

    var ScrollViewClass;
    if (Platform.OS === 'ios') {
      ScrollViewClass = RCTScrollView;
    } else if (Platform.OS === 'android') {
      if (this.props.horizontal) {
        ScrollViewClass = AndroidHorizontalScrollView;
      } else {
        ScrollViewClass = AndroidScrollView;
      }
      var keyboardDismissModeConstants = {
        'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
        'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
        'on-drag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
      };
      props.keyboardDismissMode = props.keyboardDismissMode ?
        keyboardDismissModeConstants[props.keyboardDismissMode] : undefined;
    }
    invariant(
      ScrollViewClass !== undefined,
      'ScrollViewClass must not be undefined'
    );

    return (
      <ScrollViewClass {...props} ref={SCROLLVIEW}>
        {contentContainer}
      </ScrollViewClass>
    );
  }
});

var styles = StyleSheet.create({
  base: {
    flex: 1,
  },
  contentContainerHorizontal: {
    alignSelf: 'flex-start',
    flexDirection: 'row',
  },
});

var validAttributes = {
  ...ReactNativeViewAttributes.UIView,
  alwaysBounceHorizontal: true,
  alwaysBounceVertical: true,
  automaticallyAdjustContentInsets: true,
  bounces: true,
  centerContent: true,
  contentInset: {diff: insetsDiffer},
  contentOffset: {diff: pointsDiffer},
  decelerationRate: true,
  horizontal: true,
  keyboardDismissMode: true,
  keyboardShouldPersistTaps: true,
  maximumZoomScale: true,
  minimumZoomScale: true,
  pagingEnabled: true,
  removeClippedSubviews: true,
  scrollEnabled: true,
  scrollIndicatorInsets: {diff: insetsDiffer},
  scrollsToTop: true,
  showsHorizontalScrollIndicator: true,
  showsVerticalScrollIndicator: true,
  stickyHeaderIndices: {diff: deepDiffer},
  scrollEventThrottle: true,
  zoomScale: true,
};

if (Platform.OS === 'android') {
  var AndroidScrollView = createReactNativeComponentClass({
    validAttributes: validAttributes,
    uiViewClassName: 'RCTScrollView',
  });
  var AndroidHorizontalScrollView = createReactNativeComponentClass({
    validAttributes: validAttributes,
    uiViewClassName: 'AndroidHorizontalScrollView',
  });
} else if (Platform.OS === 'ios') {
  var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
}

module.exports = ScrollView;
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */
// TODO: move this file to shims/ReactNative (requires React update and sync)

'use strict';

import type {NativeComponent} from '../../Libraries/Renderer/shims/ReactNative';
import requireNativeComponent from '../../Libraries/ReactNative/requireNativeComponent';
import {UIManager} from 'react-native';

// TODO: import from CodegenSchema once workspaces are enabled
type Options = $ReadOnly<{|
  interfaceOnly?: boolean,
  paperComponentName?: string,
  paperComponentNameDeprecated?: string,
|}>;

function codegenNativeComponent<Props>(
  componentName: string,
  options?: Options,
): Class<NativeComponent<Props>> {
  let componentNameInUse =
    options && options.paperComponentName
      ? options.paperComponentName
      : componentName;

  if (options != null && options.paperComponentNameDeprecated != null) {
    if (UIManager.getViewManagerConfig(componentName)) {
      componentNameInUse = componentName;
    } else if (
      options.paperComponentNameDeprecated != null &&
      UIManager.getViewManagerConfig(options.paperComponentNameDeprecated)
    ) {
      componentNameInUse = options.paperComponentNameDeprecated;
    } else {
      throw new Error(
        'Failed to find native component for either "::_COMPONENT_NAME_::" or "::_COMPONENT_NAME_DEPRECATED_::"',
      );
    }
  }

  // If this function is run at runtime then that means the view configs were not
  // generated with the view config babel plugin, so we need to require the native component.
  //
  // This will be useful during migration, but eventually this will error.
  return ((requireNativeComponent(componentNameInUse): any): Class<
    NativeComponent<Props>,
  >);
}

export default codegenNativeComponent;
<commit_msg>Fix error string in codegenNativeComponent<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */
// TODO: move this file to shims/ReactNative (requires React update and sync)

'use strict';

import type {NativeComponent} from '../../Libraries/Renderer/shims/ReactNative';
import requireNativeComponent from '../../Libraries/ReactNative/requireNativeComponent';
import {UIManager} from 'react-native';

// TODO: import from CodegenSchema once workspaces are enabled
type Options = $ReadOnly<{|
  interfaceOnly?: boolean,
  paperComponentName?: string,
  paperComponentNameDeprecated?: string,
|}>;

function codegenNativeComponent<Props>(
  componentName: string,
  options?: Options,
): Class<NativeComponent<Props>> {
  let componentNameInUse =
    options && options.paperComponentName
      ? options.paperComponentName
      : componentName;

  if (options != null && options.paperComponentNameDeprecated != null) {
    if (UIManager.getViewManagerConfig(componentName)) {
      componentNameInUse = componentName;
    } else if (
      options.paperComponentNameDeprecated != null &&
      UIManager.getViewManagerConfig(options.paperComponentNameDeprecated)
    ) {
      componentNameInUse = options.paperComponentNameDeprecated;
    } else {
      throw new Error(
        `Failed to find native component for either ${componentName} or ${options.paperComponentNameDeprecated ||
          '(unknown)'}`,
      );
    }
  }

  // If this function is run at runtime then that means the view configs were not
  // generated with the view config babel plugin, so we need to require the native component.
  //
  // This will be useful during migration, but eventually this will error.
  return ((requireNativeComponent(componentNameInUse): any): Class<
    NativeComponent<Props>,
  >);
}

export default codegenNativeComponent;
<|endoftext|>


<commit_before>var cheerio = require('cheerio');
require('./parserUtil');

module.exports.parse = function(html, date, callback) {
    var $ = cheerio.load(html, { decodeEntities: true });
    var result = [];

    var weekMenu = $('#privitanie').text();
    if (weekMenu) {
        var dateText = date.format('D.M.YYYY').replace(/\./g, '\\.');
        var regex = new RegExp(dateText + '((?:.|\r|\n)*?)NOVINKA!');
        var dayMenu = weekMenu.match(regex)[1];
        var menuTextNodes = dayMenu.split('\n')
            .map(l => l.trim())
            .filter(l => l.length > 0)
            .map(l => l.normalizeWhitespace())
            .filter(l => /^(\d|A\/)/.test(l)); // 4 Jakub and other nonbelievers, this filters only lines that start with number or A/

        for (let i = 0; i < menuTextNodes.length; i++) {
            if(/A\//.test(menuTextNodes[i])) {
                var soups = menuTextNodes[i].split(/\s*[ABCD]\/\s*/).filter(l => l.length > 0)
                    .forEach(l => result.push({ isSoup: true, text: l, price: NaN }));
            } else {
                let text = menuTextNodes[i];
                let price = NaN;
                /* jshint -W083 */
                text = text.replace(/\d+,\d+\s?€/, (match) => {
                    price = parseFloat(match.replace(',', '.'));
                    return '';
                });
                /* jshint +W083 */
                result.push({ isSoup: false, text: normalize(text), price: price });
            }

        }
    }

    callback(result);

    function normalize(str) {
        return str.removeItemNumbering()
            .normalizeWhitespace()
            .removeMetrics()
            .correctCommaSpacing();
    }
};
<commit_msg>fixed static analysis<commit_after>var cheerio = require('cheerio');
require('./parserUtil');

module.exports.parse = function(html, date, callback) {
    var $ = cheerio.load(html, { decodeEntities: true });
    var result = [];

    var weekMenu = $('#privitanie').text();
    if (weekMenu) {
        var dateText = date.format('D.M.YYYY').replace(/\./g, '\\.');
        var regex = new RegExp(dateText + '((?:.|\r|\n)*?)NOVINKA!');
        var dayMenu = weekMenu.match(regex)[1];
        var menuTextNodes = dayMenu.split('\n')
            .map(l => l.trim())
            .filter(l => l.length > 0)
            .map(l => l.normalizeWhitespace())
            .filter(l => /^(\d|A\/)/.test(l)); // 4 Jakub and other nonbelievers, this filters only lines that start with number or A/

        /* jshint -W083 */
        for (let i = 0; i < menuTextNodes.length; i++) {
            if(/A\//.test(menuTextNodes[i])) {
                menuTextNodes[i].split(/\s*[ABCD]\/\s*/).filter(l => l.length > 0)
                    .forEach(l => result.push({ isSoup: true, text: l, price: NaN }));
            } else {
                let text = menuTextNodes[i];
                let price = NaN;
                text = text.replace(/\d+,\d+\s?€/, (match) => {
                    price = parseFloat(match.replace(',', '.'));
                    return '';
                });
                result.push({ isSoup: false, text: normalize(text), price: price });
            }
        }
        /* jshint +W083 */
    }

    callback(result);

    function normalize(str) {
        return str.removeItemNumbering()
            .normalizeWhitespace()
            .removeMetrics()
            .correctCommaSpacing();
    }
};
<|endoftext|>


<commit_before>export default class BannerRenderer {
  render ({containerId, content, size}) {
    throw new Error('BannerRenderer#render must be implemented')
  }
}
<commit_msg>Add JSDOC for interface BannerRenderer and remove unused parameters<commit_after>/**
 * @interface
 */
export default class BannerRenderer {
  render ({containerId}) {
    throw new Error('BannerRenderer#render must be implemented')
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import {StyleSheet, Text, Image, Platform, ScrollView, View, ToolbarAndroid, TouchableHighlight} from 'react-native';
import {NavigationContext} from 'navigation-react';
import {NavigationBarIOS} from 'navigation-react-native';
import Tweets from './Tweets';

export default ({tweet: {account: {id: accountId, name, username, logo},
  text, time, retweets, likes, replies}}) => (
    <NavigationContext.Consumer>
    {({stateNavigator}) => (
      <>
        <ToolbarAndroid
          navIcon={require('./arrow.png')}
          title="Tweet"
          style={styles.toolbar}
          onIconClicked={() => {
            stateNavigator.navigateBack(1)
          }} />
        <NavigationBarIOS title="Tweet" />
        <ScrollView contentInsetAdjustmentBehavior="automatic" style={styles.view}>
          <View>
            <View style={styles.heading}>
              <TouchableHighlight underlayColor="white" onPress={() => {
                stateNavigator.navigate('timeline', {id: accountId});
              }}>
                <Image style={styles.logo} source={logo} />
              </TouchableHighlight>
              <View style={styles.details}>
                <Text style={styles.name}>{name}</Text>
                <Text>{username}</Text>
              </View>
            </View>
            <Text style={styles.text}>{text}</Text>
            <Text style={styles.time}>{time}</Text>
            <View style={styles.interactions}>
              <Text style={styles.count}>{retweets}</Text>
              <Text style={styles.interaction}>RETWEETS</Text>
              <Text style={styles.count}>{likes}</Text>
              <Text style={styles.interaction}>LIKES</Text>
            </View>
          </View>
          <Tweets tweets={replies} stateNavigator={stateNavigator} />
        </ScrollView>
      </>
    )}
  </NavigationContext.Consumer>
);

const styles = StyleSheet.create({
  toolbar: {
    height: Platform.OS === 'android' ? 50 : 0,
  },
  view: {
    paddingLeft: 20,
    paddingRight: 20,
  },
  heading: {
    flexDirection: 'row',
    marginTop: 20,
    marginBottom: 10,
  },
  logo: {
    width: 50,
    height: 50,
    borderRadius: 25,
    marginRight: 12,
  },
  name: {
    fontWeight: 'bold',
    marginTop: 5,
    marginBottom: 2,
  },
  text: {
    fontSize: 18,
  },
  time: {
    color: '#657786',
    paddingTop: 12,
    paddingBottom: 10,
    fontSize: 13,
  },
  interactions: {
    flexDirection: 'row',
    borderTopWidth: 1,
    borderBottomWidth: 1,
    borderColor: '#ccd6dd',
    paddingTop: 12,
    paddingBottom: 12,
  },
  count: {
    fontWeight: 'bold',
    fontSize: 13,
    marginRight: 5,
  },
  interaction: {
    color: '#657786',
    fontSize: 13,
    marginRight: 10,
  },
});
<commit_msg>Got stateNavigator from useContext hook<commit_after>import React, {useContext} from 'react';
import {StyleSheet, Text, Image, Platform, ScrollView, View, ToolbarAndroid, TouchableHighlight} from 'react-native';
import {NavigationContext} from 'navigation-react';
import {NavigationBarIOS} from 'navigation-react-native';
import Tweets from './Tweets';

export default ({tweet: {account: {id: accountId, name, username, logo},
  text, time, retweets, likes, replies}}) => {
  const {stateNavigator} = useContext(NavigationContext);
  return (
    <>
      <ToolbarAndroid
        navIcon={require('./arrow.png')}
        title="Tweet"
        style={styles.toolbar}
        onIconClicked={() => {
          stateNavigator.navigateBack(1)
        }} />
      <NavigationBarIOS title="Tweet" />
      <ScrollView contentInsetAdjustmentBehavior="automatic" style={styles.view}>
        <View>
          <View style={styles.heading}>
            <TouchableHighlight underlayColor="white" onPress={() => {
              stateNavigator.navigate('timeline', {id: accountId});
            }}>
              <Image style={styles.logo} source={logo} />
            </TouchableHighlight>
            <View style={styles.details}>
              <Text style={styles.name}>{name}</Text>
              <Text>{username}</Text>
            </View>
          </View>
          <Text style={styles.text}>{text}</Text>
          <Text style={styles.time}>{time}</Text>
          <View style={styles.interactions}>
            <Text style={styles.count}>{retweets}</Text>
            <Text style={styles.interaction}>RETWEETS</Text>
            <Text style={styles.count}>{likes}</Text>
            <Text style={styles.interaction}>LIKES</Text>
          </View>
        </View>
        <Tweets tweets={replies} stateNavigator={stateNavigator} />
      </ScrollView>
    </>
  );
};

const styles = StyleSheet.create({
  toolbar: {
    height: Platform.OS === 'android' ? 50 : 0,
  },
  view: {
    paddingLeft: 20,
    paddingRight: 20,
  },
  heading: {
    flexDirection: 'row',
    marginTop: 20,
    marginBottom: 10,
  },
  logo: {
    width: 50,
    height: 50,
    borderRadius: 25,
    marginRight: 12,
  },
  name: {
    fontWeight: 'bold',
    marginTop: 5,
    marginBottom: 2,
  },
  text: {
    fontSize: 18,
  },
  time: {
    color: '#657786',
    paddingTop: 12,
    paddingBottom: 10,
    fontSize: 13,
  },
  interactions: {
    flexDirection: 'row',
    borderTopWidth: 1,
    borderBottomWidth: 1,
    borderColor: '#ccd6dd',
    paddingTop: 12,
    paddingBottom: 12,
  },
  count: {
    fontWeight: 'bold',
    fontSize: 13,
    marginRight: 5,
  },
  interaction: {
    color: '#657786',
    fontSize: 13,
    marginRight: 10,
  },
});
<|endoftext|>


<commit_before>'use strict'

const readline = require('readline')

const Input = (() => {

    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    function setName() {
        return new Promise((resolve, reject) => {
            rl.question('Enter username: ', (uname) => {
                resolve(uname.replace(/\s/g, ''))
            })
        })
    }

    function setRoom() {
        return new Promise((resolve, reject) => {
            rl.question('Enter room to join or create: ', (room) => {
                resolve(
                    room
                        .trim()
                        .toLowerCase()
                        .replace(/\s/g, '-')
                )
            })
        })
    }

    function setPrompt() {
        rl.prompt(true)
    }

    function setMessage(messageHandler) {
        rl.on('line', (message) => {
            messageHandler(message)
        })
    }

    function setLeave(leaveHandler) {
        rl.on('SIGINT', () => {
            leaveHandler()
        })
    }

    function clearLine() {
        readline.clearLine(process.stdout, 0)
        readline.cursorTo(process.stdout, 0)
    }

    return {
        setName,
        setRoom,
        setPrompt,
        setMessage,
        setLeave,
        clearLine,
    }

})()

module.exports = Input
<commit_msg>Added autocompletetion<commit_after>'use strict'

const readline = require('readline')

const Input = (() => {

    const rl = readline.createInterface({
        completer,
        input: process.stdin,
        output: process.stdout,
    });

    function completer(line) {
        const completions = ':help :q :cr :gr'.split(' ')
        const hits = completions.filter(c => c.indexOf(line) === 0)
        return [hits.length ? hits : completions, line]
    }

    function setName() {
        return new Promise((resolve, reject) => {
            rl.question('Enter username: ', (uname) => {
                resolve(uname.replace(/\s/g, ''))
            })
        })
    }

    function setRoom() {
        return new Promise((resolve, reject) => {
            rl.question('Enter room to join or create: ', (room) => {
                resolve(
                    room
                        .trim()
                        .toLowerCase()
                        .replace(/\s/g, '-')
                )
            })
        })
    }

    function setPrompt() {
        rl.prompt(true)
    }

    function setMessage(messageHandler) {
        rl.on('line', (message) => {
            messageHandler(message)
        })
    }

    function setLeave(leaveHandler) {
        rl.on('SIGINT', () => {
            leaveHandler()
        })
    }

    function clearLine() {
        readline.clearLine(process.stdout, 0)
        readline.cursorTo(process.stdout, 0)
    }

    return {
        setName,
        setRoom,
        setPrompt,
        setMessage,
        setLeave,
        clearLine,
    }

})()

module.exports = Input
<|endoftext|>


<commit_before>import {style, rangeHasStyle, Pos} from "../model"
import {canLift, canWrap, joinPoint} from "../transform"
import {elt} from "../dom"
import {MenuItem} from "./menu"
export {MenuItem}
import insertCSS from "insert-css"
import "./icons"

const tags = Object.create(null)

export function registerItem(tag, item) {
  ;(tags[tag] || (tags[tag] = [])).push(item)
}
export function getItems(tag) {
  return tags[tag] || []
}

export class IconItem extends MenuItem {
  constructor(icon, title) {
    super()
    this.icon = icon
    this.title = title
  }

  active() { return false }

  render(menu) {
    let iconClass = "ProseMirror-menuicon"
    if (this.active(menu.pm)) iconClass += " ProseMirror-menuicon-active"
    let dom = elt("div", {class: iconClass, title: this.title},
                  elt("span", {class: "ProseMirror-menuicon ProseMirror-icon-" + this.icon}))
    dom.addEventListener("mousedown", e => {
      e.preventDefault(); e.stopPropagation()
      menu.run(this.apply(menu.pm))
    })
    return dom
  }
}

export class LiftItem extends IconItem {
  constructor() {
    super("lift", "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return canLift(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(pm.tr.lift(sel.from, sel.to))
  }
}

export class JoinItem extends IconItem {
  constructor() {
    super("join", "Join with block above")
  }
  select(pm) {
    return joinPoint(pm.doc, pm.selection.head)
  }
  apply(pm) {
    pm.apply(pm.tr.join(joinPoint(pm.doc, pm.selection.head)))
  }
}

export class InsertBlockItem extends IconItem {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return Pos.samePath(sel.head.path, sel.anchor.path) &&
      pm.doc.path(sel.head.path).type.canContain(pm.schema.nodeType(this.type))
  }
  apply(pm) {
    let sel = pm.selection, tr = pm.tr, off = 0
    if (sel.head.offset) {
      tr.split(sel.head)
      off = 1
    }
    pm.apply(tr.insert(sel.head.shorten(null, off), pm.schema.node(this.type, this.attrs)))
  }
}

export class WrapItem extends IconItem {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  select(pm) {
    return canWrap(pm.doc, pm.selection.from, pm.selection.to, pm.schema.node(this.type))
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(pm.tr.wrap(sel.from, sel.to, pm.schema.node(this.type)))
  }
}

export class InlineStyleItem extends IconItem {
  constructor(icon, title, style, dialog) {
    super(icon, title)
    this.style = typeof style == "string" ? {type: style} : style
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    if (sel.empty)
      return style.containsType(pm.activeStyles(), this.style.type)
    else
      return rangeHasStyle(pm.doc, sel.from, sel.to, this.style.type)
  }
  apply(pm) {
    if (this.active(pm))
      pm.setStyle(this.style, false)
    else if (this.dialog)
      return [this.dialog]
    else
      pm.setStyle(this.style, true)
  }
}

export class ImageItem extends IconItem {
  constructor() {
    super("image", "Insert image")
  }
  apply() { return [imageDialog] }
}

export class DialogItem extends MenuItem {
  focus(form) {
    let input = form.querySelector("input, textarea")
    if (input) input.focus()
  }

  render(menu) {
    let form = this.form(menu.pm), done = false

    let finish = () => {
      if (!done) {
        done = true
        menu.pm.focus()
      }
    }

    let submit = () => {
      let result = this.apply(form, menu.pm)
      finish()
      menu.run(result)
    }
    form.addEventListener("submit", e => {
      e.preventDefault()
      submit()
    })
    form.addEventListener("keydown", e => {
      if (e.keyCode == 27) {
        finish()
        menu.leave()
      } else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
        e.preventDefault()
        submit()
      }
    })
    // FIXME too hacky?
    setTimeout(() => this.focus(form), 20)
    return form
  }
}

export class LinkDialog extends DialogItem {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply(pm.tr.addStyle(sel.from, sel.to, style.link(elts.href.value, elts.title.value)))
  }
}
const linkDialog = new LinkDialog

export class ImageDialog extends DialogItem {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection, tr = pm.tr
    tr.delete(sel.from, sel.to)
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply(tr.insertInline(sel.from, pm.schema.node("image", attrs)))
  }
}
const imageDialog = new ImageDialog

class SeparatorItem extends MenuItem {
  render() { return elt("div", {class: "ProseMirror-menuseparator"}) }
}
export const separatorItem = new SeparatorItem

class UndoItem extends IconItem {
  constructor() { super("undo", "Undo") }
  select(pm) { return pm.history.canUndo() }
  apply(pm) { pm.history.undo() }
}
class RedoItem extends IconItem {
  constructor() { super("redo", "Redo") }
  select(pm) { return pm.history.canRedo() }
  apply(pm) { pm.history.redo() }
}
class HistorySeparator extends SeparatorItem {
  select(pm) { return pm.history.canUndo() || pm.history.canRedo() }
}

// FIXME make schema-aware
const blockTypes = [
  {name: "Normal", type: "paragraph"},
  {name: "Code", type: "code_block"}
]
for (let i = 1; i <= 6; i++)
  blockTypes.push({name: "Head " + i, type: "heading", attrs: {level: i}})
function getBlockType(block) {
  for (let i = 0; i < blockTypes.length; i++)
    if (blockTypes[i].type == block.type.name &&
        (block.type.attrs.level == null || block.type.attrs.level == blockTypes[i].attrs.level))
      return blockTypes[i]
}

class BlockTypeItem extends MenuItem {
  render(menu) {
    let sel = menu.pm.selection, type
    if (Pos.samePath(sel.head.path, sel.anchor.path)) type = getBlockType(menu.pm.doc.path(sel.head.path))
    let dom = elt("div", {class: "ProseMirror-blocktype", title: "Paragraph type"},
                  type ? type.name : "Type...")
    dom.addEventListener("mousedown", e => {
      e.preventDefault(); e.stopPropagation()
      showBlockTypeMenu(menu.pm, dom)
    })
    return dom
  }
}

function showBlockTypeMenu(pm, dom) {
  let menu = elt("div", {class: "ProseMirror-blocktype-menu"},
                 blockTypes.map(t => {
                   let dom = elt("div", null, t.name)
                   dom.addEventListener("mousedown", e => {
                     e.preventDefault()
                     let sel = pm.selection
                     pm.apply(pm.tr.setBlockType(sel.from, sel.to, pm.schema.node(t.type, t.attrs)))
                     finish()
                   })
                   return dom
                 }))
  let pos = dom.getBoundingClientRect(), box = pm.wrapper.getBoundingClientRect()
  menu.style.left = (pos.left - box.left - 2) + "px"
  menu.style.top = (pos.top - box.top - 2) + "px"

  let done = false
  function finish() {
    if (done) return
    done = true
    document.body.removeEventListener("mousedown", finish)
    document.body.removeEventListener("keydown", finish)
    pm.wrapper.removeChild(menu)
  }
  document.body.addEventListener("mousedown", finish)
  document.body.addEventListener("keydown", finish)
  pm.wrapper.appendChild(menu)
}

registerItem("inline", new InlineStyleItem("strong", "Strong text", style.strong))
registerItem("inline", new InlineStyleItem("em", "Emphasized text", style.em))
registerItem("inline", new InlineStyleItem("link", "Hyperlink", "link", linkDialog))
registerItem("inline", new InlineStyleItem("code", "Code font", style.code))
registerItem("inline", new ImageItem("image"))

registerItem("block", new BlockTypeItem)
registerItem("block", new LiftItem)
registerItem("block", new WrapItem("list-ol", "Wrap in ordered list", "ordered_list"))
registerItem("block", new WrapItem("list-ul", "Wrap in bullet list", "bullet_list"))
registerItem("block", new WrapItem("quote", "Wrap in blockquote", "blockquote"))
registerItem("block", new InsertBlockItem("hr", "Insert horizontal rule", "horizontal_rule"))
registerItem("block", new JoinItem)

registerItem("history", new HistorySeparator)
registerItem("history", new UndoItem)
registerItem("history", new RedoItem)

// Awkward hack to force Chrome to initialize the font and not return
// incorrect size information the first time it is used.

let forced = false
export function forceFontLoad(pm) {
  if (forced) return
  forced = true

  let node = pm.wrapper.appendChild(elt("div", {class: "ProseMirror-menuicon ProseMirror-icon-strong",
                                                style: "visibility: hidden; position: absolute"}))
  window.setTimeout(() => pm.wrapper.removeChild(node), 20)
}

insertCSS(`

.ProseMirror-menuicon {
  display: inline-block;
  padding: 1px 4px;
  margin: 0 2px;
  cursor: pointer;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  vertical-align: middle;
}

.ProseMirror-menuicon-active {
  background: #666;
  border-radius: 4px;
}

.ProseMirror-menuseparator {
  display: inline-block;
}
.ProseMirror-menuseparator:after {
  content: "︙";
  opacity: 0.5;
  padding: 0 4px;
  vertical-align: middle;
}

.ProseMirror-blocktype, .ProseMirror-blocktype-menu {
  border: 1px solid #777;
  border-radius: 3px;
  font-size: 90%;
}

.ProseMirror-blocktype {
  padding: 1px 2px 1px 4px;
  display: inline-block;
  vertical-align: middle;
  cursor: pointer;
  margin: 0 4px;
}

.ProseMirror-blocktype:after {
  content: " ▿";
  color: #777;
  vertical-align: top;
}

.ProseMirror-blocktype-menu {
  position: absolute;
  background: #444;
  color: white;
  padding: 2px 2px;
  z-index: 5;
}
.ProseMirror-blocktype-menu div {
  cursor: pointer;
  padding: 0 1em 0 2px;
}
.ProseMirror-blocktype-menu div:hover {
  background: #777;
}

`)
<commit_msg>Make styles part of the schema<commit_after>import {rangeHasStyle, Pos, containsStyle} from "../model"
import {canLift, canWrap, joinPoint} from "../transform"
import {elt} from "../dom"
import {MenuItem} from "./menu"
export {MenuItem}
import insertCSS from "insert-css"
import "./icons"

const tags = Object.create(null)

export function registerItem(tag, item) {
  ;(tags[tag] || (tags[tag] = [])).push(item)
}
export function getItems(tag) {
  return tags[tag] || []
}

export class IconItem extends MenuItem {
  constructor(icon, title) {
    super()
    this.icon = icon
    this.title = title
  }

  active() { return false }

  render(menu) {
    let iconClass = "ProseMirror-menuicon"
    if (this.active(menu.pm)) iconClass += " ProseMirror-menuicon-active"
    let dom = elt("div", {class: iconClass, title: this.title},
                  elt("span", {class: "ProseMirror-menuicon ProseMirror-icon-" + this.icon}))
    dom.addEventListener("mousedown", e => {
      e.preventDefault(); e.stopPropagation()
      menu.run(this.apply(menu.pm))
    })
    return dom
  }
}

export class LiftItem extends IconItem {
  constructor() {
    super("lift", "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return canLift(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(pm.tr.lift(sel.from, sel.to))
  }
}

export class JoinItem extends IconItem {
  constructor() {
    super("join", "Join with block above")
  }
  select(pm) {
    return joinPoint(pm.doc, pm.selection.head)
  }
  apply(pm) {
    pm.apply(pm.tr.join(joinPoint(pm.doc, pm.selection.head)))
  }
}

export class InsertBlockItem extends IconItem {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return Pos.samePath(sel.head.path, sel.anchor.path) &&
      pm.doc.path(sel.head.path).type.canContain(pm.schema.nodeType(this.type))
  }
  apply(pm) {
    let sel = pm.selection, tr = pm.tr, off = 0
    if (sel.head.offset) {
      tr.split(sel.head)
      off = 1
    }
    pm.apply(tr.insert(sel.head.shorten(null, off), pm.schema.node(this.type, this.attrs)))
  }
}

export class WrapItem extends IconItem {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  select(pm) {
    return canWrap(pm.doc, pm.selection.from, pm.selection.to, pm.schema.node(this.type))
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(pm.tr.wrap(sel.from, sel.to, pm.schema.node(this.type)))
  }
}

export class InlineStyleItem extends IconItem {
  constructor(icon, title, style, dialog, attrs) {
    super(icon, title)
    this.style = style
    this.attrs = attrs
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    let type = pm.schema.styles[this.style]
    if (sel.empty)
      return containsStyle(pm.activeStyles(), type)
    else
      return rangeHasStyle(pm.doc, sel.from, sel.to, type)
  }
  apply(pm) {
    if (this.active(pm))
      pm.setStyle(pm.schema.style(this.style, this.attrs), false)
    else if (this.dialog)
      return [this.dialog]
    else
      pm.setStyle(pm.schema.style(this.style, this.attrs), true)
  }
}

export class ImageItem extends IconItem {
  constructor() {
    super("image", "Insert image")
  }
  apply() { return [imageDialog] }
}

export class DialogItem extends MenuItem {
  focus(form) {
    let input = form.querySelector("input, textarea")
    if (input) input.focus()
  }

  render(menu) {
    let form = this.form(menu.pm), done = false

    let finish = () => {
      if (!done) {
        done = true
        menu.pm.focus()
      }
    }

    let submit = () => {
      let result = this.apply(form, menu.pm)
      finish()
      menu.run(result)
    }
    form.addEventListener("submit", e => {
      e.preventDefault()
      submit()
    })
    form.addEventListener("keydown", e => {
      if (e.keyCode == 27) {
        finish()
        menu.leave()
      } else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
        e.preventDefault()
        submit()
      }
    })
    // FIXME too hacky?
    setTimeout(() => this.focus(form), 20)
    return form
  }
}

export class LinkDialog extends DialogItem {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply(pm.tr.addStyle(sel.from, sel.to,
                            pm.schema.style("link", {href: elts.href.value,
                                                     title: elts.title.value})))
  }
}
const linkDialog = new LinkDialog

export class ImageDialog extends DialogItem {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection, tr = pm.tr
    tr.delete(sel.from, sel.to)
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply(tr.insertInline(sel.from, pm.schema.node("image", attrs)))
  }
}
const imageDialog = new ImageDialog

class SeparatorItem extends MenuItem {
  render() { return elt("div", {class: "ProseMirror-menuseparator"}) }
}
export const separatorItem = new SeparatorItem

class UndoItem extends IconItem {
  constructor() { super("undo", "Undo") }
  select(pm) { return pm.history.canUndo() }
  apply(pm) { pm.history.undo() }
}
class RedoItem extends IconItem {
  constructor() { super("redo", "Redo") }
  select(pm) { return pm.history.canRedo() }
  apply(pm) { pm.history.redo() }
}
class HistorySeparator extends SeparatorItem {
  select(pm) { return pm.history.canUndo() || pm.history.canRedo() }
}

// FIXME make schema-aware
const blockTypes = [
  {name: "Normal", type: "paragraph"},
  {name: "Code", type: "code_block"}
]
for (let i = 1; i <= 6; i++)
  blockTypes.push({name: "Head " + i, type: "heading", attrs: {level: i}})
function getBlockType(block) {
  for (let i = 0; i < blockTypes.length; i++)
    if (blockTypes[i].type == block.type.name &&
        (block.type.attrs.level == null || block.type.attrs.level == blockTypes[i].attrs.level))
      return blockTypes[i]
}

class BlockTypeItem extends MenuItem {
  render(menu) {
    let sel = menu.pm.selection, type
    if (Pos.samePath(sel.head.path, sel.anchor.path)) type = getBlockType(menu.pm.doc.path(sel.head.path))
    let dom = elt("div", {class: "ProseMirror-blocktype", title: "Paragraph type"},
                  type ? type.name : "Type...")
    dom.addEventListener("mousedown", e => {
      e.preventDefault(); e.stopPropagation()
      showBlockTypeMenu(menu.pm, dom)
    })
    return dom
  }
}

function showBlockTypeMenu(pm, dom) {
  let menu = elt("div", {class: "ProseMirror-blocktype-menu"},
                 blockTypes.map(t => {
                   let dom = elt("div", null, t.name)
                   dom.addEventListener("mousedown", e => {
                     e.preventDefault()
                     let sel = pm.selection
                     pm.apply(pm.tr.setBlockType(sel.from, sel.to, pm.schema.node(t.type, t.attrs)))
                     finish()
                   })
                   return dom
                 }))
  let pos = dom.getBoundingClientRect(), box = pm.wrapper.getBoundingClientRect()
  menu.style.left = (pos.left - box.left - 2) + "px"
  menu.style.top = (pos.top - box.top - 2) + "px"

  let done = false
  function finish() {
    if (done) return
    done = true
    document.body.removeEventListener("mousedown", finish)
    document.body.removeEventListener("keydown", finish)
    pm.wrapper.removeChild(menu)
  }
  document.body.addEventListener("mousedown", finish)
  document.body.addEventListener("keydown", finish)
  pm.wrapper.appendChild(menu)
}

registerItem("inline", new InlineStyleItem("strong", "Strong text", "strong"))
registerItem("inline", new InlineStyleItem("em", "Emphasized text", "em"))
registerItem("inline", new InlineStyleItem("link", "Hyperlink", "link", linkDialog))
registerItem("inline", new InlineStyleItem("code", "Code font", "code"))
registerItem("inline", new ImageItem("image"))

registerItem("block", new BlockTypeItem)
registerItem("block", new LiftItem)
registerItem("block", new WrapItem("list-ol", "Wrap in ordered list", "ordered_list"))
registerItem("block", new WrapItem("list-ul", "Wrap in bullet list", "bullet_list"))
registerItem("block", new WrapItem("quote", "Wrap in blockquote", "blockquote"))
registerItem("block", new InsertBlockItem("hr", "Insert horizontal rule", "horizontal_rule"))
registerItem("block", new JoinItem)

registerItem("history", new HistorySeparator)
registerItem("history", new UndoItem)
registerItem("history", new RedoItem)

// Awkward hack to force Chrome to initialize the font and not return
// incorrect size information the first time it is used.

let forced = false
export function forceFontLoad(pm) {
  if (forced) return
  forced = true

  let node = pm.wrapper.appendChild(elt("div", {class: "ProseMirror-menuicon ProseMirror-icon-strong",
                                                style: "visibility: hidden; position: absolute"}))
  window.setTimeout(() => pm.wrapper.removeChild(node), 20)
}

insertCSS(`

.ProseMirror-menuicon {
  display: inline-block;
  padding: 1px 4px;
  margin: 0 2px;
  cursor: pointer;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  vertical-align: middle;
}

.ProseMirror-menuicon-active {
  background: #666;
  border-radius: 4px;
}

.ProseMirror-menuseparator {
  display: inline-block;
}
.ProseMirror-menuseparator:after {
  content: "︙";
  opacity: 0.5;
  padding: 0 4px;
  vertical-align: middle;
}

.ProseMirror-blocktype, .ProseMirror-blocktype-menu {
  border: 1px solid #777;
  border-radius: 3px;
  font-size: 90%;
}

.ProseMirror-blocktype {
  padding: 1px 2px 1px 4px;
  display: inline-block;
  vertical-align: middle;
  cursor: pointer;
  margin: 0 4px;
}

.ProseMirror-blocktype:after {
  content: " ▿";
  color: #777;
  vertical-align: top;
}

.ProseMirror-blocktype-menu {
  position: absolute;
  background: #444;
  color: white;
  padding: 2px 2px;
  z-index: 5;
}
.ProseMirror-blocktype-menu div {
  cursor: pointer;
  padding: 0 1em 0 2px;
}
.ProseMirror-blocktype-menu div:hover {
  background: #777;
}

`)
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';
import Analyzer from 'parser/core/Analyzer';
import SUGGESTION_IMPORTANCE from 'parser/core/ISSUE_IMPORTANCE';

const LOWER_FOOD_IDS = [
  // very low
  SPELLS.KUL_TIRAMISU.id,
  SPELLS.LOA_LEAF.id,
  SPELLS.RAVENBERRY_TARTS.id,
  SPELLS.MON_DAZI.id,
  // somwhat low
  SPELLS.HONEY_GLAZED_HAUNCHES.id,
  SPELLS.SAILOR_PIE.id,
  SPELLS.SWAMP_FISH_N_CHIPS.id,
  SPELLS.SPICED_SNAPPER.id,
  // low - 75 primary stat
  SPELLS.GALLEY_BANQUET_AGI.id,
  SPELLS.GALLEY_BANQUET_INT.id,
  SPELLS.GALLEY_BANQUET_STR.id,
  // 113 stamina
  SPELLS.GALLEY_BANQUET_STA.id,
  SPELLS.WELL_FED_WILD_BERRY_BREAD.id,
  // caused by Reawakening trait (Resto Druid rebirth) - 60 primary stat
  SPELLS.WELL_FED_REAWAKENING_INT.id,
  SPELLS.WELL_FED_REAWAKENING_STR.id,
  SPELLS.WELL_FED_REAWAKENING_AGI.id,
];

const MID_TIER_FOOD_IDS = [
  // 100 primary stat
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_AGI.id,
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_INT.id,
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_STR.id,
  // 150 stamina
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_STA.id,
  SPELLS.WELL_FED_SEASONED_STEAK_AND_POTATOES.id,
  // 85 primary stat buffs
  SPELLS.BORALUS_BLOOD_SAUSAGE_AGI.id,
  SPELLS.BORALUS_BLOOD_SAUSAGE_INT.id,
  SPELLS.BORALUS_BLOOD_SAUSAGE_STR.id,
  // 93 secondary stat
  SPELLS.ABYSSAL_FRIED_RISSOLE.id,
  SPELLS.BIL_TONG.id,
  SPELLS.MECH_DOWELS_BIG_MECH.id,
  SPELLS.BAKED_PORT_TATO.id,
];

const HIGHER_FOOD_IDS = [
  // 131 primary stat
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_AGI.id,
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_INT.id,
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STR.id,
  // 198 stamina
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STA.id,
  SPELLS.FRAGRANT_KAKAVIA.id,
];

class FoodChecker extends Analyzer {
  lowerFoodUp = false;
  midTierFoodUp = false;
  higherFoodUp = false;
  on_toPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (event.prepull) {
      if (LOWER_FOOD_IDS.includes(spellId)) {
        this.lowerFoodUp = true;
      }
      if (HIGHER_FOOD_IDS.includes(spellId)) {
        this.higherFoodUp = true;
      }
      if (MID_TIER_FOOD_IDS.includes(spellId)) {
        this.midTierFoodUp = true;
      }
    }
  }
  get higherFoodSuggestionThresholds() {
    return {
      actual: this.higherFoodUp,
      isEqual: false,
      style: 'boolean',
    };
  }
  get isPresentFoodSuggestionThresholds() {
    return {
      actual: this.higherFoodUp || this.lowerFoodUp || this.midTierFoodUp,
      isEqual: false,
      style: 'boolean',
    };
  }
  suggestions(when) {
    let importance = SUGGESTION_IMPORTANCE.MINOR;
    let suggestionText = 'You did not have any food active when starting the fight. Having the right food buff during combat is an easy way to improve performance.';
    if (!this.higherFoodUp && (this.lowerFoodUp || this.midTierFoodUp)) {
      suggestionText = 'You did not have the best food active when starting the fight. Using the best food available is an easy way to improve performance.';
    }
    if (!this.higherFoodUp && !this.lowerFoodUp && !this.midTierFoodUp) {
      importance = SUGGESTION_IMPORTANCE.MAJOR;
    }
    when(this.higherFoodSuggestionThresholds)
      .addSuggestion((suggest) => {
        return suggest(suggestionText)
          .icon(SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STR.icon)
          .staticImportance(importance);
      });
  }
}
export default FoodChecker;
<commit_msg>change secondary stat food to higher tier<commit_after>import SPELLS from 'common/SPELLS';
import Analyzer from 'parser/core/Analyzer';
import SUGGESTION_IMPORTANCE from 'parser/core/ISSUE_IMPORTANCE';

const LOWER_FOOD_IDS = [
  // very low
  SPELLS.KUL_TIRAMISU.id,
  SPELLS.LOA_LEAF.id,
  SPELLS.RAVENBERRY_TARTS.id,
  SPELLS.MON_DAZI.id,
  // somwhat low
  SPELLS.HONEY_GLAZED_HAUNCHES.id,
  SPELLS.SAILOR_PIE.id,
  SPELLS.SWAMP_FISH_N_CHIPS.id,
  SPELLS.SPICED_SNAPPER.id,
  // low - 75 primary stat
  SPELLS.GALLEY_BANQUET_AGI.id,
  SPELLS.GALLEY_BANQUET_INT.id,
  SPELLS.GALLEY_BANQUET_STR.id,
  // 113 stamina
  SPELLS.GALLEY_BANQUET_STA.id,
  SPELLS.WELL_FED_WILD_BERRY_BREAD.id,
  // caused by Reawakening trait (Resto Druid rebirth) - 60 primary stat
  SPELLS.WELL_FED_REAWAKENING_INT.id,
  SPELLS.WELL_FED_REAWAKENING_STR.id,
  SPELLS.WELL_FED_REAWAKENING_AGI.id,
];

const MID_TIER_FOOD_IDS = [
  // 100 primary stat
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_AGI.id,
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_INT.id,
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_STR.id,
  // 150 stamina
  SPELLS.BOUNTIFUL_CAPTAIN_FEAST_STA.id,
  SPELLS.WELL_FED_SEASONED_STEAK_AND_POTATOES.id,
  // 85 primary stat buffs
  SPELLS.BORALUS_BLOOD_SAUSAGE_AGI.id,
  SPELLS.BORALUS_BLOOD_SAUSAGE_INT.id,
  SPELLS.BORALUS_BLOOD_SAUSAGE_STR.id,
];

const HIGHER_FOOD_IDS = [
  // 131 primary stat
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_AGI.id,
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_INT.id,
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STR.id,
  // 198 stamina
  SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STA.id,
  SPELLS.FRAGRANT_KAKAVIA.id,
  // 93 secondary stat
  SPELLS.ABYSSAL_FRIED_RISSOLE.id,
  SPELLS.BIL_TONG.id,
  SPELLS.MECH_DOWELS_BIG_MECH.id,
  SPELLS.BAKED_PORT_TATO.id,
];

class FoodChecker extends Analyzer {
  lowerFoodUp = false;
  midTierFoodUp = false;
  higherFoodUp = false;
  on_toPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (event.prepull) {
      if (LOWER_FOOD_IDS.includes(spellId)) {
        this.lowerFoodUp = true;
      }
      if (HIGHER_FOOD_IDS.includes(spellId)) {
        this.higherFoodUp = true;
      }
      if (MID_TIER_FOOD_IDS.includes(spellId)) {
        this.midTierFoodUp = true;
      }
    }
  }
  get higherFoodSuggestionThresholds() {
    return {
      actual: this.higherFoodUp,
      isEqual: false,
      style: 'boolean',
    };
  }
  get isPresentFoodSuggestionThresholds() {
    return {
      actual: this.higherFoodUp || this.lowerFoodUp || this.midTierFoodUp,
      isEqual: false,
      style: 'boolean',
    };
  }
  suggestions(when) {
    let importance = SUGGESTION_IMPORTANCE.MINOR;
    let suggestionText = 'You did not have any food active when starting the fight. Having the right food buff during combat is an easy way to improve performance.';
    if (!this.higherFoodUp && (this.lowerFoodUp || this.midTierFoodUp)) {
      suggestionText = 'You did not have the best food active when starting the fight. Using the best food available is an easy way to improve performance.';
    }
    if (!this.higherFoodUp && !this.lowerFoodUp && !this.midTierFoodUp) {
      importance = SUGGESTION_IMPORTANCE.MAJOR;
    }
    when(this.higherFoodSuggestionThresholds)
      .addSuggestion((suggest) => {
        return suggest(suggestionText)
          .icon(SPELLS.FAMINE_EVALUATOR_AND_SNACK_TABLE_FEAST_STR.icon)
          .staticImportance(importance);
      });
  }
}
export default FoodChecker;
<|endoftext|>