<commit_before>/**
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
 * under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.
 *
 * Camunda licenses this file to you under the MIT; you may not use this file
 * except in compliance with the MIT License.
 */

import React from 'react';

import { Modal } from '../../../app/primitives';

import {
  omit
} from 'min-dash';

import css from './DeploymentConfigModal.less';

import AuthTypes from '../shared/AuthTypes';

import {
  CheckBox,
  Radio,
  TextInput
} from '../shared/components';

import {
  Formik,
  Field
} from 'formik';

export default class DeploymentConfigModal extends React.PureComponent {

  constructor(props) {
    super(props);

    this.state = {
      isAuthNeeded: false
    };

    this.valuesCache = { ...props.configuration };
  }

  componentDidMount = () => {
    const {
      subscribeToFocusChange
    } = this.props;

    const {
      onAppFocusChange
    } = this;

    subscribeToFocusChange(onAppFocusChange);
  }

  componentWillUnmount = () => {
    this.props.unsubscribeFromFocusChange();
  }

  isConnectionError(code) {
    return code === 'NOT_FOUND' || code === 'CONNECTION_FAILED' || code === 'NO_INTERNET_CONNECTION';
  }

  checkEndpointURLConnectivity = async (skipError) => {
    const {
      valuesCache,
      setFieldErrorCache,
      externalErrorCodeCache,
      isConnectionError,
      checkAuthStatus
    } = this;

    checkAuthStatus(valuesCache);

    if (isConnectionError(externalErrorCodeCache) || skipError) {

      const validationResult = await this.props.validator.validateConnection(valuesCache.endpoint);

      if (!hasKeys(validationResult)) {

        this.externalErrorCodeCache = null;
        this.props.validator.clearEndpointURLError(setFieldErrorCache);
      } else {

        const { code } = validationResult;

        if (isConnectionError(code) && code !== this.externalErrorCodeCache) {
          this.props.validator.updateEndpointURLError(code, setFieldErrorCache);
        }

        this.externalErrorCodeCache = code;
      }
    }
  }

  onSetFieldValueReceived = () => {

    // Initial endpoint URL validation. Note that this is not a form validation
    // and should affect only the Endpoint URL field.
    return this.checkEndpointURLConnectivity(true);
  }

  onAppFocusChange = () => {

    // User may fix connection related errors by focusing out from app (turn on wifi, start server etc.)
    // In that case we want to check if errors are fixed when the users focuses back on to the app.
    return this.checkEndpointURLConnectivity();
  }

  onClose = (action = 'cancel', data = null, shouldOverrideCredentials = false) => {

    if (shouldOverrideCredentials) {

      const { valuesCache } = this;
      const { endpoint } = valuesCache;
      const {
        username, password, token, rememberCredentials
      } = endpoint;

      if (rememberCredentials) {
        this.props.saveCredential({ username, password, token });
      } else {
        this.props.removeCredentials();
      }
    }

    this.props.onClose(action, data);
  }

  onSubmit = async (values, { setFieldError }) => {

    const {
      endpoint
    } = values;

    const connectionValidation = await this.props.validator.validateConnection(endpoint);

    if (!hasKeys(connectionValidation)) {
      this.externalErrorCodeCache = null;
      this.onClose('deploy', values);
    } else {

      const {
        details,
        code
      } = connectionValidation;

      if (code === 'UNAUTHORIZED') {
        this.setState({
          isAuthNeeded: true
        });
      }

      this.externalErrorCodeCache = code;
      this.props.validator.onExternalError(values.endpoint.authType, details, code, setFieldError);
    }
  }

  fieldError = (meta) => {
    return meta.error;
  }

  setAuthType = (form) => {

    return event => {

      const authType = event.target.value;

      const {
        values,
        setValues
      } = form;

      let {
        endpoint
      } = values;

      if (authType !== AuthTypes.basic) {
        endpoint = omit(endpoint, [ 'username', 'password' ]);
      }

      if (authType !== AuthTypes.bearer) {
        endpoint = omit(endpoint, [ 'token' ]);
      }

      setValues({
        ...values,
        endpoint: {
          ...endpoint,
          authType
        }
      });
    };

  }

  onAuthDetection = (isAuthNeeded) => {
    this.setState({
      isAuthNeeded
    });
  }

  checkAuthStatus = (values) => {
    this.props.validator.validateConnectionWithoutCredentials(values.endpoint.url).then((result) => {
      if (!result) {
        this.onAuthDetection(false);
      } else if (!result.isExpired) {
        this.onAuthDetection(!!result && (result.code === 'UNAUTHORIZED'));
      }
    });
  }

  render() {

    const {
      fieldError,
      onSubmit,
      onClose,
      onAuthDetection,
      onSetFieldValueReceived
    } = this;

    const {
      configuration: values,
      validator,
      title,
      intro,
      primaryAction
    } = this.props;

    const {
      isAuthNeeded
    } = this.state;

    return (
      <Modal className={ css.DeploymentConfigModal } onClose={ () => {
        onClose('cancel', null, true);
      } }>

        <Formik
          initialValues={ values }
          onSubmit={ onSubmit }
          validateOnBlur={ false }
        >
          { form => {

            this.valuesCache = { ...form.values };
            if (!this.setFieldErrorCache) {
              this.setFieldErrorCache = form.setFieldError;
              onSetFieldValueReceived();
            }

            return (
              <form onSubmit={ form.handleSubmit }>

                <Modal.Title>
                  {
                    title || 'Deploy Diagram'
                  }
                </Modal.Title>

                <Modal.Body>
                  {
                    intro && (

                        { intro }

                    )
                  }
                  <fieldset>

                      <Field
                        name="deployment.name"
                        component={ TextInput }
                        label="Deployment Name"
                        fieldError={ fieldError }
                        validate={ (value) => {
                          return validator.validateDeploymentName(value, this.isOnBeforeSubmit);
                        } }
                        autoFocus
                      />

                      <Field
                        name="deployment.tenantId"
                        component={ TextInput }
                        fieldError={ fieldError }
                        hint="Optional"
                        label="Tenant ID"
                      />

                  </fieldset>

                  <fieldset>
                    <legend>
                      Endpoint Configuration
                    </legend>

                      <Field
                        name="endpoint.url"
                        component={ TextInput }
                        fieldError={ fieldError }
                        validate={ (value) => {
                          this.externalErrorCodeCache = null;
                          return validator.validateEndpointURL(
                            value,
                            form.setFieldError,
                            this.isOnBeforeSubmit,
                            onAuthDetection,
                            (code) => { this.externalErrorCodeCache = code; }
                          );
                        } }
                        label="REST Endpoint"
                        hint="Should point to a running Camunda Engine REST API endpoint."
                      />

                      {
                        isAuthNeeded && (
                          <Field
                            name="endpoint.authType"
                            label="Authentication"
                            component={ Radio }
                            onChange={ (event) => {
                              form.handleChange(event);
                              this.setAuthType(form);
                            } }
                            values={
                              [
                                { value: AuthTypes.basic, label: 'HTTP Basic' },
                                { value: AuthTypes.bearer, label: 'Bearer token' }
                              ]
                            }
                          />
                        )
                      }

                      { isAuthNeeded && form.values.endpoint.authType === AuthTypes.basic && (
                        <React.Fragment>
                          <Field
                            name="endpoint.username"
                            component={ TextInput }
                            fieldError={ fieldError }
                            validate={ (value) => {
                              return validator.validateUsername(value || '', this.isOnBeforeSubmit);
                            } }
                            label="Username"
                            onChange={ form.handleChange }
                          />

                          <Field
                            name="endpoint.password"
                            component={ TextInput }
                            fieldError={ fieldError }
                            validate={ (value) => {
                              return validator.validatePassword(value || '', this.isOnBeforeSubmit);
                            } }
                            label="Password"
                            type="password"
                            onChange={ form.handleChange }
                          />
                        </React.Fragment>
                      )}

                      { isAuthNeeded && form.values.endpoint.authType === AuthTypes.bearer && (
                        <Field
                          name="endpoint.token"
                          component={ TextInput }
                          fieldError={ fieldError }
                          validate={ (value) => {
                            return validator.validateToken(value || '', this.isOnBeforeSubmit);
                          } }
                          label="Token"
                          onChange={ form.handleChange }
                        />
                      )}

                      {
                        isAuthNeeded && (
                          <Field
                            name="endpoint.rememberCredentials"
                            component={ CheckBox }
                            type="checkbox"
                            label="Remember credentials"
                            onChange={ form.handleChange }
                          />
                        )
                      }

                  </fieldset>
                </Modal.Body>

                <Modal.Footer>

                    <button
                      type="button"
                      className="btn btn-secondary"
                      onClick={ () => {
                        onClose('cancel', null, false);
                      } }
                    >
                      Cancel
                    </button>

                    <button
                      type="submit"
                      className="btn btn-primary"
                      disabled={ form.isSubmitting }
                      onClick={ () => {

                        // @oguz:
                        // this is a hack as FormIK does not seem to
                        // set isSubmitting when this button is clicked.
                        // if you come up with a better solution, please
                        // do a PR.
                        this.isOnBeforeSubmit = true;
                        setTimeout(() => {
                          this.isOnBeforeSubmit = false;
                        });
                      } }
                    >
                      { primaryAction || 'Deploy' }
                    </button>

                </Modal.Footer>
              </form>
            );
          } }
        </Formik>
      </Modal>
    );
  }
}

function hasKeys(obj) {
  return obj && Object.keys(obj).length > 0;
}
<commit_msg>chore(deployment-tool): remove unnecessary event handlers<commit_after>/**
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
 * under one or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.
 *
 * Camunda licenses this file to you under the MIT; you may not use this file
 * except in compliance with the MIT License.
 */

import React from 'react';

import { Modal } from '../../../app/primitives';

import {
  omit
} from 'min-dash';

import css from './DeploymentConfigModal.less';

import AuthTypes from '../shared/AuthTypes';

import {
  CheckBox,
  Radio,
  TextInput
} from '../shared/components';

import {
  Formik,
  Field
} from 'formik';

export default class DeploymentConfigModal extends React.PureComponent {

  constructor(props) {
    super(props);

    this.state = {
      isAuthNeeded: false
    };

    this.valuesCache = { ...props.configuration };
  }

  componentDidMount = () => {
    const {
      subscribeToFocusChange
    } = this.props;

    const {
      onAppFocusChange
    } = this;

    subscribeToFocusChange(onAppFocusChange);
  }

  componentWillUnmount = () => {
    this.props.unsubscribeFromFocusChange();
  }

  isConnectionError(code) {
    return code === 'NOT_FOUND' || code === 'CONNECTION_FAILED' || code === 'NO_INTERNET_CONNECTION';
  }

  checkEndpointURLConnectivity = async (skipError) => {
    const {
      valuesCache,
      setFieldErrorCache,
      externalErrorCodeCache,
      isConnectionError,
      checkAuthStatus
    } = this;

    checkAuthStatus(valuesCache);

    if (isConnectionError(externalErrorCodeCache) || skipError) {

      const validationResult = await this.props.validator.validateConnection(valuesCache.endpoint);

      if (!hasKeys(validationResult)) {

        this.externalErrorCodeCache = null;
        this.props.validator.clearEndpointURLError(setFieldErrorCache);
      } else {

        const { code } = validationResult;

        if (isConnectionError(code) && code !== this.externalErrorCodeCache) {
          this.props.validator.updateEndpointURLError(code, setFieldErrorCache);
        }

        this.externalErrorCodeCache = code;
      }
    }
  }

  onSetFieldValueReceived = () => {

    // Initial endpoint URL validation. Note that this is not a form validation
    // and should affect only the Endpoint URL field.
    return this.checkEndpointURLConnectivity(true);
  }

  onAppFocusChange = () => {

    // User may fix connection related errors by focusing out from app (turn on wifi, start server etc.)
    // In that case we want to check if errors are fixed when the users focuses back on to the app.
    return this.checkEndpointURLConnectivity();
  }

  onClose = (action = 'cancel', data = null, shouldOverrideCredentials = false) => {

    if (shouldOverrideCredentials) {

      const { valuesCache } = this;
      const { endpoint } = valuesCache;
      const {
        username, password, token, rememberCredentials
      } = endpoint;

      if (rememberCredentials) {
        this.props.saveCredential({ username, password, token });
      } else {
        this.props.removeCredentials();
      }
    }

    this.props.onClose(action, data);
  }

  onSubmit = async (values, { setFieldError }) => {

    const {
      endpoint
    } = values;

    const connectionValidation = await this.props.validator.validateConnection(endpoint);

    if (!hasKeys(connectionValidation)) {
      this.externalErrorCodeCache = null;
      this.onClose('deploy', values);
    } else {

      const {
        details,
        code
      } = connectionValidation;

      if (code === 'UNAUTHORIZED') {
        this.setState({
          isAuthNeeded: true
        });
      }

      this.externalErrorCodeCache = code;
      this.props.validator.onExternalError(values.endpoint.authType, details, code, setFieldError);
    }
  }

  fieldError = (meta) => {
    return meta.error;
  }

  setAuthType = (form) => {

    return event => {

      const authType = event.target.value;

      const {
        values,
        setValues
      } = form;

      let {
        endpoint
      } = values;

      if (authType !== AuthTypes.basic) {
        endpoint = omit(endpoint, [ 'username', 'password' ]);
      }

      if (authType !== AuthTypes.bearer) {
        endpoint = omit(endpoint, [ 'token' ]);
      }

      setValues({
        ...values,
        endpoint: {
          ...endpoint,
          authType
        }
      });
    };

  }

  onAuthDetection = (isAuthNeeded) => {
    this.setState({
      isAuthNeeded
    });
  }

  checkAuthStatus = (values) => {
    this.props.validator.validateConnectionWithoutCredentials(values.endpoint.url).then((result) => {
      if (!result) {
        this.onAuthDetection(false);
      } else if (!result.isExpired) {
        this.onAuthDetection(!!result && (result.code === 'UNAUTHORIZED'));
      }
    });
  }

  render() {

    const {
      fieldError,
      onSubmit,
      onClose,
      onAuthDetection,
      onSetFieldValueReceived
    } = this;

    const {
      configuration: values,
      validator,
      title,
      intro,
      primaryAction
    } = this.props;

    const {
      isAuthNeeded
    } = this.state;

    return (
      <Modal className={ css.DeploymentConfigModal } onClose={ () => {
        onClose('cancel', null, true);
      } }>

        <Formik
          initialValues={ values }
          onSubmit={ onSubmit }
          validateOnBlur={ false }
        >
          { form => {

            this.valuesCache = { ...form.values };
            if (!this.setFieldErrorCache) {
              this.setFieldErrorCache = form.setFieldError;
              onSetFieldValueReceived();
            }

            return (
              <form onSubmit={ form.handleSubmit }>

                <Modal.Title>
                  {
                    title || 'Deploy Diagram'
                  }
                </Modal.Title>

                <Modal.Body>
                  {
                    intro && (

                        { intro }

                    )
                  }
                  <fieldset>

                      <Field
                        name="deployment.name"
                        component={ TextInput }
                        label="Deployment Name"
                        fieldError={ fieldError }
                        validate={ (value) => {
                          return validator.validateDeploymentName(value, this.isOnBeforeSubmit);
                        } }
                        autoFocus
                      />

                      <Field
                        name="deployment.tenantId"
                        component={ TextInput }
                        fieldError={ fieldError }
                        hint="Optional"
                        label="Tenant ID"
                      />

                  </fieldset>

                  <fieldset>
                    <legend>
                      Endpoint Configuration
                    </legend>

                      <Field
                        name="endpoint.url"
                        component={ TextInput }
                        fieldError={ fieldError }
                        validate={ (value) => {
                          this.externalErrorCodeCache = null;
                          return validator.validateEndpointURL(
                            value,
                            form.setFieldError,
                            this.isOnBeforeSubmit,
                            onAuthDetection,
                            (code) => { this.externalErrorCodeCache = code; }
                          );
                        } }
                        label="REST Endpoint"
                        hint="Should point to a running Camunda Engine REST API endpoint."
                      />

                      {
                        isAuthNeeded && (
                          <Field
                            name="endpoint.authType"
                            label="Authentication"
                            component={ Radio }
                            onChange={ (event) => {
                              form.handleChange(event);
                              this.setAuthType(form);
                            } }
                            values={
                              [
                                { value: AuthTypes.basic, label: 'HTTP Basic' },
                                { value: AuthTypes.bearer, label: 'Bearer token' }
                              ]
                            }
                          />
                        )
                      }

                      { isAuthNeeded && form.values.endpoint.authType === AuthTypes.basic && (
                        <React.Fragment>
                          <Field
                            name="endpoint.username"
                            component={ TextInput }
                            fieldError={ fieldError }
                            validate={ (value) => {
                              return validator.validateUsername(value || '', this.isOnBeforeSubmit);
                            } }
                            label="Username"
                          />

                          <Field
                            name="endpoint.password"
                            component={ TextInput }
                            fieldError={ fieldError }
                            validate={ (value) => {
                              return validator.validatePassword(value || '', this.isOnBeforeSubmit);
                            } }
                            label="Password"
                            type="password"
                          />
                        </React.Fragment>
                      )}

                      { isAuthNeeded && form.values.endpoint.authType === AuthTypes.bearer && (
                        <Field
                          name="endpoint.token"
                          component={ TextInput }
                          fieldError={ fieldError }
                          validate={ (value) => {
                            return validator.validateToken(value || '', this.isOnBeforeSubmit);
                          } }
                          label="Token"
                        />
                      )}

                      {
                        isAuthNeeded && (
                          <Field
                            name="endpoint.rememberCredentials"
                            component={ CheckBox }
                            type="checkbox"
                            label="Remember credentials"
                          />
                        )
                      }

                  </fieldset>
                </Modal.Body>

                <Modal.Footer>

                    <button
                      type="button"
                      className="btn btn-secondary"
                      onClick={ () => {
                        onClose('cancel', null, false);
                      } }
                    >
                      Cancel
                    </button>

                    <button
                      type="submit"
                      className="btn btn-primary"
                      disabled={ form.isSubmitting }
                      onClick={ () => {

                        // @oguz:
                        // this is a hack as FormIK does not seem to
                        // set isSubmitting when this button is clicked.
                        // if you come up with a better solution, please
                        // do a PR.
                        this.isOnBeforeSubmit = true;
                        setTimeout(() => {
                          this.isOnBeforeSubmit = false;
                        });
                      } }
                    >
                      { primaryAction || 'Deploy' }
                    </button>

                </Modal.Footer>
              </form>
            );
          } }
        </Formik>
      </Modal>
    );
  }
}

function hasKeys(obj) {
  return obj && Object.keys(obj).length > 0;
}
<|endoftext|>


<commit_before>function DragAndDropBlock(runtime, element) {
    function publish_event(data) {
      $.ajax({
          type: "POST",
          url: runtime.handlerUrl(element, 'publish_event'),
          data: JSON.stringify(data)
      });
    }

    var dragAndDrop = (function($) {
        var _fn = {

            // DOM Elements
            $ul: $('.xblock--drag-and-drop .items', element),
            $target: $('.xblock--drag-and-drop .target-img', element),
            $feedback: $('.xblock--drag-and-drop .feedback .message', element),
            $popup: $('.xblock--drag-and-drop .popup', element),

            // Cannot set until items added to DOM
            $items: {}, // $('.xblock--drag-and-drop .items .option'),
            $zones: {}, // $('.xblock--drag-and-drop .target .zone'),

            // jQuery UI Draggable options
            options: {
                drag: {
                    containment: '.xblock--drag-and-drop .drag-container',
                    cursor: 'move',
                    stack: '.xblock--drag-and-drop .items .option'
                },
                drop: {
                    accept: '.xblock--drag-and-drop .items .option',
                    tolerance: 'pointer'
                }
            },

            tpl: {
                init: function() {
                    _fn.tpl = {
                        item: Handlebars.compile($("#item-tpl", element).html()),
                        imageItem: Handlebars.compile($("#image-item-tpl", element).html()),
                        zoneElement: Handlebars.compile($("#zone-element-tpl", element).html())
                    };
                }
            },

            init: function(data) {
                _fn.data = data;

                // Compile templates
                _fn.tpl.init();

                // Add the items to the page
                _fn.items.draw();
                _fn.zones.draw();

                // Init drag and drop plugin
                _fn.$items.draggable(_fn.options.drag);
                _fn.$zones.droppable(_fn.options.drop);

                // Init click handlers
                _fn.clickHandlers.init(_fn.$items, _fn.$zones);

                // Position the already correct items
                _fn.items.init();

                // Load welcome or final feedback
                if (_fn.data.state.finished)
                    _fn.finish(_fn.data.feedback.finish);
                else
                    _fn.feedback.set(_fn.data.feedback.start);

                // Set the target image
                if (_fn.data.targetImg)
                    _fn.$target.css('background', 'url(' + _fn.data.targetImg + ') no-repeat');
            },

            finish: function(final_feedback) {
                // Disable any decoy items
                _fn.$items.draggable('disable');

                // Show final feedback
                if (final_feedback) _fn.feedback.set(final_feedback);
            },

            clickHandlers: {
                init: function($drag, $dropzone) {
                    var clk = _fn.clickHandlers;

                    $drag.on('dragstart', clk.drag.start);
                    $drag.on('dragstop', clk.drag.stop);

                    $dropzone.on('drop', clk.drop.success);
                    $dropzone.on('dropover', clk.drop.hover);

                    $(".close", _fn.$popup).on('click', function() {
                        _fn.$popup.hide();
                        publish_event({
                            event_type: 'xblock.drag-and-drop-v2.feedback.closed',
                            content: _fn.$popup.find(".popup-content").text()
                        });
                    });
                },
                drag: {
                    start: function(event, ui) {
                        target = $(event.currentTarget);
                        target.removeClass('within-dropzone fade');

                        var item_id = target.data("value");
                        publish_event({event_type:'xblock.drag-and-drop-v2.item.picked-up', item_id:item_id});
                    },

                    stop: function(event, ui) {
                        var $el = $(event.currentTarget),
                            val = $el.data('value'),
                            zone = $el.data('zone') || null;

                        if (!$el.hasClass('within-dropzone')) {
                            // Return to original position
                            _fn.clickHandlers.drag.reset($el);
                            return;
                        }

                        $.post(runtime.handlerUrl(element, 'do_attempt'),
                            JSON.stringify({
                                val: val,
                                zone: zone,
                                top: $el.css('top'),
                                left: $el.css('left')
                        }), 'json').done(function(data){
                            if (data.correct) {
                                $el.draggable('disable');

                                if (data.finished) {
                                    _fn.finish(data.final_feedback);
                                }
                            } else {
                                // Return to original position
                                _fn.clickHandlers.drag.reset($el);
                            }

                            if (data.feedback) {
                                _fn.feedback.popup(data.feedback, data.correct);
                            }
                        });
                    },

                    set: function($el, top, left) {
                        $el.addClass('within-dropzone fade')
                            .css({
                                top: top,
                                left: left
                            })
                            .draggable('disable');
                    },

                    reset: function($el) {
                        $el.removeClass('within-dropzone fade')
                            .css({
                                top: '',
                                left: ''
                            });
                    }
                },
                drop: {
                    hover: function(event, ui) {
                        var zone = $(event.currentTarget).data('zone');
                        ui.draggable.data('zone', zone);
                    },
                    success: function(event, ui) {
                        ui.draggable.addClass('within-dropzone');
                    }
                }
            },

            items: {
                init: function() {
                    _fn.$items.each(function (){
                        var $el = $(this),
                            saved_entry = _fn.data.state.items[$el.data('value')];
                        if (saved_entry) {
                            _fn.clickHandlers.drag.set($el,
                                saved_entry[0], saved_entry[1]);
                        }
                    });
                },
                draw: function() {
                    var list = [],
                        items = _fn.data.items,
                        tpl = _fn.tpl.item,
                        img_tpl = _fn.tpl.imageItem;

                    items.forEach(function(item) {
                        if (item.backgroundImage.length > 0) {
                            list.push(img_tpl(item));
                        } else {
                            list.push(tpl(item));
                        }
                    });

                    // Update DOM
                    _fn.$ul.html(list.join(''));

                    // Set variable
                    _fn.$items = $('.xblock--drag-and-drop .items .option', element);
                }
            },

            zones: {
                draw: function() {
                    var html = [],
                        zones = _fn.data.zones,
                        tpl = _fn.tpl.zoneElement,
                        i,
                        len = zones.length;

                    for (i=0; i<len; i++) {
                        html.push(tpl(zones[i]));
                    }

                    // Update DOM
                    _fn.$target.html(html.join(''));

                    // Set variable
                    _fn.$zones = _fn.$target.find('.zone');
                }
            },

            feedback: {
                // Update DOM with feedback
                set: function(str) {
                    if ($.trim(str) === '') _fn.$feedback.parent().hide();
                    else _fn.$feedback.parent().show();
                    return _fn.$feedback.html(str);
                },

                // Show a feedback popup
                popup: function(str, boo) {
                    if (str === undefined || str === '') return;

                    if (_fn.$popup.is(":visible")) {
                        publish_event({
                            event_type: "xblock.drag-and-drop-v2.feedback.replaced",
                            old: _fn.$popup.find(".popup-content").text(),
                            new: str
                        });
                    } else {
                        publish_event({
                            event_type: "xblock.drag-and-drop-v2.feedback.opened",
                            content: str
                        });
                    }

                    _fn.$popup.find(".popup-content").text(str);
                    return _fn.$popup.show();
                }
            },

            data: null
        };

        return {
            init: _fn.init,
        };
    })(jQuery);

    $.ajax(runtime.handlerUrl(element, 'get_data'), {
        dataType: 'json'
    }).done(function(data){
        dragAndDrop.init(data);
    });

    publish_event({event_type:"xblock.drag-and-drop-v2.loaded"});
}
<commit_msg>Publish close and open event instead of replace<commit_after>function DragAndDropBlock(runtime, element) {
    function publish_event(data) {
      $.ajax({
          type: "POST",
          url: runtime.handlerUrl(element, 'publish_event'),
          data: JSON.stringify(data)
      });
    }

    var dragAndDrop = (function($) {
        var _fn = {

            // DOM Elements
            $ul: $('.xblock--drag-and-drop .items', element),
            $target: $('.xblock--drag-and-drop .target-img', element),
            $feedback: $('.xblock--drag-and-drop .feedback .message', element),
            $popup: $('.xblock--drag-and-drop .popup', element),

            // Cannot set until items added to DOM
            $items: {}, // $('.xblock--drag-and-drop .items .option'),
            $zones: {}, // $('.xblock--drag-and-drop .target .zone'),

            // jQuery UI Draggable options
            options: {
                drag: {
                    containment: '.xblock--drag-and-drop .drag-container',
                    cursor: 'move',
                    stack: '.xblock--drag-and-drop .items .option'
                },
                drop: {
                    accept: '.xblock--drag-and-drop .items .option',
                    tolerance: 'pointer'
                }
            },

            tpl: {
                init: function() {
                    _fn.tpl = {
                        item: Handlebars.compile($("#item-tpl", element).html()),
                        imageItem: Handlebars.compile($("#image-item-tpl", element).html()),
                        zoneElement: Handlebars.compile($("#zone-element-tpl", element).html())
                    };
                }
            },

            init: function(data) {
                _fn.data = data;

                // Compile templates
                _fn.tpl.init();

                // Add the items to the page
                _fn.items.draw();
                _fn.zones.draw();

                // Init drag and drop plugin
                _fn.$items.draggable(_fn.options.drag);
                _fn.$zones.droppable(_fn.options.drop);

                // Init click handlers
                _fn.clickHandlers.init(_fn.$items, _fn.$zones);

                // Position the already correct items
                _fn.items.init();

                // Load welcome or final feedback
                if (_fn.data.state.finished)
                    _fn.finish(_fn.data.feedback.finish);
                else
                    _fn.feedback.set(_fn.data.feedback.start);

                // Set the target image
                if (_fn.data.targetImg)
                    _fn.$target.css('background', 'url(' + _fn.data.targetImg + ') no-repeat');
            },

            finish: function(final_feedback) {
                // Disable any decoy items
                _fn.$items.draggable('disable');

                // Show final feedback
                if (final_feedback) _fn.feedback.set(final_feedback);
            },

            clickHandlers: {
                init: function($drag, $dropzone) {
                    var clk = _fn.clickHandlers;

                    $drag.on('dragstart', clk.drag.start);
                    $drag.on('dragstop', clk.drag.stop);

                    $dropzone.on('drop', clk.drop.success);
                    $dropzone.on('dropover', clk.drop.hover);

                    $(".close", _fn.$popup).on('click', function() {
                        _fn.$popup.hide();
                        publish_event({
                            event_type: 'xblock.drag-and-drop-v2.feedback.closed',
                            content: _fn.$popup.find(".popup-content").text(),
                            manually: true
                        });
                    });
                },
                drag: {
                    start: function(event, ui) {
                        target = $(event.currentTarget);
                        target.removeClass('within-dropzone fade');

                        var item_id = target.data("value");
                        publish_event({event_type:'xblock.drag-and-drop-v2.item.picked-up', item_id:item_id});
                    },

                    stop: function(event, ui) {
                        var $el = $(event.currentTarget),
                            val = $el.data('value'),
                            zone = $el.data('zone') || null;

                        if (!$el.hasClass('within-dropzone')) {
                            // Return to original position
                            _fn.clickHandlers.drag.reset($el);
                            return;
                        }

                        $.post(runtime.handlerUrl(element, 'do_attempt'),
                            JSON.stringify({
                                val: val,
                                zone: zone,
                                top: $el.css('top'),
                                left: $el.css('left')
                        }), 'json').done(function(data){
                            if (data.correct) {
                                $el.draggable('disable');

                                if (data.finished) {
                                    _fn.finish(data.final_feedback);
                                }
                            } else {
                                // Return to original position
                                _fn.clickHandlers.drag.reset($el);
                            }

                            if (data.feedback) {
                                _fn.feedback.popup(data.feedback, data.correct);
                            }
                        });
                    },

                    set: function($el, top, left) {
                        $el.addClass('within-dropzone fade')
                            .css({
                                top: top,
                                left: left
                            })
                            .draggable('disable');
                    },

                    reset: function($el) {
                        $el.removeClass('within-dropzone fade')
                            .css({
                                top: '',
                                left: ''
                            });
                    }
                },
                drop: {
                    hover: function(event, ui) {
                        var zone = $(event.currentTarget).data('zone');
                        ui.draggable.data('zone', zone);
                    },
                    success: function(event, ui) {
                        ui.draggable.addClass('within-dropzone');
                    }
                }
            },

            items: {
                init: function() {
                    _fn.$items.each(function (){
                        var $el = $(this),
                            saved_entry = _fn.data.state.items[$el.data('value')];
                        if (saved_entry) {
                            _fn.clickHandlers.drag.set($el,
                                saved_entry[0], saved_entry[1]);
                        }
                    });
                },
                draw: function() {
                    var list = [],
                        items = _fn.data.items,
                        tpl = _fn.tpl.item,
                        img_tpl = _fn.tpl.imageItem;

                    items.forEach(function(item) {
                        if (item.backgroundImage.length > 0) {
                            list.push(img_tpl(item));
                        } else {
                            list.push(tpl(item));
                        }
                    });

                    // Update DOM
                    _fn.$ul.html(list.join(''));

                    // Set variable
                    _fn.$items = $('.xblock--drag-and-drop .items .option', element);
                }
            },

            zones: {
                draw: function() {
                    var html = [],
                        zones = _fn.data.zones,
                        tpl = _fn.tpl.zoneElement,
                        i,
                        len = zones.length;

                    for (i=0; i<len; i++) {
                        html.push(tpl(zones[i]));
                    }

                    // Update DOM
                    _fn.$target.html(html.join(''));

                    // Set variable
                    _fn.$zones = _fn.$target.find('.zone');
                }
            },

            feedback: {
                // Update DOM with feedback
                set: function(str) {
                    if ($.trim(str) === '') _fn.$feedback.parent().hide();
                    else _fn.$feedback.parent().show();
                    return _fn.$feedback.html(str);
                },

                // Show a feedback popup
                popup: function(str, boo) {
                    if (str === undefined || str === '') return;

                    if (_fn.$popup.is(":visible")) {
                        publish_event({
                            event_type: "xblock.drag-and-drop-v2.feedback.closed",
                            content: _fn.$popup.find(".popup-content").text(),
                            manually: false
                        });
                    };
                    publish_event({
                        event_type: "xblock.drag-and-drop-v2.feedback.opened",
                        content: str
                    });

                    _fn.$popup.find(".popup-content").text(str);
                    return _fn.$popup.show();
                }
            },

            data: null
        };

        return {
            init: _fn.init,
        };
    })(jQuery);

    $.ajax(runtime.handlerUrl(element, 'get_data'), {
        dataType: 'json'
    }).done(function(data){
        dragAndDrop.init(data);
    });

    publish_event({event_type:"xblock.drag-and-drop-v2.loaded"});
}
<|endoftext|>


<commit_before>var yargs = require('yargs');

var argv = yargs.usage('This is my awesome program', {
  'about': {
    description: 'Provide some details about the author of this program',
    required: true,
    short: 'a',
  },
  'info': {
    description: 'Provide some information about the node.js agains!!!!!!',
    boolean: true,
    short: 'i'
  }
}).argv;

yargs.showHelp();

console.log('\n\nInspecting options');
console.dir(argv);
<commit_msg>Replaced short with alias in example. Resolves #28<commit_after>var yargs = require('yargs');

var argv = yargs.usage('This is my awesome program', {
  'about': {
    description: 'Provide some details about the author of this program',
    required: true,
    alias: 'a',
  },
  'info': {
    description: 'Provide some information about the node.js agains!!!!!!',
    boolean: true,
    alias: 'i'
  }
}).argv;

yargs.showHelp();

console.log('\n\nInspecting options');
console.dir(argv);
<|endoftext|>


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

module.exports = {
  setDB: function(newDb) {
    db = require(newDb);
  },

  getAllDrivers: function(){
    QUERY = "SELECT * From driver";
    return db.query(QUERY);
  },

  addDriver: function(name, phone, late_count){
    QUERY = "INSERT INTO driver (name, phone, late_count) VALUES ('" + name + "', '" + phone + "', " + late_count + ") RETURNING *";
    return db.query(QUERY);
  },

  deleteDriver: function(driverID){
    QUERY = "DELETE FROM driver WHERE id=$1 RETURNING $1 AS id";
    ARGS = [driverID];
    return db.query(QUERY, ARGS);
  },

  updateDriver: function(driverID, name, phone, late_count){
    QUERY = "UPDATE driver SET name='" + name + "', phone='" + phone + "', late_count=" + late_count + " WHERE id=" + driverID + " RETURNING *";
    // ARGS = [driverID, name, phone, late_count];
    return db.query(QUERY);
  },

  getDriverByID: function(driverID){
    return db.query("SELECT * FROM driver WHERE id=$1",[driverID]);
  }
}
<commit_msg>Fixed lowercase SQL request in driver manager<commit_after>var db = require('./db');

module.exports = {
  setDB: function(newDb) {
    db = require(newDb);
  },

  getAllDrivers: function(){
    QUERY = "SELECT * FROM driver";
    return db.query(QUERY);
  },

  addDriver: function(name, phone, late_count){
    QUERY = "INSERT INTO driver (name, phone, late_count) VALUES ('" + name + "', '" + phone + "', " + late_count + ") RETURNING *";
    return db.query(QUERY);
  },

  deleteDriver: function(driverID){
    QUERY = "DELETE FROM driver WHERE id=$1 RETURNING $1 AS id";
    ARGS = [driverID];
    return db.query(QUERY, ARGS);
  },

  updateDriver: function(driverID, name, phone, late_count){
    QUERY = "UPDATE driver SET name='" + name + "', phone='" + phone + "', late_count=" + late_count + " WHERE id=" + driverID + " RETURNING *";
    // ARGS = [driverID, name, phone, late_count];
    return db.query(QUERY);
  },

  getDriverByID: function(driverID){
    return db.query("SELECT * FROM driver WHERE id=$1",[driverID]);
  }
}
<|endoftext|>


<commit_before>var onRun = function(context) {
    var manager,
        doc = context.document,
        command = context.command,
        identifier = command.identifier(),
        resourcesPath = command.pluginBundle().url().path(),
        language = NSUserDefaults.standardUserDefaults().objectForKey("AppleLanguages").objectAtIndex(0),
        languagePath = resourcesPath + "/Contents/Resources/i18n/" + language + ".json";

    if (NSFileManager.defaultManager().fileExistsAtPath(languagePath)) {
        var mocha = Mocha.sharedRuntime();
        i18n = [NSString stringWithContentsOfFile: languagePath encoding: NSUTF8StringEncoding error: nil];

        if (!NSClassFromString("SketchI18NPluginManager")) {
            mocha.loadFrameworkWithName_inDirectory("SketchI18NPlugin", resourcesPath + "/Contents/Resources");
            manager = SketchI18NPluginManager.manager();
            manager.loadStrings(i18n);
        } else {
            manager = SketchI18NPluginManager.manager();
        }
        if (identifier == "i18n-toggle-command") {
            manager.toggle();
        } else {
            manager.run();
        }
    }
}
<commit_msg>fix macOS locale issues #47<commit_after>var onRun = function(context) {
    var manager,
        languagePath,
        doc = context.document,
        command = context.command,
        identifier = command.identifier(),
        resourcesPath = command.pluginBundle().url().path(),
        language = NSUserDefaults.standardUserDefaults().objectForKey("AppleLanguages").objectAtIndex(0);

    for(;;){
        languagePath = resourcesPath + "/Contents/Resources/i18n/" + language + ".json";
        if (NSFileManager.defaultManager().fileExistsAtPath(languagePath)) {
            break;
        }
        else {
            var index = language.lastIndexOf("-");
            if (index == -1) {
                return;
            }
            language = language.substring(0, index);
        }
    }

    if (!NSClassFromString("SketchI18NPluginManager")) {
        var mocha = Mocha.sharedRuntime();
        mocha.loadFrameworkWithName_inDirectory("SketchI18NPlugin", resourcesPath + "/Contents/Resources");
        manager = SketchI18NPluginManager.manager();
        var i18n = NSString.stringWithContentsOfFile_encoding_error(languagePath, NSUTF8StringEncoding, nil);
        manager.loadStrings(i18n);
    } else {
        manager = SketchI18NPluginManager.manager();
    }

    if (identifier == "i18n-toggle-command") {
        manager.toggle();
    } else {
        manager.run();
    }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import moment from 'moment';
import { filter, map, forEach } from 'lodash';
import { nextConnect } from '../../store';
import { getAttendees } from '../../actions';

class TicketTrackerDetails extends Component {

  constructor(props) {
    super(props);
    this.state = { sales: [] };
  }

  componentWillMount() {
    this.props.getAttendees(this.props.id);
  }

  componentWillReceiveProps(nextProps) {
    const { attendees, profile } = nextProps;
    const sales = filter(attendees, (attendee) => attendee.affiliate === profile.user_token);
    this.setState({ sales });
  }

  totalSales() {
    let count = 0;
    forEach(this.state.sales, (sale) => {
      count = count + sale.costs.base_price.value / 2000;
      return count;
    });
    return count;
  }

  render() {
    if (this.state.sales.length === 0) {
      return
Loading ticket tracker...
;
    }
    const totalAmtSold = this.totalSales();
    const remaining = 15 - totalAmtSold;
    return (

{this.props.name.text} Show -
            {moment(this.props.start.local).format('MMMM Do YYYY')}

                BUYER
                AMOUNT
                TICKET SOLD
                EMAIL

              {this.state.sales.length !== 0 && map(this.state.sales, (sale) => (

                  {sale.profile.name}
                  {sale.costs.base_price.display}
                  {sale.costs.base_price.value / 2000}
                  {sale.profile.email}

))}

              {this.state.sales.length === 0 &&

No sales yet
}

              Total Tickets: 15

              Sold: {totalAmtSold}

              Remaining: {remaining < 0 ? 0 : remaining}

                BUYOUT TICKETS

    );
  }

}

TicketTrackerDetails.propTypes = {
  name: React.PropTypes.object,
  start: React.PropTypes.object,
  getAttendees: React.PropTypes.func,
  id: React.PropTypes.string,
};

function mapStateToProps(state) {
  return {
    attendees: state.attendees,
    profile: state.profile,
  };
}

export default nextConnect(mapStateToProps, { getAttendees })(TicketTrackerDetails);
<commit_msg>updates<commit_after>import React, { Component } from 'react';
import moment from 'moment';
import { filter, map, forEach } from 'lodash';
import { nextConnect } from '../../store';
import { getAttendees } from '../../actions';

class TicketTrackerDetails extends Component {

  constructor(props) {
    super(props);
    this.state = { sales: [] };
  }

  componentWillMount() {
    this.props.getAttendees(this.props.id);
  }

  componentWillReceiveProps(nextProps) {
    const { attendees, profile } = nextProps;
    const sales = filter(attendees, (attendee) => attendee.affiliate === profile.user_token);
    this.setState({ sales });
  }

  totalSales() {
    let count = 0;
    forEach(this.state.sales, (sale) => {
      count = count + sale.costs.base_price.value / 2000;
      return count;
    });
    return count;
  }

  render() {
    if (this.state.sales.length === 0) {
      return
No sales
;
    }
    const totalAmtSold = this.totalSales();
    const remaining = 15 - totalAmtSold;
    return (

{this.props.name.text} Show -
            {moment(this.props.start.local).format('MMMM Do YYYY')}

                BUYER
                AMOUNT
                TICKET SOLD
                EMAIL

              {this.state.sales.length !== 0 && map(this.state.sales, (sale) => (

                  {sale.profile.name}
                  {sale.costs.base_price.display}
                  {sale.costs.base_price.value / 2000}
                  {sale.profile.email}

))}

              {this.state.sales.length === 0 &&

No sales yet
}

              Total Tickets: 15

              Sold: {totalAmtSold}

              Remaining: {remaining < 0 ? 0 : remaining}

                BUYOUT TICKETS

    );
  }

}

TicketTrackerDetails.propTypes = {
  name: React.PropTypes.object,
  start: React.PropTypes.object,
  getAttendees: React.PropTypes.func,
  id: React.PropTypes.string,
};

function mapStateToProps(state) {
  return {
    attendees: state.attendees,
    profile: state.profile,
  };
}

export default nextConnect(mapStateToProps, { getAttendees })(TicketTrackerDetails);
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import debounce from 'lodash/debounce';
import PropTypes from 'prop-types';
import { toastr } from 'react-redux-toastr';

// Redux
import { connect } from 'react-redux';

// Services
import { fetchDashboards } from 'services/dashboard';

// Components
import Spinner from 'components/ui/Spinner';
import CustomTable from 'components/ui/customtable/CustomTable';
import SearchInput from 'components/ui/SearchInput';
import TableFilters from 'components/admin/table-filters';

// constants
import { INITIAL_PAGINATION } from './constants';

// Table components
import EditAction from './actions/EditAction';
import DeleteAction from './actions/DeleteAction';

// TDs
import NameTD from './td/name';
import OwnerTD from './td/owner';
import RoleTD from './td/role';
import PublishedTD from './td/published';
import PreviewTD from './td/preview';

class DashboardsTable extends PureComponent {
  static propTypes = { user: PropTypes.object.isRequired };

  state = {
    dashboards: [],
    pagination: INITIAL_PAGINATION,
    filters: { name: null, 'user.role': 'ADMIN' },
    loading: false
  };

  componentWillMount() {
    this.loadDashboards();
  }

  onFiltersChange = (value) => {
    this.setState({
      filters: {
        ...this.state.filters,
        'user.role': value.value
      }
    },
    () => this.loadDashboards());
  }

  /**
   * Event handler executed when the user search for a dataset
   * @param {string} { value } Search keywords
   */
  onSearch = debounce((value) => {
    const { filters } = this.state;

    if (value.length > 0 && value.length < 3) return;

    this.setState({
      loading: true,
      filters: {
        ...filters,
        name: value
      },
      pagination: INITIAL_PAGINATION
    }, () => this.loadDashboards());
  }, 250)

  onChangePage = (page) => {
    const { pagination } = this.state;

    this.setState({
      pagination: {
        ...pagination,
        page
      }
    });
  }

  loadDashboards = () => {
    const { user: { token } } = this.props;
    const { pagination, filters } = this.state;

    this.setState({ loading: true });

    fetchDashboards(
      {
        includes: 'user',
        ...filters,
        'page[number]': pagination.page,
        'page[size]': pagination.limit,
        application: process.env.APPLICATIONS,
        env: process.env.API_ENV
      },
      { Authorization: token },
      true
    )
      .then(({ dashboards, meta }) => {
        const {
          'total-pages': pages,
          'total-items': size
        } = meta;
        const nextPagination = {
          ...pagination,
          size,
          pages
        };

        this.setState({
          loading: false,
          dashboards: dashboards.map(_dashboard => ({
            ..._dashboard,
            owner: _dashboard.user ? _dashboard.user.name || (_dashboard.user.email || '').split('@')[0] : '',
            role: _dashboard.user ? _dashboard.user.role || '' : ''
          })),
          pagination: nextPagination
        });
      })
      .catch(error => toastr.error('There was an error loading the dashboards', error));
  }

  render() {
    const { pagination, loading, dashboards } = this.state;

    return (

        <Spinner className="-light" isLoading={loading} />

        <TableFilters
          filtersChange={this.onFiltersChange}
        />

        <SearchInput
          input={{ placeholder: 'Search dashboard' }}
          link={{
            label: 'New dashboard',
            route: 'admin_dashboards_detail',
            params: { tab: 'dashboards', id: 'new' }
          }}
          onSearch={this.onSearch}
        />

        <CustomTable
          columns={[
            { label: 'Name', value: 'name', td: NameTD },
            { label: 'Owner', value: 'owner', td: OwnerTD },
            { label: 'Role', value: 'role', td: RoleTD },
            { label: 'Preview', value: 'slug', td: PreviewTD },
            { label: 'Published', value: 'published', td: PublishedTD }
          ]}
          actions={{
            show: true,
            list: [
              { name: 'Edit', route: 'admin_dashboards_detail', params: { tab: 'dashboards', subtab: 'edit', id: '{{id}}' }, show: true, component: EditAction },
              { name: 'Remove', route: 'admin_dashboards_detail', params: { tab: 'dashboards', subtab: 'remove', id: '{{id}}' }, component: DeleteAction }
            ]
          }}
          sort={{
            field: 'name',
            value: 1
          }}
          filters={false}
          data={dashboards}
          onChangePage={this.onChangePage}
          onRowDelete={() => this.loadDashboards()}
          pagination={pagination}
        />

    );
  }
}

const mapStateToProps = state => ({ user: state.user });

export default connect(mapStateToProps, null)(DashboardsTable);
<commit_msg>fix page change<commit_after>import React, { PureComponent } from 'react';
import debounce from 'lodash/debounce';
import PropTypes from 'prop-types';
import { toastr } from 'react-redux-toastr';

// Redux
import { connect } from 'react-redux';

// Services
import { fetchDashboards } from 'services/dashboard';

// Components
import Spinner from 'components/ui/Spinner';
import CustomTable from 'components/ui/customtable/CustomTable';
import SearchInput from 'components/ui/SearchInput';
import TableFilters from 'components/admin/table-filters';

// constants
import { INITIAL_PAGINATION } from './constants';

// Table components
import EditAction from './actions/EditAction';
import DeleteAction from './actions/DeleteAction';

// TDs
import NameTD from './td/name';
import OwnerTD from './td/owner';
import RoleTD from './td/role';
import PublishedTD from './td/published';
import PreviewTD from './td/preview';

class DashboardsTable extends PureComponent {
  static propTypes = { user: PropTypes.object.isRequired };

  state = {
    dashboards: [],
    pagination: INITIAL_PAGINATION,
    filters: { name: null, 'user.role': 'ADMIN' },
    loading: false
  };

  componentWillMount() {
    this.loadDashboards();
  }

  onFiltersChange = (value) => {
    this.setState({
      filters: {
        ...this.state.filters,
        'user.role': value.value
      }
    },
    () => this.loadDashboards());
  }

  /**
   * Event handler executed when the user search for a dataset
   * @param {string} { value } Search keywords
   */
  onSearch = debounce((value) => {
    const { filters } = this.state;

    if (value.length > 0 && value.length < 3) return;

    this.setState({
      loading: true,
      filters: {
        ...filters,
        name: value
      },
      pagination: INITIAL_PAGINATION
    }, () => this.loadDashboards());
  }, 250)

  onChangePage = (page) => {
    const { pagination } = this.state;

    this.setState({
      pagination: {
        ...pagination,
        page
      }
    }, () => this.loadDashboards());
  }

  loadDashboards = () => {
    const { user: { token } } = this.props;
    const { pagination, filters } = this.state;

    this.setState({ loading: true });

    fetchDashboards(
      {
        includes: 'user',
        ...filters,
        'page[number]': pagination.page,
        'page[size]': pagination.limit,
        application: process.env.APPLICATIONS,
        env: process.env.API_ENV
      },
      { Authorization: token },
      true
    )
      .then(({ dashboards, meta }) => {
        const {
          'total-pages': pages,
          'total-items': size
        } = meta;
        const nextPagination = {
          ...pagination,
          size,
          pages
        };

        this.setState({
          loading: false,
          dashboards: dashboards.map(_dashboard => ({
            ..._dashboard,
            owner: _dashboard.user ? _dashboard.user.name || (_dashboard.user.email || '').split('@')[0] : '',
            role: _dashboard.user ? _dashboard.user.role || '' : ''
          })),
          pagination: nextPagination
        });
      })
      .catch(error => toastr.error('There was an error loading the dashboards', error));
  }

  render() {
    const { pagination, loading, dashboards } = this.state;

    return (

        <Spinner className="-light" isLoading={loading} />

        <TableFilters
          filtersChange={this.onFiltersChange}
        />

        <SearchInput
          input={{ placeholder: 'Search dashboard' }}
          link={{
            label: 'New dashboard',
            route: 'admin_dashboards_detail',
            params: { tab: 'dashboards', id: 'new' }
          }}
          onSearch={this.onSearch}
        />

        <CustomTable
          columns={[
            { label: 'Name', value: 'name', td: NameTD },
            { label: 'Owner', value: 'owner', td: OwnerTD },
            { label: 'Role', value: 'role', td: RoleTD },
            { label: 'Preview', value: 'slug', td: PreviewTD },
            { label: 'Published', value: 'published', td: PublishedTD }
          ]}
          actions={{
            show: true,
            list: [
              { name: 'Edit', route: 'admin_dashboards_detail', params: { tab: 'dashboards', subtab: 'edit', id: '{{id}}' }, show: true, component: EditAction },
              { name: 'Remove', route: 'admin_dashboards_detail', params: { tab: 'dashboards', subtab: 'remove', id: '{{id}}' }, component: DeleteAction }
            ]
          }}
          sort={{
            field: 'name',
            value: 1
          }}
          filters={false}
          data={dashboards}
          onChangePage={this.onChangePage}
          onRowDelete={() => this.loadDashboards()}
          pagination={pagination}
        />

    );
  }
}

const mapStateToProps = state => ({ user: state.user });

export default connect(mapStateToProps, null)(DashboardsTable);
<|endoftext|>


<commit_before>// overriding Array.map
Array.prototype.map = function(f) {

	if(typeof f !== 'function') {
		throw new Error('Arguments passed in to .map() should be a function');
	}

	var len = this.length,
		index,
		results = [],
		currVal;

	for(index = 0; index < len; index++) {
		currVal = f.call(this,this[index]);
		if(currVal) {
			results.push(currVal);
		}
	}

	return results;
};

var arr = [1,2,3,4];

var odd = function(a) {
	if(a % 2 !== 0) {
		return a;
	}
};

var increment = function(a) {
	return a+= 1;
};

var oddElements = arr.map(odd);
var incrementedElements = arr.map(increment);

console.log(oddElements);
console.log(incrementedElements);

/*************** Overriding Array.push() ********************/

Array.prototype.push = function() {

	if(!arguments.length) {
		throw new Error('Array.push() requires a value to be inserted');
	}

	// only accept one argument to be pushed irrespective of the variables passed in
	this[this.length] = arguments[0];
};

var arr = [];

arr.push(23);
arr.push('some string');
arr.push({'name' : "Pranay"});

console.log(arr);

/*************** Overriding Array.pop() ********************/

Array.prototype.pop = function() {

	if(!this.length) {
		return;
	}

	this.length = (this.length - 1);
};

var arr = [1,2,3,4,5];

arr.pop();
arr.pop();

console.log(arr);

/*************** Overriding Array.splice() ********************/

Array.prototype.splice = function(from,to) {

	if(typeof from !== 'number' || typeof to !== 'number') {
		throw new Error('Arguments passed in to Array.splice() should be numbers');
		return;
	}

	var index = 1,
		diff = to - from,
		len = this.length;
	diff += 1;
	var cloneDiff = diff;

	while(to < len) {
		this[from] = this[to + 1];
		to+= 1;
		from+= 1;
	}

	this.length = (this.length - cloneDiff);
};

var arr = [1,2,3,4,5,6,7];

arr.splice(1,3);

console.log(arr);

/*************** Overriding Array.slice() ********************/

Array.prototype.slice = function(from,to) {

	if(typeof from !== 'number' || typeof to !== 'number') {
		throw new Error('Arguments passed in Array.slice() should be numbers');
		return;
	}

	var result = [],
		currVal,
		index = 0;

	while(from <= to) {
		currVal = this[from];
		if(currVal) {
			result[index] = currVal;
			index++;
		}
		from++;
	}

	return result;
};

var arr = [1,2,3,4,5];

var slicedArray = arr.slice(1,3);

console.log(slicedArray);

/*************** Overriding Array.every() ********************/

Array.prototype.every = function(fn) {

	if(!fn || typeof(fn) !== 'function') {
		throw new Error('arguments passed in .every() must be function');
		return;
	}

	var valid = true,
			len = this.length;

	while(len--) {
		valid = fn.call({},this[len]);
		if(!valid) {
			break;
		}
	}

	return valid;
};

var arr = [1,2,3,4,5];

var isValid = arr.every(function(a){
	return a < 10;
});

console.log('All elements are lesser than 10?',isValid);

isValid = arr.every(function(a){
	return (a % 2 == 0);
});

console.log('All elements are even?',isValid);

/*************** Overriding Array.concat() ********************/

Array.prototype.concat = function(arguments) {

	if(!arguments.length) {
		return this;
	}

	var len = arguments.length,
		originalArray = this,
		cloneArray = [],
		index = 0,
		currElem;

	while(index < this.length) {
		cloneArray[index] = this[index];
		index++;
	}

	index = 0;

	var processArray = function(originalArray,elemArray) {
		var len = elemArray.length,
			originalLength = originalArray.length,
			index = 0,
			currElem;

		while(index < len) {
			currElem = elemArray[index];
			if(currElem.constructor == Array) {
				processArray(elemArray,currElem);
			}
			index++;
		}

		index = 0;

		while(index < elemArray.length) {
			originalArray[originalLength] = elemArray[index];
			originalLength++;
		}

		return originalArray;
	}

	while(index < len) {

		currElem = arguments[index];

		if(currElem.constructor == Array) {
			processArray(cloneArray,currElem);
			index++;
			continue;
		}

		cloneArray[cloneArray.length] = currElem;
		index++;
	}

	return cloneArray;
};

var arr = [2,3,4];
var arrToConcat = [5,6,7,'something'];

console.log(arr.concat(arrToConcat));
console.log(arr);<commit_msg>Override definition for Array.some()<commit_after>// overriding Array.map
Array.prototype.map = function(f) {

	if(typeof f !== 'function') {
		throw new Error('Arguments passed in to .map() should be a function');
	}

	var len = this.length,
		index,
		results = [],
		currVal;

	for(index = 0; index < len; index++) {
		currVal = f.call(this,this[index]);
		if(currVal) {
			results.push(currVal);
		}
	}

	return results;
};

var arr = [1,2,3,4];

var odd = function(a) {
	if(a % 2 !== 0) {
		return a;
	}
};

var increment = function(a) {
	return a+= 1;
};

var oddElements = arr.map(odd);
var incrementedElements = arr.map(increment);

console.log(oddElements);
console.log(incrementedElements);

/*************** Overriding Array.push() ********************/

Array.prototype.push = function() {

	if(!arguments.length) {
		throw new Error('Array.push() requires a value to be inserted');
	}

	// only accept one argument to be pushed irrespective of the variables passed in
	this[this.length] = arguments[0];
};

var arr = [];

arr.push(23);
arr.push('some string');
arr.push({'name' : "Pranay"});

console.log(arr);

/*************** Overriding Array.pop() ********************/

Array.prototype.pop = function() {

	if(!this.length) {
		return;
	}

	this.length = (this.length - 1);
};

var arr = [1,2,3,4,5];

arr.pop();
arr.pop();

console.log(arr);

/*************** Overriding Array.splice() ********************/

Array.prototype.splice = function(from,to) {

	if(typeof from !== 'number' || typeof to !== 'number') {
		throw new Error('Arguments passed in to Array.splice() should be numbers');
		return;
	}

	var index = 1,
		diff = to - from,
		len = this.length;
	diff += 1;
	var cloneDiff = diff;

	while(to < len) {
		this[from] = this[to + 1];
		to+= 1;
		from+= 1;
	}

	this.length = (this.length - cloneDiff);
};

var arr = [1,2,3,4,5,6,7];

arr.splice(1,3);

console.log(arr);

/*************** Overriding Array.slice() ********************/

Array.prototype.slice = function(from,to) {

	if(typeof from !== 'number' || typeof to !== 'number') {
		throw new Error('Arguments passed in Array.slice() should be numbers');
		return;
	}

	var result = [],
		currVal,
		index = 0;

	while(from <= to) {
		currVal = this[from];
		if(currVal) {
			result[index] = currVal;
			index++;
		}
		from++;
	}

	return result;
};

var arr = [1,2,3,4,5];

var slicedArray = arr.slice(1,3);

console.log(slicedArray);

/*************** Overriding Array.every() ********************/

Array.prototype.every = function(fn) {

	if(!fn || typeof(fn) !== 'function') {
		throw new Error('arguments passed in .every() must be function');
		return;
	}

	var valid = true,
			len = this.length;

	while(len--) {
		valid = fn.call({},this[len]);
		if(!valid) {
			break;
		}
	}

	return valid;
};

var arr = [1,2,3,4,5];

var isValid = arr.every(function(a){
	return a < 10;
});

console.log('All elements are lesser than 10?',isValid);

isValid = arr.every(function(a){
	return (a % 2 == 0);
});

console.log('All elements are even?',isValid);

/*************** Overriding Array.some() ********************/

Array.prototype.some = function(fn) {

	if(!fn || typeof(fn) !== 'function') {
		throw new Error('arguments passed in .some() must be function');
		return;
	}

	var valid = false,
			len = this.length;

	while(len--) {
		valid = fn.call({},this[len]);
		if(valid) {
			break;
		}
	}

	return valid;
};

var arr = [1,2,3,4,5];

var isValid = arr.some(function(a){
	return a < 10;
});

console.log('Some elements are lesser than 10?',isValid);

isValid = arr.some(function(a){
	return (a % 2 == 0);
});

console.log('Some elements are even?',isValid);

/*************** Overriding Array.concat() ********************/

Array.prototype.concat = function(arguments) {

	if(!arguments.length) {
		return this;
	}

	var len = arguments.length,
		originalArray = this,
		cloneArray = [],
		index = 0,
		currElem;

	while(index < this.length) {
		cloneArray[index] = this[index];
		index++;
	}

	index = 0;

	var processArray = function(originalArray,elemArray) {
		var len = elemArray.length,
			originalLength = originalArray.length,
			index = 0,
			currElem;

		while(index < len) {
			currElem = elemArray[index];
			if(currElem.constructor == Array) {
				processArray(elemArray,currElem);
			}
			index++;
		}

		index = 0;

		while(index < elemArray.length) {
			originalArray[originalLength] = elemArray[index];
			originalLength++;
		}

		return originalArray;
	}

	while(index < len) {

		currElem = arguments[index];

		if(currElem.constructor == Array) {
			processArray(cloneArray,currElem);
			index++;
			continue;
		}

		cloneArray[cloneArray.length] = currElem;
		index++;
	}

	return cloneArray;
};

var arr = [2,3,4];
var arrToConcat = [5,6,7,'something'];

console.log(arr.concat(arrToConcat));
console.log(arr);<|endoftext|>


<commit_before>/* global Y */
'use strict'

function extend (Y) {
  class YArray extends Y.utils.CustomType {
    constructor (os, _model, _content) {
      super()
      this.os = os
      this._model = _model
      // Array of all the neccessary content
      this._content = _content

      // the parent of this type
      this._parent = null
      this._deepEventHandler = new Y.utils.EventListenerHandler()

      // this._debugEvents = [] // TODO: remove!!
      this.eventHandler = new Y.utils.EventHandler((op) => {
        // this._debugEvents.push(JSON.parse(JSON.stringify(op)))
        if (op.struct === 'Insert') {
          // when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
          if (this._content.some(function (c) { return Y.utils.compareIds(c.id, op.id) })) {
            // op exists
            return
          }
          let pos
          // we check op.left only!,
          // because op.right might not be defined when this is called
          if (op.left === null) {
            pos = 0
          } else {
            pos = 1 + this._content.findIndex(function (c) {
              return Y.utils.compareIds(c.id, op.left)
            })
            if (pos <= 0) {
              throw new Error('Unexpected operation!')
            }
          }
          /* (see above for new approach)
          var _e = this._content[pos]
          // when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
          // If the algorithm works correctly, the double should always exist on the correct position (pos - the computed destination)
          if (_e != null && Y.utils.compareIds(_e.id, op.id)) {
            // is already defined
            return
          }*/
          var values
          var length
          if (op.hasOwnProperty('opContent')) {
            this._content.splice(pos, 0, {
              id: op.id,
              type: op.opContent
            })
            length = 1
            let type = this.os.getType(op.opContent)
            type._parent = this._model
            values = [type]
          } else {
            var contents = op.content.map(function (c, i) {
              return {
                id: [op.id[0], op.id[1] + i],
                val: c
              }
            })
            // insert value in _content
            // It is not possible to insert more than ~2^16 elements in an Array (see #5). We handle this case explicitly
            if (contents.length < 30000) {
              this._content.splice.apply(this._content, [pos, 0].concat(contents))
            } else {
              this._content = this._content.slice(0, pos).concat(contents).concat(this._content.slice(pos))
            }
            values = op.content
            length = op.content.length
          }
          Y.utils.bubbleEvent(this, {
            type: 'insert',
            object: this,
            index: pos,
            values: values,
            length: length
          })
        } else if (op.struct === 'Delete') {
          var i = 0 // current position in _content
          for (; i < this._content.length && op.length > 0; i++) {
            var c = this._content[i]
            if (Y.utils.inDeletionRange(op, c.id)) {
              // is in deletion range!
              var delLength
              // check how many character to delete in one flush
              for (delLength = 1;
                    delLength < op.length && i + delLength < this._content.length && Y.utils.inDeletionRange(op, this._content[i + delLength].id);
                    delLength++) {}
              // last operation that will be deleted
              c = this._content[i + delLength - 1]
              // update delete operation
              op.length -= c.id[1] - op.target[1] + 1
              op.target = [c.id[0], c.id[1] + 1]
              // apply deletion & find send event
              let content = this._content.splice(i, delLength)
              let values = content.map((c) => {
                if (c.val != null) {
                  return c.val
                } else {
                  return this.os.getType(c.type)
                }
              })
              Y.utils.bubbleEvent(this, {
                type: 'delete',
                object: this,
                index: i,
                values: values,
                _content: content,
                length: delLength
              })
              // with the fresh delete op, we can continue
              // note: we don't have to increment i, because the i-th content was deleted
              // but on the other had, the (i+delLength)-th was not in deletion range
              // So we don't do i--
            }
          }
        } else {
          throw new Error('Unexpected struct!')
        }
      })
    }
    _getPathToChild (childId) {
      return this._content.findIndex(c =>
        c.type != null && Y.utils.compareIds(c.type, childId)
      )
    }
    _destroy () {
      this.eventHandler.destroy()
      this.eventHandler = null
      this._content = null
      this._model = null
      this._parent = null
      this.os = null
    }
    get length () {
      return this._content.length
    }
    get (pos) {
      if (pos == null || typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (pos >= this._content.length) {
        return undefined
      }
      if (this._content[pos].type == null) {
        return this._content[pos].val
      } else {
        return this.os.getType(this._content[pos].type)
      }
    }
    toArray () {
      return this._content.map((x, i) => {
        if (x.type != null) {
          return this.os.getType(x.type)
        } else {
          return x.val
        }
      })
    }
    push (contents) {
      return this.insert(this._content.length, contents)
    }
    insert (pos, contents) {
      if (typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (!Array.isArray(contents)) {
        throw new Error('contents must be an Array of objects!')
      }
      if (contents.length === 0) {
        return
      }
      if (pos > this._content.length || pos < 0) {
        throw new Error('This position exceeds the range of the array!')
      }
      var mostLeft = pos === 0 ? null : this._content[pos - 1].id

      var ops = []
      var prevId = mostLeft
      for (var i = 0; i < contents.length;) {
        var op = {
          left: prevId,
          origin: prevId,
          // right: mostRight,
          // NOTE: I intentionally do not define right here, because it could be deleted
          // at the time of inserting this operation (when we get the transaction),
          // and would therefore not defined in this._content
          parent: this._model,
          struct: 'Insert'
        }
        var _content = []
        var typeDefinition
        while (i < contents.length) {
          var val = contents[i++]
          typeDefinition = Y.utils.isTypeDefinition(val)
          if (!typeDefinition) {
            _content.push(val)
          } else if (_content.length > 0) {
            i-- // come back again later
            break
          } else {
            break
          }
        }
        if (_content.length > 0) {
          // content is defined
          op.content = _content
          op.id = this.os.getNextOpId(_content.length)
        } else {
          // otherwise its a type
          var typeid = this.os.getNextOpId(1)
          this.os.createType(typeDefinition, typeid)
          op.opContent = typeid
          op.id = this.os.getNextOpId(1)
        }
        ops.push(op)
        prevId = op.id
      }
      var eventHandler = this.eventHandler
      this.os.requestTransaction(function *() {
        // now we can set the right reference.
        var mostRight
        if (mostLeft != null) {
          var ml = yield* this.getInsertionCleanEnd(mostLeft)
          mostRight = ml.right
        } else {
          mostRight = (yield* this.getOperation(ops[0].parent)).start
        }
        for (var j = 0; j < ops.length; j++) {
          var op = ops[j]
          op.right = mostRight
        }
        yield* eventHandler.awaitOps(this, this.applyCreatedOperations, [ops])
      })
      // always remember to do that after this.os.requestTransaction
      // (otherwise values might contain a undefined reference to type)
      eventHandler.awaitAndPrematurelyCall(ops)
    }
    delete (pos, length) {
      if (length == null) { length = 1 }
      if (typeof length !== 'number') {
        throw new Error('length must be a number!')
      }
      if (typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (pos + length > this._content.length || pos < 0 || length < 0) {
        throw new Error('The deletion range exceeds the range of the array!')
      }
      if (length === 0) {
        return
      }
      var eventHandler = this.eventHandler
      var dels = []
      for (var i = 0; i < length; i = i + delLength) {
        var targetId = this._content[pos + i].id
        var delLength
        // how many insertions can we delete in one deletion?
        for (delLength = 1; i + delLength < length; delLength++) {
          if (!Y.utils.compareIds(this._content[pos + i + delLength].id, [targetId[0], targetId[1] + delLength])) {
            break
          }
        }
        dels.push({
          target: targetId,
          struct: 'Delete',
          length: delLength
        })
      }
      this.os.requestTransaction(function *() {
        yield* eventHandler.awaitOps(this, this.applyCreatedOperations, [dels])
      })
      // always remember to do that after this.os.requestTransaction
      // (otherwise values might contain a undefined reference to type)
      eventHandler.awaitAndPrematurelyCall(dels)
    }
    observe (f) {
      this.eventHandler.addEventListener(f)
    }
    observeDeep (f) {
      this._deepEventHandler.addEventListener(f)
    }
    unobserve (f) {
      this.eventHandler.removeEventListener(f)
    }
    unobserveDeep (f) {
      this._deepEventHandler.addEventListener(f)
    }
    * _changed (transaction, op) {
      if (!op.deleted) {
        if (op.struct === 'Insert') {
          // update left
          var l = op.left
          var left
          while (l != null) {
            left = yield* transaction.getInsertion(l)
            if (!left.deleted) {
              break
            }
            l = left.left
          }
          op.left = l
          // if op contains opContent, initialize it
          if (op.opContent != null) {
            yield* transaction.store.initType.call(transaction, op.opContent)
          }
        }
        this.eventHandler.receivedOp(op)
      }
    }
  }

  Y.extend('Array', new Y.utils.CustomTypeDefinition({
    name: 'Array',
    class: YArray,
    struct: 'List',
    initType: function * YArrayInitializer (os, model) {
      var _content = []
      var _types = []
      yield* Y.Struct.List.map.call(this, model, function (op) {
        if (op.hasOwnProperty('opContent')) {
          _content.push({
            id: op.id,
            type: op.opContent
          })
          _types.push(op.opContent)
        } else {
          op.content.forEach(function (c, i) {
            _content.push({
              id: [op.id[0], op.id[1] + i],
              val: op.content[i]
            })
          })
        }
      })
      for (var i = 0; i < _types.length; i++) {
        var type = yield* this.store.initType.call(this, _types[i])
        type._parent = model.id
      }
      return new YArray(os, model.id, _content)
    },
    createType: function YArrayCreateType (os, model) {
      return new YArray(os, model.id, [])
    }
  }))
}

module.exports = extend
if (typeof Y !== 'undefined') {
  extend(Y)
}
<commit_msg>correctly implement unobserveDeep<commit_after>/* global Y */
'use strict'

function extend (Y) {
  class YArray extends Y.utils.CustomType {
    constructor (os, _model, _content) {
      super()
      this.os = os
      this._model = _model
      // Array of all the neccessary content
      this._content = _content

      // the parent of this type
      this._parent = null
      this._deepEventHandler = new Y.utils.EventListenerHandler()

      // this._debugEvents = [] // TODO: remove!!
      this.eventHandler = new Y.utils.EventHandler((op) => {
        // this._debugEvents.push(JSON.parse(JSON.stringify(op)))
        if (op.struct === 'Insert') {
          // when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
          if (this._content.some(function (c) { return Y.utils.compareIds(c.id, op.id) })) {
            // op exists
            return
          }
          let pos
          // we check op.left only!,
          // because op.right might not be defined when this is called
          if (op.left === null) {
            pos = 0
          } else {
            pos = 1 + this._content.findIndex(function (c) {
              return Y.utils.compareIds(c.id, op.left)
            })
            if (pos <= 0) {
              throw new Error('Unexpected operation!')
            }
          }
          /* (see above for new approach)
          var _e = this._content[pos]
          // when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
          // If the algorithm works correctly, the double should always exist on the correct position (pos - the computed destination)
          if (_e != null && Y.utils.compareIds(_e.id, op.id)) {
            // is already defined
            return
          }*/
          var values
          var length
          if (op.hasOwnProperty('opContent')) {
            this._content.splice(pos, 0, {
              id: op.id,
              type: op.opContent
            })
            length = 1
            let type = this.os.getType(op.opContent)
            type._parent = this._model
            values = [type]
          } else {
            var contents = op.content.map(function (c, i) {
              return {
                id: [op.id[0], op.id[1] + i],
                val: c
              }
            })
            // insert value in _content
            // It is not possible to insert more than ~2^16 elements in an Array (see #5). We handle this case explicitly
            if (contents.length < 30000) {
              this._content.splice.apply(this._content, [pos, 0].concat(contents))
            } else {
              this._content = this._content.slice(0, pos).concat(contents).concat(this._content.slice(pos))
            }
            values = op.content
            length = op.content.length
          }
          Y.utils.bubbleEvent(this, {
            type: 'insert',
            object: this,
            index: pos,
            values: values,
            length: length
          })
        } else if (op.struct === 'Delete') {
          var i = 0 // current position in _content
          for (; i < this._content.length && op.length > 0; i++) {
            var c = this._content[i]
            if (Y.utils.inDeletionRange(op, c.id)) {
              // is in deletion range!
              var delLength
              // check how many character to delete in one flush
              for (delLength = 1;
                    delLength < op.length && i + delLength < this._content.length && Y.utils.inDeletionRange(op, this._content[i + delLength].id);
                    delLength++) {}
              // last operation that will be deleted
              c = this._content[i + delLength - 1]
              // update delete operation
              op.length -= c.id[1] - op.target[1] + 1
              op.target = [c.id[0], c.id[1] + 1]
              // apply deletion & find send event
              let content = this._content.splice(i, delLength)
              let values = content.map((c) => {
                if (c.val != null) {
                  return c.val
                } else {
                  return this.os.getType(c.type)
                }
              })
              Y.utils.bubbleEvent(this, {
                type: 'delete',
                object: this,
                index: i,
                values: values,
                _content: content,
                length: delLength
              })
              // with the fresh delete op, we can continue
              // note: we don't have to increment i, because the i-th content was deleted
              // but on the other had, the (i+delLength)-th was not in deletion range
              // So we don't do i--
            }
          }
        } else {
          throw new Error('Unexpected struct!')
        }
      })
    }
    _getPathToChild (childId) {
      return this._content.findIndex(c =>
        c.type != null && Y.utils.compareIds(c.type, childId)
      )
    }
    _destroy () {
      this.eventHandler.destroy()
      this.eventHandler = null
      this._content = null
      this._model = null
      this._parent = null
      this.os = null
    }
    get length () {
      return this._content.length
    }
    get (pos) {
      if (pos == null || typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (pos >= this._content.length) {
        return undefined
      }
      if (this._content[pos].type == null) {
        return this._content[pos].val
      } else {
        return this.os.getType(this._content[pos].type)
      }
    }
    toArray () {
      return this._content.map((x, i) => {
        if (x.type != null) {
          return this.os.getType(x.type)
        } else {
          return x.val
        }
      })
    }
    push (contents) {
      return this.insert(this._content.length, contents)
    }
    insert (pos, contents) {
      if (typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (!Array.isArray(contents)) {
        throw new Error('contents must be an Array of objects!')
      }
      if (contents.length === 0) {
        return
      }
      if (pos > this._content.length || pos < 0) {
        throw new Error('This position exceeds the range of the array!')
      }
      var mostLeft = pos === 0 ? null : this._content[pos - 1].id

      var ops = []
      var prevId = mostLeft
      for (var i = 0; i < contents.length;) {
        var op = {
          left: prevId,
          origin: prevId,
          // right: mostRight,
          // NOTE: I intentionally do not define right here, because it could be deleted
          // at the time of inserting this operation (when we get the transaction),
          // and would therefore not defined in this._content
          parent: this._model,
          struct: 'Insert'
        }
        var _content = []
        var typeDefinition
        while (i < contents.length) {
          var val = contents[i++]
          typeDefinition = Y.utils.isTypeDefinition(val)
          if (!typeDefinition) {
            _content.push(val)
          } else if (_content.length > 0) {
            i-- // come back again later
            break
          } else {
            break
          }
        }
        if (_content.length > 0) {
          // content is defined
          op.content = _content
          op.id = this.os.getNextOpId(_content.length)
        } else {
          // otherwise its a type
          var typeid = this.os.getNextOpId(1)
          this.os.createType(typeDefinition, typeid)
          op.opContent = typeid
          op.id = this.os.getNextOpId(1)
        }
        ops.push(op)
        prevId = op.id
      }
      var eventHandler = this.eventHandler
      this.os.requestTransaction(function *() {
        // now we can set the right reference.
        var mostRight
        if (mostLeft != null) {
          var ml = yield* this.getInsertionCleanEnd(mostLeft)
          mostRight = ml.right
        } else {
          mostRight = (yield* this.getOperation(ops[0].parent)).start
        }
        for (var j = 0; j < ops.length; j++) {
          var op = ops[j]
          op.right = mostRight
        }
        yield* eventHandler.awaitOps(this, this.applyCreatedOperations, [ops])
      })
      // always remember to do that after this.os.requestTransaction
      // (otherwise values might contain a undefined reference to type)
      eventHandler.awaitAndPrematurelyCall(ops)
    }
    delete (pos, length) {
      if (length == null) { length = 1 }
      if (typeof length !== 'number') {
        throw new Error('length must be a number!')
      }
      if (typeof pos !== 'number') {
        throw new Error('pos must be a number!')
      }
      if (pos + length > this._content.length || pos < 0 || length < 0) {
        throw new Error('The deletion range exceeds the range of the array!')
      }
      if (length === 0) {
        return
      }
      var eventHandler = this.eventHandler
      var dels = []
      for (var i = 0; i < length; i = i + delLength) {
        var targetId = this._content[pos + i].id
        var delLength
        // how many insertions can we delete in one deletion?
        for (delLength = 1; i + delLength < length; delLength++) {
          if (!Y.utils.compareIds(this._content[pos + i + delLength].id, [targetId[0], targetId[1] + delLength])) {
            break
          }
        }
        dels.push({
          target: targetId,
          struct: 'Delete',
          length: delLength
        })
      }
      this.os.requestTransaction(function *() {
        yield* eventHandler.awaitOps(this, this.applyCreatedOperations, [dels])
      })
      // always remember to do that after this.os.requestTransaction
      // (otherwise values might contain a undefined reference to type)
      eventHandler.awaitAndPrematurelyCall(dels)
    }
    observe (f) {
      this.eventHandler.addEventListener(f)
    }
    observeDeep (f) {
      this._deepEventHandler.addEventListener(f)
    }
    unobserve (f) {
      this.eventHandler.removeEventListener(f)
    }
    unobserveDeep (f) {
      this._deepEventHandler.removeEventListener(f)
    }
    * _changed (transaction, op) {
      if (!op.deleted) {
        if (op.struct === 'Insert') {
          // update left
          var l = op.left
          var left
          while (l != null) {
            left = yield* transaction.getInsertion(l)
            if (!left.deleted) {
              break
            }
            l = left.left
          }
          op.left = l
          // if op contains opContent, initialize it
          if (op.opContent != null) {
            yield* transaction.store.initType.call(transaction, op.opContent)
          }
        }
        this.eventHandler.receivedOp(op)
      }
    }
  }

  Y.extend('Array', new Y.utils.CustomTypeDefinition({
    name: 'Array',
    class: YArray,
    struct: 'List',
    initType: function * YArrayInitializer (os, model) {
      var _content = []
      var _types = []
      yield* Y.Struct.List.map.call(this, model, function (op) {
        if (op.hasOwnProperty('opContent')) {
          _content.push({
            id: op.id,
            type: op.opContent
          })
          _types.push(op.opContent)
        } else {
          op.content.forEach(function (c, i) {
            _content.push({
              id: [op.id[0], op.id[1] + i],
              val: op.content[i]
            })
          })
        }
      })
      for (var i = 0; i < _types.length; i++) {
        var type = yield* this.store.initType.call(this, _types[i])
        type._parent = model.id
      }
      return new YArray(os, model.id, _content)
    },
    createType: function YArrayCreateType (os, model) {
      return new YArray(os, model.id, [])
    }
  }))
}

module.exports = extend
if (typeof Y !== 'undefined') {
  extend(Y)
}
<|endoftext|>