<commit_before>/* eslint-env browser */

/**
 * Note: window.gapiReady must be a promise that resolves to
 * window.gapi.
 *
 * @template T
 * @param {string} name the library to load
 * @return {Promise<T>} resolves to window.gapi[name]
 */
function gapiLoad(name) {
  return new Promise((resolve, reject) => {
    if ('gapiReady' in window) {
      window.gapiReady.then(gapi => {
        gapi.load(name, () => resolve(gapi[name]));
      });
    } else {
      reject('Promise window.gapiReady not found');
    }
  });
}

/**
 * Promise'd version of [`gapi.client.load`](https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientloadname--------version--------callback).
 *
 * @template T
 * @param {string} name the API client to load
 * @param {string} [version="v1"] version
 * @return {Promise<T>} resolves to gapi.client[name]
 */
function clientLoad(name, version) { // eslint-disable-line no-unused-vars
  version = version ? version : 'v1';
  return gapiLoad('client').then(client => {
    return new Promise(resolve => {
      client.load(name, version, () => resolve(client[name]));
    });
  });
}

/**
 * Promise'd version of [`gapi.auth2.init`](https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams).
 *
 * @param {any} params https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams
 * @return {Promise<gapi.auth2.GoogleAuth>} Promise resolving to an initialized gapi.auth2.GoogleAuth object
 */
function authInit(params) {
  return gapiLoad('auth2').then(auth2 => {
    /* Ideally we'd just return `auth2.init(params)` here, but
     * instead we need to work around a few bugs and surprises in
     * `auth2.init()` and the "Promise" it returns.
     */
    return new Promise(resolve => {
      auth2.init(params).then(t => {
        t.then = null;
        resolve(t);
      });
    });
  });
}

/* Returns a `Promise<ServiceWorkerRegistration>` like
 * [ServiceWorkerContainer.register()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register),
 * except that when it resolves, `script`'s service worker is active and
 * controlling the page.
 *
 * (When the promise returned by `ServiceWorkerContainer.register()`
 * resolves, the page might be controlled by a previously-installed service
 * worker, or no service worker.)
 *
 * There's [a proposal](https://github.com/slightlyoff/ServiceWorker/issues/770)
 * to make something similar part of the service worker spec.
 *
 * @param {string} script URL of service worker
 * @param {object} options passed to register()
 * @return {Promise<ServiceWorkerRegistration>}
 */
function registerReady(script, options) {
  if (!('serviceWorker' in navigator)) {
    return new Promise();
  }

  return navigator.serviceWorker.register(script, options).then(r => {
    var incoming = r.installing || r.waiting;
    if (r.active && !incoming) {
      return r;
    }

    return new Promise(resolve => {
      incoming.onstatechange = e => {
        if (e.target.state === 'activated') {
          incoming.onstatechange = null;
          resolve(r);
        }
      };
    });
  });
}

(() => {
  // LOGIN/LOGOUT HANDLER

  const [login, logout] = [document.getElementById('login'), document.getElementById('logout')];

  /**
   * @param {GoogleUser} user
   */
  function onChange(user) {
    if (user.isSignedIn()) {
      console.log('id_token', user.getAuthResponse().id_token);
      login.disabled = true;
      logout.disabled = false;
      const pwaForm = document.getElementById('pwaForm');
      if (pwaForm) {
        const idTokenInput = document.getElementById('idToken');
        idTokenInput.setAttribute('value', user.getAuthResponse().id_token);

        const pwaSubmit = document.getElementById('pwaSubmit');
        pwaSubmit.removeAttribute('disabled');
      }
    } else {
      console.log('user signed out/never signed in');
      login.disabled = false;
      logout.disabled = true;
      const pwaForm = document.getElementById('pwaForm');
      if (pwaForm) {
        const idTokenInput = document.getElementById('idToken');
        idTokenInput.setAttribute('value', '');

        const pwaSubmit = document.getElementById('pwaSubmit');
        pwaSubmit.setAttribute('disabled', '');
      }
    }
  }

  /* eslint-disable camelcase */
  const params = {
    scope: 'profile',
    client_id: '605287872172-js6omne47i1k79hnfo7d4bdu9rlemslr.apps.googleusercontent.com',
    fetch_basic_profile: false
  };
  /* eslint-enable camelcase */

  authInit(params).then(auth => {
    auth.currentUser.listen(onChange);
    onChange(auth.currentUser.get()); // User may be signed in already

    login.addEventListener('click', () => auth.signIn());
    logout.addEventListener('click', () => auth.signOut());
  });

  // REGISTER SERVICE WORKER

  navigator.serviceWorker.register('/sw.js').then(r => {
    console.log('REGISTRATION', r);
  });
})();
<commit_msg>Improve comments, remove registerReady()<commit_after>/* eslint-env browser */

/**
 * Note: window.gapiReady must be a promise that resolves to
 * window.gapi.
 *
 * @template T
 * @param {string} name the library to load
 * @return {Promise<T>} resolves to window.gapi[name]
 */
function gapiLoad(name) {
  return new Promise((resolve, reject) => {
    if ('gapiReady' in window) {
      window.gapiReady.then(gapi => {
        gapi.load(name, () => resolve(gapi[name]));
      });
    } else {
      reject('Promise window.gapiReady not found');
    }
  });
}

/**
 * Promise'd version of [`gapi.client.load`](https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientloadname--------version--------callback).
 *
 * @template T
 * @param {string} name the API client to load
 * @param {string} [version="v1"] version
 * @return {Promise<T>} resolves to gapi.client[name]
 */
function clientLoad(name, version) { // eslint-disable-line no-unused-vars
  version = version ? version : 'v1';
  return gapiLoad('client').then(client => {
    return new Promise(resolve => {
      client.load(name, version, () => resolve(client[name]));
    });
  });
}

/**
 * Promise'd version of [`gapi.auth2.init`](https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams).
 *
 * @param {any} params https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams
 * @return {Promise<gapi.auth2.GoogleAuth>} Promise resolving to an initialized gapi.auth2.GoogleAuth object
 */
function authInit(params) {
  return gapiLoad('auth2').then(auth2 => {
    /* Ideally we'd just return `auth2.init(params)` here, but
     * instead we need to work around a few bugs and surprises in
     * `auth2.init()` and the "Promise" it returns.
     */
    return new Promise(resolve => {
      auth2.init(params).then(t => {
        t.then = null;
        resolve(t);
      });
    });
  });
}

(() => {
  // LOGIN/LOGOUT HANDLER

  const [login, logout] = [document.getElementById('login'), document.getElementById('logout')];

  /**
   * @param {GoogleUser} user
   */
  function onChange(user) {
    if (user.isSignedIn()) {
      console.log('id_token', user.getAuthResponse().id_token);
      login.disabled = true;
      logout.disabled = false;
      const pwaForm = document.getElementById('pwaForm');
      if (pwaForm) {
        const idTokenInput = document.getElementById('idToken');
        idTokenInput.setAttribute('value', user.getAuthResponse().id_token);

        const pwaSubmit = document.getElementById('pwaSubmit');
        pwaSubmit.removeAttribute('disabled');
      }
    } else {
      console.log('user signed out/never signed in');
      login.disabled = false;
      logout.disabled = true;
      const pwaForm = document.getElementById('pwaForm');
      if (pwaForm) {
        const idTokenInput = document.getElementById('idToken');
        idTokenInput.setAttribute('value', '');

        const pwaSubmit = document.getElementById('pwaSubmit');
        pwaSubmit.setAttribute('disabled', '');
      }
    }
  }

  /* eslint-disable camelcase */
  const params = {
    scope: 'profile',
    client_id: '605287872172-js6omne47i1k79hnfo7d4bdu9rlemslr.apps.googleusercontent.com',
    fetch_basic_profile: false
  };
  /* eslint-enable camelcase */

  authInit(params).then(auth => {
    auth.currentUser.listen(onChange);
    onChange(auth.currentUser.get()); // User may be signed in already

    login.addEventListener('click', () => auth.signIn());
    logout.addEventListener('click', () => auth.signOut());
  });

  // REGISTER SERVICE WORKER

  navigator.serviceWorker.register('/sw.js').then(r => {
    console.log('REGISTRATION', r);
  });
})();
<|endoftext|>


<commit_before>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import classnames from 'classnames';
import { FormattedDate } from 'react-intl';
import Intl from '../utils/Intl';
import Box from './Box';
import Value from './Value';
import Animate from './Animate';
import Meter from './Meter';
import Button from './Button';
import StatusIcon from './icons/Status';
import CloseIcon from './icons/base/Close';
import Props from '../utils/Props';
import CSSClassnames from '../utils/CSSClassnames';
import Announcer from '../utils/Announcer';
import { checkDarkBackground } from '../utils/DOM';

const CLASS_ROOT = CSSClassnames.NOTIFICATION;
const BACKGROUND_COLOR_INDEX = CSSClassnames.BACKGROUND_COLOR_INDEX;

export default class Notification extends Component {

  constructor () {
    super();
    this._announce = this._announce.bind(this);
    this.state = {};
  }

  componentDidMount () {
    this._announce();
    // Measure the actual background color brightness to determine whether
    // to set a dark or light context.
    this._setDarkBackground();
  }

  componentWillReceiveProps (nextProps) {
    if (nextProps.status !== this.props.status) {
      this.setState({ updateDarkBackground: true });
    }
  }

  componentDidUpdate () {
    this._announce();
    if (this.state.updateDarkBackground) {
      this.setState({ updateDarkBackground: false });
      this._setDarkBackground();
    }
  }

  _setDarkBackground () {
    const { colorIndex } = this.props;
    const box = findDOMNode(this.boxContainerRef);
    checkDarkBackground(colorIndex, box,
      (darkBackground) => this.setState({ darkBackground }));
  }

  _announce () {
    const { announce, message } = this.props;
    const { intl } = this.context;
    if (announce) {
      const notificationMessage = Intl.getMessage(intl, 'Notification');
      Announcer.announce(`${notificationMessage}: ${message}`);
    }
  }

  render () {
    const {
      children, className, closer, context, percentComplete, message,
      onClose, timestamp, size, state, status
    } = this.props;
    const { intl } = this.context;
    const { darkBackground } = this.state;
    const classes = classnames(
      CLASS_ROOT,
      `${CLASS_ROOT}--status-${status.toLowerCase()}`,
      `${BACKGROUND_COLOR_INDEX}-${status.toLowerCase()}`,
      {
        [`${BACKGROUND_COLOR_INDEX}--dark`]: darkBackground,
        [`${BACKGROUND_COLOR_INDEX}--light`]: !darkBackground,
        [`${CLASS_ROOT}--${size}`]: size
      },
      className
    );

    let statusNode;
    if (status) {
      statusNode = (
        <StatusIcon className={`${CLASS_ROOT}__status`}
          value={status} size={size} />
      );
    }

    let stateNode;
    if (state) {
      stateNode = (
        <div className={`${CLASS_ROOT}__state`}>{state}

      );
    }

    let progress;
    if (percentComplete || 0 === percentComplete) {
      progress = (
        <Box direction='row' align='center' pad={{ between: 'medium' }}>
          <Meter
            series={[{
              value: percentComplete,
              colorIndex: 'light-1'
            }]}/>
          <Value value={percentComplete} units='%' size='small'/>
        </Box>
      );
    }

    let timestampNode;
    if (timestamp) {
      let timestampFormatted = timestamp.toString();
      if (intl) {
        timestampFormatted = (
          <FormattedDate value={timestamp} weekday='long' day='numeric'
            month='long' year='numeric' hour='numeric' minute='numeric'
            second='numeric' />
        );
      }

      timestampNode = (
        <div className={`${CLASS_ROOT}__timestamp`}>
          {timestampFormatted}

      );
    }

    let closerNode;
    if (typeof closer === 'object') {
      closerNode = closer;
    } else if (onClose && closer) {
      closerNode = (
        <Button plain={true} onClick={onClose}
          icon={<CloseIcon className={`${CLASS_ROOT}__close`} />}
          a11yTitle={
            Intl.getMessage(intl, 'Close Notification')
          } />
      );
    }

    const boxProps = Props.pick(this.props, Object.keys(Box.propTypes));
    const restProps =
      Props.omit(this.props, Object.keys(Notification.propTypes));
    boxProps.announce = false;
    const fullBox =
      boxProps.hasOwnProperty('full') ? boxProps.full : 'horizontal';

    if (size && typeof size === 'string') {
      // don't transfer size to Box since it means something different
      delete boxProps.size;
    }
    return (
      <Animate enter={{ animation: 'fade', duration: 1000 }}
        leave={{ animation: 'fade', duration: 1000 }}>
        <Box ref={(ref) => this._containerRef = ref}
          {...restProps} {...boxProps} className={classes}
          pad='small' direction='row' align='start' responsive={false}
          full={fullBox}>
          <Box pad='small'>
            {statusNode}
          </Box>
          <Box flex={true} pad='small'>
            <span className={`${CLASS_ROOT}__message`}>
              {message}

            {context}
            {timestampNode}
            {stateNode}
            {progress}
            {children}
          </Box>
          {closerNode}
        </Box>
      </Animate>
    );
  }
};

Notification.propTypes = {
  closer: PropTypes.oneOfType([
    PropTypes.node,
    PropTypes.bool
  ]),
  context: PropTypes.node,
  message: PropTypes.string.isRequired,
  onClose: PropTypes.func,
  percentComplete: PropTypes.number,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  state: PropTypes.string,
  status: PropTypes.string,
  timestamp: PropTypes.object, // Date
  ...Box.propTypes
};

Notification.contextTypes = {
  intl: PropTypes.object
};

Notification.defaultProps = {
  closer: false,
  status: 'unknown',
  pad: 'medium'
};
<commit_msg>Changed Notification to not expect to take the full viewport width.<commit_after>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import classnames from 'classnames';
import { FormattedDate } from 'react-intl';
import Intl from '../utils/Intl';
import Box from './Box';
import Value from './Value';
import Animate from './Animate';
import Meter from './Meter';
import Button from './Button';
import StatusIcon from './icons/Status';
import CloseIcon from './icons/base/Close';
import Props from '../utils/Props';
import CSSClassnames from '../utils/CSSClassnames';
import Announcer from '../utils/Announcer';
import { checkDarkBackground } from '../utils/DOM';

const CLASS_ROOT = CSSClassnames.NOTIFICATION;
const BACKGROUND_COLOR_INDEX = CSSClassnames.BACKGROUND_COLOR_INDEX;

export default class Notification extends Component {

  constructor () {
    super();
    this._announce = this._announce.bind(this);
    this.state = {};
  }

  componentDidMount () {
    this._announce();
    // Measure the actual background color brightness to determine whether
    // to set a dark or light context.
    this._setDarkBackground();
  }

  componentWillReceiveProps (nextProps) {
    if (nextProps.status !== this.props.status) {
      this.setState({ updateDarkBackground: true });
    }
  }

  componentDidUpdate () {
    this._announce();
    if (this.state.updateDarkBackground) {
      this.setState({ updateDarkBackground: false });
      this._setDarkBackground();
    }
  }

  _setDarkBackground () {
    const { colorIndex } = this.props;
    const box = findDOMNode(this.boxContainerRef);
    checkDarkBackground(colorIndex, box,
      (darkBackground) => this.setState({ darkBackground }));
  }

  _announce () {
    const { announce, message } = this.props;
    const { intl } = this.context;
    if (announce) {
      const notificationMessage = Intl.getMessage(intl, 'Notification');
      Announcer.announce(`${notificationMessage}: ${message}`);
    }
  }

  render () {
    const {
      children, className, closer, context, percentComplete, message,
      onClose, timestamp, size, state, status
    } = this.props;
    const { intl } = this.context;
    const { darkBackground } = this.state;
    const classes = classnames(
      CLASS_ROOT,
      `${CLASS_ROOT}--status-${status.toLowerCase()}`,
      `${BACKGROUND_COLOR_INDEX}-${status.toLowerCase()}`,
      {
        [`${BACKGROUND_COLOR_INDEX}--dark`]: darkBackground,
        [`${BACKGROUND_COLOR_INDEX}--light`]: !darkBackground,
        [`${CLASS_ROOT}--${size}`]: size
      },
      className
    );

    let statusNode;
    if (status) {
      statusNode = (
        <StatusIcon className={`${CLASS_ROOT}__status`}
          value={status} size={size} />
      );
    }

    let stateNode;
    if (state) {
      stateNode = (
        <div className={`${CLASS_ROOT}__state`}>{state}

      );
    }

    let progress;
    if (percentComplete || 0 === percentComplete) {
      progress = (
        <Box direction='row' align='center' pad={{ between: 'medium' }}>
          <Meter
            series={[{
              value: percentComplete,
              colorIndex: 'light-1'
            }]}/>
          <Value value={percentComplete} units='%' size='small'/>
        </Box>
      );
    }

    let timestampNode;
    if (timestamp) {
      let timestampFormatted = timestamp.toString();
      if (intl) {
        timestampFormatted = (
          <FormattedDate value={timestamp} weekday='long' day='numeric'
            month='long' year='numeric' hour='numeric' minute='numeric'
            second='numeric' />
        );
      }

      timestampNode = (
        <div className={`${CLASS_ROOT}__timestamp`}>
          {timestampFormatted}

      );
    }

    let closerNode;
    if (typeof closer === 'object') {
      closerNode = closer;
    } else if (onClose && closer) {
      closerNode = (
        <Button plain={true} onClick={onClose}
          icon={<CloseIcon className={`${CLASS_ROOT}__close`} />}
          a11yTitle={
            Intl.getMessage(intl, 'Close Notification')
          } />
      );
    }

    const boxProps = Props.pick(this.props, Object.keys(Box.propTypes));
    const restProps =
      Props.omit(this.props, Object.keys(Notification.propTypes));
    boxProps.announce = false;
    const fullBox =
      boxProps.hasOwnProperty('full') ? boxProps.full : undefined;

    if (size && typeof size === 'string') {
      // don't transfer size to Box since it means something different
      delete boxProps.size;
    }
    return (
      <Animate enter={{ animation: 'fade', duration: 1000 }}
        leave={{ animation: 'fade', duration: 1000 }}>
        <Box ref={(ref) => this._containerRef = ref}
          {...restProps} {...boxProps} className={classes}
          pad='small' direction='row' align='start' responsive={false}
          full={fullBox}>
          <Box pad='small'>
            {statusNode}
          </Box>
          <Box flex={true} pad='small'>
            <span className={`${CLASS_ROOT}__message`}>
              {message}

            {context}
            {timestampNode}
            {stateNode}
            {progress}
            {children}
          </Box>
          {closerNode}
        </Box>
      </Animate>
    );
  }
};

Notification.propTypes = {
  closer: PropTypes.oneOfType([
    PropTypes.node,
    PropTypes.bool
  ]),
  context: PropTypes.node,
  message: PropTypes.string.isRequired,
  onClose: PropTypes.func,
  percentComplete: PropTypes.number,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  state: PropTypes.string,
  status: PropTypes.string,
  timestamp: PropTypes.object, // Date
  ...Box.propTypes
};

Notification.contextTypes = {
  intl: PropTypes.object
};

Notification.defaultProps = {
  closer: false,
  status: 'unknown',
  pad: 'medium'
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies
 */

// Public node modules.
const _ = require('lodash');

// Utils
const {
  models: { getValuePrimaryKey },
} = require('strapi-utils');

const transformToArrayID = (array, association) => {
  if (_.isArray(array)) {
    array = array.map(value => {
      if (_.isPlainObject(value)) {
        return value._id || value.id || false;
      }

      return value;
    });

    return array.filter(n => n);
  }

  if (
    association.type === 'model' ||
    (association.type === 'collection' && _.isObject(array))
  ) {
    return _.isEmpty(_.toString(array)) ? [] : transformToArrayID([array]);
  }

  return [];
};

const getModel = (model, plugin) => {
  return (
    _.get(strapi.plugins, [plugin, 'models', model]) ||
    _.get(strapi, ['models', model]) ||
    undefined
  );
};

const removeUndefinedKeys = obj => _.pickBy(obj, _.negate(_.isUndefined));

module.exports = {
  async findOne(params, populate, { transacting } = {}) {
    const record = await this.forge({
      [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
    }).fetch({
      transacting,
      withRelated: populate,
    });

    const data = record ? record.toJSON() : record;

    // Retrieve data manually.
    if (_.isEmpty(populate)) {
      const arrayOfPromises = this.associations
        .filter(association =>
          ['manyMorphToOne', 'manyMorphToMany'].includes(association.nature)
        )
        .map(() => {
          return this.morph
            .forge()
            .where({
              [`${this.collectionName}_id`]: getValuePrimaryKey(
                params,
                this.primaryKey
              ),
            })
            .fetchAll({
              transacting,
            });
        });

      const related = await Promise.all(arrayOfPromises);

      related.forEach((value, index) => {
        data[this.associations[index].alias] = value ? value.toJSON() : value;
      });
    }

    return data;
  },

  async update(params, { transacting } = {}) {
    const relationUpdates = [];
    const primaryKeyValue = getValuePrimaryKey(params, this.primaryKey);
    const response = await module.exports.findOne.call(this, params, null, {
      transacting,
    });

    // Only update fields which are on this document.
    const values =
      params.parseRelationships === false
        ? params.values
        : Object.keys(removeUndefinedKeys(params.values)).reduce(
            (acc, current) => {
              const property = params.values[current];
              const association = this.associations.filter(
                x => x.alias === current
              )[0];
              const details = this._attributes[current];

              if (!association && _.get(details, 'isVirtual') !== true) {
                return _.set(acc, current, property);
              }

              const assocModel = getModel(
                details.model || details.collection,
                details.plugin
              );
              switch (association.nature) {
                case 'oneWay': {
                  return _.set(
                    acc,
                    current,
                    _.get(property, assocModel.primaryKey, property)
                  );
                }
                case 'oneToOne': {
                  if (response[current] === property) return acc;

                  if (_.isNull(property)) {
                    const updatePromise = assocModel
                      .where({
                        [assocModel.primaryKey]: getValuePrimaryKey(
                          response[current],
                          assocModel.primaryKey
                        ),
                      })
                      .save(
                        { [details.via]: null },
                        {
                          method: 'update',
                          patch: true,
                          require: false,
                          transacting,
                        }
                      );

                    relationUpdates.push(updatePromise);
                    return _.set(acc, current, null);
                  }

                  // set old relations to null
                  const updateLink = this.where({ [current]: property })
                    .save(
                      { [current]: null },
                      {
                        method: 'update',
                        patch: true,
                        require: false,
                        transacting,
                      }
                    )
                    .then(() => {
                      return assocModel
                        .where({ [this.primaryKey]: property })
                        .save(
                          { [details.via]: primaryKeyValue },
                          {
                            method: 'update',
                            patch: true,
                            require: false,
                            transacting,
                          }
                        );
                    });

                  // set new relation
                  relationUpdates.push(updateLink);
                  return _.set(acc, current, property);
                }
                case 'oneToMany': {
                  // receive array of ids or array of objects with ids

                  // set relation to null for all the ids not in the list
                  const currentIds = response[current];
                  const toRemove = _.differenceWith(
                    currentIds,
                    property,
                    (a, b) => {
                      return (
                        `${a[assocModel.primaryKey] || a}` ===
                        `${b[assocModel.primaryKey] || b}`
                      );
                    }
                  );

                  const updatePromise = assocModel
                    .where(
                      assocModel.primaryKey,
                      'in',
                      toRemove.map(val => val[assocModel.primaryKey] || val)
                    )
                    .save(
                      { [details.via]: null },
                      {
                        method: 'update',
                        patch: true,
                        require: false,
                        transacting,
                      }
                    )
                    .then(() => {
                      return assocModel
                        .where(
                          assocModel.primaryKey,
                          'in',
                          property.map(val => val[assocModel.primaryKey] || val)
                        )
                        .save(
                          { [details.via]: primaryKeyValue },
                          {
                            method: 'update',
                            patch: true,
                            require: false,
                            transacting,
                          }
                        );
                    });

                  relationUpdates.push(updatePromise);
                  return acc;
                }
                case 'manyToOne': {
                  return _.set(
                    acc,
                    current,
                    _.get(property, assocModel.primaryKey, property)
                  );
                }
                case 'manyWay':
                case 'manyToMany': {
                  const currentValue = transformToArrayID(
                    response[current],
                    association
                  ).map(id => id.toString());
                  const storedValue = transformToArrayID(
                    params.values[current],
                    association
                  ).map(id => id.toString());

                  const toAdd = _.difference(storedValue, currentValue);
                  const toRemove = _.difference(currentValue, storedValue);

                  const collection = this.forge({
                    [this.primaryKey]: primaryKeyValue,
                  })[association.alias]();

                  const updatePromise = collection
                    .detach(toRemove, { transacting })
                    .then(() => collection.attach(toAdd, { transacting }));

                  relationUpdates.push(updatePromise);
                  return acc;
                }
                case 'manyMorphToMany':
                case 'manyMorphToOne':
                  // Update the relational array.
                  params.values[current].forEach(obj => {
                    const model = strapi.getModel(
                      obj.ref,
                      obj.source && obj.source !== 'content-manager'
                        ? obj.source
                        : null
                    );

                    // Remove existing relationship because only one file
                    // can be related to this field.
                    if (association.nature === 'manyMorphToOne') {
                      relationUpdates.push(
                        module.exports.removeRelationMorph
                          .call(
                            this,
                            {
                              alias: association.alias,
                              ref: model.collectionName,
                              refId: obj.refId,
                              field: obj.field,
                            },
                            { transacting }
                          )
                          .then(() =>
                            module.exports.addRelationMorph.call(
                              this,
                              {
                                id: response[this.primaryKey],
                                alias: association.alias,
                                ref: model.collectionName,
                                refId: obj.refId,
                                field: obj.field,
                              },
                              { transacting }
                            )
                          )
                      );
                    } else {
                      relationUpdates.push(
                        module.exports.addRelationMorph.call(
                          this,
                          {
                            id: response[this.primaryKey],
                            alias: association.alias,
                            ref: model.collectionName,
                            refId: obj.refId,
                            field: obj.field,
                          },
                          { transacting }
                        )
                      );
                    }
                  });
                  break;
                case 'oneToManyMorph':
                case 'manyToManyMorph': {
                  // Compare array of ID to find deleted files.
                  const currentValue = transformToArrayID(
                    response[current],
                    association
                  ).map(id => id.toString());
                  const storedValue = transformToArrayID(
                    params.values[current],
                    association
                  ).map(id => id.toString());

                  const toAdd = _.difference(storedValue, currentValue);
                  const toRemove = _.difference(currentValue, storedValue);

                  const model = getModel(
                    details.collection || details.model,
                    details.plugin
                  );

                  toAdd.forEach(id => {
                    relationUpdates.push(
                      module.exports.addRelationMorph.call(
                        model,
                        {
                          id,
                          alias: association.via,
                          ref: this.collectionName,
                          refId: response.id,
                          field: association.alias,
                        },
                        { transacting }
                      )
                    );
                  });

                  // Update the relational array.
                  toRemove.forEach(id => {
                    relationUpdates.push(
                      module.exports.removeRelationMorph.call(
                        model,
                        {
                          id,
                          alias: association.via,
                          ref: this.collectionName,
                          refId: response.id,
                          field: association.alias,
                        },
                        { transacting }
                      )
                    );
                  });
                  break;
                }
                case 'oneMorphToOne':
                case 'oneMorphToMany': {
                  break;
                }
                default:
              }

              return acc;
            },
            {}
          );

    await Promise.all(relationUpdates);

    delete values[this.primaryKey];
    if (!_.isEmpty(values)) {
      await this.forge({
        [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
      }).save(values, {
        patch: true,
        transacting,
      });
    }

    const result = await this.forge({
      [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
    }).fetch({
      transacting,
    });

    return result && result.toJSON ? result.toJSON() : result;
  },

  async addRelationMorph(params, { transacting } = {}) {
    const record = await this.morph
      .forge()
      .where({
        [`${this.collectionName}_id`]: params.id,
        [`${params.alias}_id`]: params.refId,
        [`${params.alias}_type`]: params.ref,
        field: params.field,
      })
      .fetch({
        transacting,
      });

    const entry = record ? record.toJSON() : record;

    if (entry) {
      return Promise.resolve();
    }

    return await this.morph
      .forge({
        [`${this.collectionName}_id`]: params.id,
        [`${params.alias}_id`]: params.refId,
        [`${params.alias}_type`]: params.ref,
        field: params.field,
      })
      .save(null, { transacting });
  },

  async removeRelationMorph(params, { transacting } = {}) {
    return await this.morph
      .forge()
      .where(
        _.omitBy(
          {
            [`${this.collectionName}_id`]: params.id,
            [`${params.alias}_id`]: params.refId,
            [`${params.alias}_type`]: params.ref,
            field: params.field,
          },
          _.isUndefined
        )
      )
      .destroy({
        require: false,
        transacting,
      });
  },
};
<commit_msg>Fix multi image upload deleting old links<commit_after>'use strict';

/**
 * Module dependencies
 */

// Public node modules.
const _ = require('lodash');

// Utils
const {
  models: { getValuePrimaryKey },
} = require('strapi-utils');

const transformToArrayID = (array, association) => {
  if (_.isArray(array)) {
    array = array.map(value => {
      if (_.isPlainObject(value)) {
        return value._id || value.id || false;
      }

      return value;
    });

    return array.filter(n => n);
  }

  if (
    association.type === 'model' ||
    (association.type === 'collection' && _.isObject(array))
  ) {
    return _.isEmpty(_.toString(array)) ? [] : transformToArrayID([array]);
  }

  return [];
};

const getModel = (model, plugin) => {
  return (
    _.get(strapi.plugins, [plugin, 'models', model]) ||
    _.get(strapi, ['models', model]) ||
    undefined
  );
};

const removeUndefinedKeys = obj => _.pickBy(obj, _.negate(_.isUndefined));

module.exports = {
  async findOne(params, populate, { transacting } = {}) {
    const record = await this.forge({
      [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
    }).fetch({
      transacting,
      withRelated: populate,
    });

    const data = record ? record.toJSON() : record;

    // Retrieve data manually.
    if (_.isEmpty(populate)) {
      const arrayOfPromises = this.associations
        .filter(association =>
          ['manyMorphToOne', 'manyMorphToMany'].includes(association.nature)
        )
        .map(() => {
          return this.morph
            .forge()
            .where({
              [`${this.collectionName}_id`]: getValuePrimaryKey(
                params,
                this.primaryKey
              ),
            })
            .fetchAll({
              transacting,
            });
        });

      const related = await Promise.all(arrayOfPromises);

      related.forEach((value, index) => {
        data[this.associations[index].alias] = value ? value.toJSON() : value;
      });
    }

    return data;
  },

  async update(params, { transacting } = {}) {
    const relationUpdates = [];
    const primaryKeyValue = getValuePrimaryKey(params, this.primaryKey);
    const response = await module.exports.findOne.call(this, params, null, {
      transacting,
    });

    // Only update fields which are on this document.
    const values =
      params.parseRelationships === false
        ? params.values
        : Object.keys(removeUndefinedKeys(params.values)).reduce(
            (acc, current) => {
              const property = params.values[current];
              const association = this.associations.filter(
                x => x.alias === current
              )[0];
              const details = this._attributes[current];

              if (!association && _.get(details, 'isVirtual') !== true) {
                return _.set(acc, current, property);
              }

              const assocModel = getModel(
                details.model || details.collection,
                details.plugin
              );
              switch (association.nature) {
                case 'oneWay': {
                  return _.set(
                    acc,
                    current,
                    _.get(property, assocModel.primaryKey, property)
                  );
                }
                case 'oneToOne': {
                  if (response[current] === property) return acc;

                  if (_.isNull(property)) {
                    const updatePromise = assocModel
                      .where({
                        [assocModel.primaryKey]: getValuePrimaryKey(
                          response[current],
                          assocModel.primaryKey
                        ),
                      })
                      .save(
                        { [details.via]: null },
                        {
                          method: 'update',
                          patch: true,
                          require: false,
                          transacting,
                        }
                      );

                    relationUpdates.push(updatePromise);
                    return _.set(acc, current, null);
                  }

                  // set old relations to null
                  const updateLink = this.where({ [current]: property })
                    .save(
                      { [current]: null },
                      {
                        method: 'update',
                        patch: true,
                        require: false,
                        transacting,
                      }
                    )
                    .then(() => {
                      return assocModel
                        .where({ [this.primaryKey]: property })
                        .save(
                          { [details.via]: primaryKeyValue },
                          {
                            method: 'update',
                            patch: true,
                            require: false,
                            transacting,
                          }
                        );
                    });

                  // set new relation
                  relationUpdates.push(updateLink);
                  return _.set(acc, current, property);
                }
                case 'oneToMany': {
                  // receive array of ids or array of objects with ids

                  // set relation to null for all the ids not in the list
                  const currentIds = response[current];
                  const toRemove = _.differenceWith(
                    currentIds,
                    property,
                    (a, b) => {
                      return (
                        `${a[assocModel.primaryKey] || a}` ===
                        `${b[assocModel.primaryKey] || b}`
                      );
                    }
                  );

                  const updatePromise = assocModel
                    .where(
                      assocModel.primaryKey,
                      'in',
                      toRemove.map(val => val[assocModel.primaryKey] || val)
                    )
                    .save(
                      { [details.via]: null },
                      {
                        method: 'update',
                        patch: true,
                        require: false,
                        transacting,
                      }
                    )
                    .then(() => {
                      return assocModel
                        .where(
                          assocModel.primaryKey,
                          'in',
                          property.map(val => val[assocModel.primaryKey] || val)
                        )
                        .save(
                          { [details.via]: primaryKeyValue },
                          {
                            method: 'update',
                            patch: true,
                            require: false,
                            transacting,
                          }
                        );
                    });

                  relationUpdates.push(updatePromise);
                  return acc;
                }
                case 'manyToOne': {
                  return _.set(
                    acc,
                    current,
                    _.get(property, assocModel.primaryKey, property)
                  );
                }
                case 'manyWay':
                case 'manyToMany': {
                  const currentValue = transformToArrayID(
                    response[current],
                    association
                  ).map(id => id.toString());
                  const storedValue = transformToArrayID(
                    params.values[current],
                    association
                  ).map(id => id.toString());

                  const toAdd = _.difference(storedValue, currentValue);
                  const toRemove = _.difference(currentValue, storedValue);

                  const collection = this.forge({
                    [this.primaryKey]: primaryKeyValue,
                  })[association.alias]();

                  const updatePromise = collection
                    .detach(toRemove, { transacting })
                    .then(() => collection.attach(toAdd, { transacting }));

                  relationUpdates.push(updatePromise);
                  return acc;
                }
                case 'manyMorphToMany':
                case 'manyMorphToOne':
                  // Update the relational array.
                  params.values[current].forEach(obj => {
                    const model = strapi.getModel(
                      obj.ref,
                      obj.source && obj.source !== 'content-manager'
                        ? obj.source
                        : null
                    );

                    const reverseAssoc = model.associations.find(assoc => assoc.alias === obj.field);

                    // Remove existing relationship because only one file
                    // can be related to this field.
                    if (reverseAssoc && reverseAssoc.nature === 'oneToManyMorph') {
                      relationUpdates.push(
                        module.exports.removeRelationMorph
                          .call(
                            this,
                            {
                              alias: association.alias,
                              ref: model.collectionName,
                              refId: obj.refId,
                              field: obj.field,
                            },
                            { transacting }
                          )
                          .then(() =>
                            module.exports.addRelationMorph.call(
                              this,
                              {
                                id: response[this.primaryKey],
                                alias: association.alias,
                                ref: model.collectionName,
                                refId: obj.refId,
                                field: obj.field,
                              },
                              { transacting }
                            )
                          )
                      );
                    } else {
                      relationUpdates.push(
                        module.exports.addRelationMorph.call(
                          this,
                          {
                            id: response[this.primaryKey],
                            alias: association.alias,
                            ref: model.collectionName,
                            refId: obj.refId,
                            field: obj.field,
                          },
                          { transacting }
                        )
                      );
                    }
                  });
                  break;
                case 'oneToManyMorph':
                case 'manyToManyMorph': {
                  // Compare array of ID to find deleted files.
                  const currentValue = transformToArrayID(
                    response[current],
                    association
                  ).map(id => id.toString());
                  const storedValue = transformToArrayID(
                    params.values[current],
                    association
                  ).map(id => id.toString());

                  const toAdd = _.difference(storedValue, currentValue);
                  const toRemove = _.difference(currentValue, storedValue);

                  const model = getModel(
                    details.collection || details.model,
                    details.plugin
                  );

                  toAdd.forEach(id => {
                    relationUpdates.push(
                      module.exports.addRelationMorph.call(
                        model,
                        {
                          id,
                          alias: association.via,
                          ref: this.collectionName,
                          refId: response.id,
                          field: association.alias,
                        },
                        { transacting }
                      )
                    );
                  });

                  // Update the relational array.
                  toRemove.forEach(id => {
                    relationUpdates.push(
                      module.exports.removeRelationMorph.call(
                        model,
                        {
                          id,
                          alias: association.via,
                          ref: this.collectionName,
                          refId: response.id,
                          field: association.alias,
                        },
                        { transacting }
                      )
                    );
                  });
                  break;
                }
                case 'oneMorphToOne':
                case 'oneMorphToMany': {
                  break;
                }
                default:
              }

              return acc;
            },
            {}
          );

    await Promise.all(relationUpdates);

    delete values[this.primaryKey];
    if (!_.isEmpty(values)) {
      await this.forge({
        [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
      }).save(values, {
        patch: true,
        transacting,
      });
    }

    const result = await this.forge({
      [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey),
    }).fetch({
      transacting,
    });

    return result && result.toJSON ? result.toJSON() : result;
  },

  async addRelationMorph(params, { transacting } = {}) {
    const record = await this.morph
      .forge()
      .where({
        [`${this.collectionName}_id`]: params.id,
        [`${params.alias}_id`]: params.refId,
        [`${params.alias}_type`]: params.ref,
        field: params.field,
      })
      .fetch({
        transacting,
      });

    const entry = record ? record.toJSON() : record;

    if (entry) {
      return Promise.resolve();
    }

    return await this.morph
      .forge({
        [`${this.collectionName}_id`]: params.id,
        [`${params.alias}_id`]: params.refId,
        [`${params.alias}_type`]: params.ref,
        field: params.field,
      })
      .save(null, { transacting });
  },

  async removeRelationMorph(params, { transacting } = {}) {
    return await this.morph
      .forge()
      .where(
        _.omitBy(
          {
            [`${this.collectionName}_id`]: params.id,
            [`${params.alias}_id`]: params.refId,
            [`${params.alias}_type`]: params.ref,
            field: params.field,
          },
          _.isUndefined
        )
      )
      .destroy({
        require: false,
        transacting,
      });
  },
};
<|endoftext|>


<commit_before>/* @flow */
/* global navigator, alert */
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { connect } from 'react-redux';

import { graphql, compose } from 'react-apollo';
import gql from 'graphql-tag';

import SearchBar from './SearchBar';

import Map from '../../natives/Map';
import MapMarker from '../../natives/MapMarker';
import {updateUserLocation} from '../../../redux/actions/user';
import {getVenuesWithTasksNearPosition} from '../../../redux/actions/venue';
import {pushRoute} from '../../../redux/actions/router';

export class MapView extends React.Component {
  state = {
    position: null,
    x: 50,
    y: 50,
  };

  componentWillMount() {
    navigator.geolocation.getCurrentPosition((position) => {
        this._onGetPosition(position);
      },
      (error) => alert(JSON.stringify(error)),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    );
    this.watchID = navigator.geolocation.watchPosition(position => {
      this._onGetPosition(position);
    });
  }
  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  watchID = null;

  _onGetPosition = ({coords}) => {
    this.props.updateUserLocation({lat: coords.latitude, lng: coords.longitude});
  }
  _goToVenueDetails(venue) {
    const {goToVenueDetails} = this.props;
    goToVenueDetails(venue);
  }
  _renderMarkers(venues = []) {
    return venues.map((venue, key) => {
      const cKey = `${venue.source || 'bd'}_${venue._id || venue.foursquareId}`;
      return (
        <MapMarker key={key}
          coordinate={{
            latitude: venue.address.location[1],
            longitude: venue.address.location[0],
          }}
          onPress={() => {
            this._goToVenueDetails(venue);
          }}
          numberOfTasks={venue.nbTasks} />
      );
    });
  }
  render() {
    const {venues, searchResults, venuesError} = this.props;
    console.log('error=> ', venuesError)
    const venuesToShow = (!!searchResults) ? searchResults : venues;
    return (
      <View style={{flex: 1}}>
        <Map style={{
          ...StyleSheet.absoluteFillObject,
          backgroundColor: 'red',
        }} >
          {this._renderMarkers(venuesToShow)}
        </Map>
        <SearchBar openDrawer={this.props.openDrawer} />
      </View>
    );
  }
}

MapView.propTypes = {};

MapView.fragments = {
  venues: gql`
    fragment MapViewVenues on Venue {
      _id,
      foursquareId,
      name,
      source,
      nbTasks
      address {
        location,
      },
    }
  `,
};

const VenuesNearUserQuery = gql`
  query VenuesNearUser($lat: Float!, $lng: Float!, $radius: Float) {
    venuesWithinRadius(lat: $lat, lng: $lng, radius: $radius) {
      ...MapViewVenues
    }
  }
  ${MapView.fragments.venues}
`;

const SearchVenuesQuery = gql`
  query SearchVenues($lat: Float!, $lng: Float!, $radius: Float, $query: String!) {
    searchVenues(lat: $lat, lng: $lng, radius: $radius, query: $query) {
      ...MapViewVenues
    }
  }
  ${MapView.fragments.venues}
`;

const mapStateToProps = (state: Object): Object => ({
  userLocation: state.userLocation,
  query: state.search.query,
});
const mapDispatchToProps = (dispatch: Function): Object => ({
  goToVenueDetails: (venue) => {
    dispatch(pushRoute({
      key: 'venueDetails',
      _id: venue._id,
      id: venue._id,
      sourceId: venue.foursquareId,
      source: 'foursquare',
    }));
  },
  updateUserLocation: ({lat, lng}) => {
    dispatch(updateUserLocation(lat, lng));
  },
});

export default compose(
  connect(mapStateToProps, mapDispatchToProps),
  graphql(VenuesNearUserQuery, {
    skip: ({userLocation}): boolean => (!userLocation || !userLocation.coords),
    options: ({ userLocation: {coords} }): Object => ({
      variables: {
        lat: coords.lat,
        lng: coords.lng,
        radius: 4000,
      },
    }),
    props: ({ ownProps, data: { loading, error, venuesWithinRadius } }) => ({
      ...ownProps,
      loading,
      venuesError: error,
      venues: venuesWithinRadius,
    }),
  }),
  graphql(SearchVenuesQuery, {
    skip: ({userLocation, query}): boolean => (!query || !userLocation || !userLocation.coords),
    options: ({ userLocation: {coords}, query }): Object => ({
      variables: {
        lat: coords.lat,
        lng: coords.lng,
        radius: 4000,
        query,
      },
    }),
    props: ({ ownProps, data: { loading, error, searchVenues } }) => ({
      ...ownProps,
      loading,
      searchError: error,
      searchResults: searchVenues,
    }),
  }),
)(MapView);
<commit_msg>Remove alert on location request timed out<commit_after>/* @flow */
/* global navigator, alert */
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { connect } from 'react-redux';

import { graphql, compose } from 'react-apollo';
import gql from 'graphql-tag';

import SearchBar from './SearchBar';

import Map from '../../natives/Map';
import MapMarker from '../../natives/MapMarker';
import {updateUserLocation} from '../../../redux/actions/user';
import {getVenuesWithTasksNearPosition} from '../../../redux/actions/venue';
import {pushRoute} from '../../../redux/actions/router';

export class MapView extends React.Component {
  state = {
    position: null,
    x: 50,
    y: 50,
  };

  componentWillMount() {
    navigator.geolocation.getCurrentPosition((position) => {
        this._onGetPosition(position);
      },
      (error) => console.log(JSON.stringify(error)),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    );
    this.watchID = navigator.geolocation.watchPosition(position => {
      this._onGetPosition(position);
    });
  }
  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  watchID = null;

  _onGetPosition = ({coords}) => {
    this.props.updateUserLocation({lat: coords.latitude, lng: coords.longitude});
  }
  _goToVenueDetails(venue) {
    const {goToVenueDetails} = this.props;
    goToVenueDetails(venue);
  }
  _renderMarkers(venues = []) {
    return venues.map((venue, key) => {
      const cKey = `${venue.source || 'bd'}_${venue._id || venue.foursquareId}`;
      return (
        <MapMarker key={key}
          coordinate={{
            latitude: venue.address.location[1],
            longitude: venue.address.location[0],
          }}
          onPress={() => {
            this._goToVenueDetails(venue);
          }}
          numberOfTasks={venue.nbTasks} />
      );
    });
  }
  render() {
    const {venues, searchResults, venuesError} = this.props;
    console.log('error=> ', venuesError)
    const venuesToShow = (!!searchResults) ? searchResults : venues;
    return (
      <View style={{flex: 1}}>
        <Map style={{
          ...StyleSheet.absoluteFillObject,
          backgroundColor: 'red',
        }} >
          {this._renderMarkers(venuesToShow)}
        </Map>
        <SearchBar openDrawer={this.props.openDrawer} />
      </View>
    );
  }
}

MapView.propTypes = {};

MapView.fragments = {
  venues: gql`
    fragment MapViewVenues on Venue {
      _id,
      foursquareId,
      name,
      source,
      nbTasks
      address {
        location,
      },
    }
  `,
};

const VenuesNearUserQuery = gql`
  query VenuesNearUser($lat: Float!, $lng: Float!, $radius: Float) {
    venuesWithinRadius(lat: $lat, lng: $lng, radius: $radius) {
      ...MapViewVenues
    }
  }
  ${MapView.fragments.venues}
`;

const SearchVenuesQuery = gql`
  query SearchVenues($lat: Float!, $lng: Float!, $radius: Float, $query: String!) {
    searchVenues(lat: $lat, lng: $lng, radius: $radius, query: $query) {
      ...MapViewVenues
    }
  }
  ${MapView.fragments.venues}
`;

const mapStateToProps = (state: Object): Object => ({
  userLocation: state.userLocation,
  query: state.search.query,
});
const mapDispatchToProps = (dispatch: Function): Object => ({
  goToVenueDetails: (venue) => {
    dispatch(pushRoute({
      key: 'venueDetails',
      _id: venue._id,
      id: venue._id,
      sourceId: venue.foursquareId,
      source: 'foursquare',
    }));
  },
  updateUserLocation: ({lat, lng}) => {
    dispatch(updateUserLocation(lat, lng));
  },
});

export default compose(
  connect(mapStateToProps, mapDispatchToProps),
  graphql(VenuesNearUserQuery, {
    skip: ({userLocation}): boolean => (!userLocation || !userLocation.coords),
    options: ({ userLocation: {coords} }): Object => ({
      variables: {
        lat: coords.lat,
        lng: coords.lng,
        radius: 4000,
      },
    }),
    props: ({ ownProps, data: { loading, error, venuesWithinRadius } }) => ({
      ...ownProps,
      loading,
      venuesError: error,
      venues: venuesWithinRadius,
    }),
  }),
  graphql(SearchVenuesQuery, {
    skip: ({userLocation, query}): boolean => (!query || !userLocation || !userLocation.coords),
    options: ({ userLocation: {coords}, query }): Object => ({
      variables: {
        lat: coords.lat,
        lng: coords.lng,
        radius: 4000,
        query,
      },
    }),
    props: ({ ownProps, data: { loading, error, searchVenues } }) => ({
      ...ownProps,
      loading,
      searchError: error,
      searchResults: searchVenues,
    }),
  }),
)(MapView);
<|endoftext|>


<commit_before>'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var postcss = _interopDefault(require('postcss'));
var postcssScss = _interopDefault(require('postcss-scss'));

var CssSelectorExtract = function CssSelectorExtract () {};

CssSelectorExtract.process = function process(css, selectors, replacementSelectors) {
  return new Promise(function (resolve, reject) {
    var result = CssSelectorExtract.processSync(css, selectors, replacementSelectors);
    resolve(result);
  });
};

CssSelectorExtract.processSync = function processSync(css, selectors, replacementSelectors) {
  return postcss(this.prototype._postcssSelectorExtract(selectors, replacementSelectors)).process(css, { syntax: postcssScss }).css;
};

CssSelectorExtract.prototype._postcssSelectorExtract = function _postcssSelectorExtract(selectors, replacementSelectors) {
    if ( replacementSelectors === void 0 ) replacementSelectors = {};

  return postcss.plugin('postcss-extract-selectors', function (options) {
    return function (cssNodes) {
      cssNodes.walkRules(function (rule) {
        // Split combined selectors into an array.
        var ruleSelectors = rule.selector.split(',').map(function (ruleSelector) { return ruleSelector.replace(/(\r\n|\n|\r)/gm, '').trim(); });
        // Find whitelisted selectors and remove others.
        ruleSelectors.forEach(function (ruleSelector, index) {
          var selectorFilterIndex = selectors.indexOf(ruleSelector);
          // Replace the selector if a replacement selector is defined.
          ruleSelectors[index] = replacementSelectors[ruleSelector] || ruleSelectors[index];
          if (selectorFilterIndex == -1) {
            // Set an empty value for the selector to mark it for deletion.
            ruleSelectors[index] = '';
          }
        });
        // Remove empty selectors.
        ruleSelectors = ruleSelectors.filter(function (ruleSelector) { return ruleSelector.length > 0 || false; });
        if (ruleSelectors.length) {
          rule.selector = ruleSelectors.join(',');
        } else {
          // Remove the rule.
          rule.remove();
        }
      });
      cssNodes.walkAtRules(function (rule) {
        // Remove empty @ rules.
        if (rule.nodes && !rule.nodes.length) {
          rule.remove();
        }
      });
    };
  });
};

module.exports = CssSelectorExtract;<commit_msg>Rebuild dist files<commit_after>'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var postcss = _interopDefault(require('postcss'));
var postcssScss = _interopDefault(require('postcss-scss'));

var CssSelectorExtract = function CssSelectorExtract () {};

CssSelectorExtract.process = function process(css, selectors, replacementSelectors) {
  return new Promise(function (resolve, reject) {
    var result = CssSelectorExtract.processSync(css, selectors, replacementSelectors);
    resolve(result);
  });
};

CssSelectorExtract.processSync = function processSync(css, selectors, replacementSelectors) {
  var postcssSelectorExtract = this.prototype._postcssSelectorExtract(selectors, replacementSelectors);
  return postcss(postcssSelectorExtract).process(css, { syntax: postcssScss }).css;
};

CssSelectorExtract.prototype._postcssSelectorExtract = function _postcssSelectorExtract(selectors, replacementSelectors) {
    if ( replacementSelectors === void 0 ) replacementSelectors = {};

  return postcss.plugin('postcss-extract-selectors', function (options) {
    return function (cssNodes) {
      cssNodes.walkRules(function (rule) {
        // Split combined selectors into an array.
        var ruleSelectors = rule.selector.split(',').map(function (ruleSelector) { return ruleSelector.replace(/(\r\n|\n|\r)/gm, '').trim(); });
        // Find whitelisted selectors and remove others.
        ruleSelectors.forEach(function (ruleSelector, index) {
          var selectorFilterIndex = selectors.indexOf(ruleSelector);
          // Replace the selector if a replacement selector is defined.
          ruleSelectors[index] = replacementSelectors[ruleSelector] || ruleSelectors[index];
          if (selectorFilterIndex == -1) {
            // Set an empty value for the selector to mark it for deletion.
            ruleSelectors[index] = '';
          }
        });
        // Remove empty selectors.
        ruleSelectors = ruleSelectors.filter(function (ruleSelector) { return ruleSelector.length > 0 || false; });
        if (ruleSelectors.length) {
          rule.selector = ruleSelectors.join(',');
        } else {
          // Remove the rule.
          rule.remove();
        }
      });
      cssNodes.walkAtRules(function (rule) {
        // Remove empty @ rules.
        if (rule.nodes && !rule.nodes.length) {
          rule.remove();
        }
      });
    };
  });
};

module.exports = CssSelectorExtract;<|endoftext|>


<commit_before>
window.AudioContext = window.AudioContext||window.webkitAudioContext;
var gAudioContext = new AudioContext();
var gSoundInfoByID = {};
var gBufferByID = {};

function playBufferForID(inID) {
    console.log('playBufferForID', inID);
    var aBufferSource = gAudioContext.createBufferSource();
    aBufferSource.buffer = gBufferByID[inID];
    aBufferSource.connect(gAudioContext.destination);
    aBufferSource.start();
}

function createBufferForID(inID, url) {
    console.log('createBufferForID', inID, url);
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';

    // Decode asynchronously
    request.onload = function() {
        console.log('about to decode', inID, url);
        gAudioContext.decodeAudioData(request.response, function(inBuffer) {
            console.log('decoded', inID, url);
            gBufferByID[inID] = inBuffer;
            handleBufferListUpdate(inID);
        }, function (e) {
            console.log('error handler', e);
        });
    }

    request.send();
}

function getInfoAndLoadPreviewByID(inID) {
    console.log('getInfoAndLoadPreviewByID', inID);
    freesound.getSound(inID,
        function(sound) {
            gSoundInfoByID[inID] = sound;
            handleSoundInfoUpdate(inID);
            createBufferForID(inID, sound.previews['preview-hq-mp3']);
        },
        function(e) {
            console.log("Sound could not be retrieved", e);
        }
    );
}

function handleBufferListUpdate(inID) {
    console.log('buffers now', Object.keys(gBufferByID).length);
    document.getElementById('buffercount').textContent = Object.keys(gBufferByID).length;
}

function handleSoundInfoUpdate(inID) {
    console.log('sound info now', Object.keys(gSoundInfoByID).length);
    document.getElementById('soundinfocount').textContent = Object.keys(gSoundInfoByID).length;
}

function handleSearch(event) {
    event.preventDefault();

    var searchText = document.getElementById('searchtext').value;
    console.log('clicked', searchText);

    console.log('about to search', searchtext);
    freesound.textSearch(searchText, {},
        function(resultsObject) {
            for (var index = 0; index < resultsObject.results.length; index++) {
                getInfoAndLoadPreviewByID(resultsObject.results[index].id);
            }
        }, function(err) {
            console.log('textsearch err', err);
        }
    );
}

function handlePlay(event) {
    event.preventDefault();
    var soundIDs = Object.keys(gBufferByID);
    var randomIndex = Math.floor(Math.random() * soundIDs.length);
    playBufferForID(soundIDs[randomIndex]);

    console.log('handlePlay');
}

window.onload = function(){
    // TODO: must not disclose this in plaintext JS downloaded to user
    freesound.setToken("1beba8e340a9f1b0fad8c5bf14f0361df331a6fb");

    document.getElementById('searchbutton').addEventListener('click', handleSearch);

    document.getElementById('playbutton').addEventListener('click', handlePlay);
};
<commit_msg>maintain search history<commit_after>
window.AudioContext = window.AudioContext||window.webkitAudioContext;
var gAudioContext = new AudioContext();
var gSoundInfoByID = {};
var gBufferByID = {};
var gSearchHistory = {};

function playBufferForID(inID) {
    console.log('playBufferForID', inID);
    var aBufferSource = gAudioContext.createBufferSource();
    aBufferSource.buffer = gBufferByID[inID];
    aBufferSource.connect(gAudioContext.destination);
    aBufferSource.start();
}

function createBufferForID(inID, url) {
    console.log('createBufferForID', inID, url);
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';

    // Decode asynchronously
    request.onload = function() {
        console.log('about to decode', inID, url);
        gAudioContext.decodeAudioData(request.response, function(inBuffer) {
            console.log('decoded', inID, url);
            gBufferByID[inID] = inBuffer;
            handleBufferListUpdate(inID);
        }, function (e) {
            console.log('error handler', e);
        });
    }

    request.send();
}

function getInfoAndLoadPreviewByID(inID) {
    console.log('getInfoAndLoadPreviewByID', inID);
    freesound.getSound(inID,
        function(sound) {
            gSoundInfoByID[inID] = sound;
            handleSoundInfoUpdate(inID);
            createBufferForID(inID, sound.previews['preview-hq-mp3']);
        },
        function(e) {
            console.log("Sound could not be retrieved", e);
        }
    );
}

function handleBufferListUpdate(inID) {
    console.log('buffers now', Object.keys(gBufferByID).length);
    document.getElementById('buffercount').textContent = Object.keys(gBufferByID).length;
}

function handleSoundInfoUpdate(inID) {
    console.log('sound info now', Object.keys(gSoundInfoByID).length);
    document.getElementById('soundinfocount').textContent = Object.keys(gSoundInfoByID).length;
}

function handleSearch(event) {
    event.preventDefault();

    var searchText = document.getElementById('searchtext').value;
    console.log('clicked', searchText);
    gSearchHistory[searchText] = [];

    console.log('about to search', searchtext);
    freesound.textSearch(searchText, {},
        function(resultsObject) {
            for (var index = 0; index < resultsObject.results.length; index++) {
                var tempID = resultsObject.results[index].id;
                gSearchHistory[searchText].push(tempID);
                getInfoAndLoadPreviewByID(tempID);
            }
        }, function(err) {
            console.log('textsearch err', err);
        }
    );
}

function handlePlay(event) {
    event.preventDefault();
    var soundIDs = Object.keys(gBufferByID);
    var randomIndex = Math.floor(Math.random() * soundIDs.length);
    playBufferForID(soundIDs[randomIndex]);

    console.log('handlePlay');
}

window.onload = function(){
    // TODO: must not disclose this in plaintext JS downloaded to user
    freesound.setToken("1beba8e340a9f1b0fad8c5bf14f0361df331a6fb");

    document.getElementById('searchbutton').addEventListener('click', handleSearch);

    document.getElementById('playbutton').addEventListener('click', handlePlay);
};
<|endoftext|>


<commit_before>Template.activityCalendar.rendered = function () {
  // Get reference to template instance
  const instance = this;

  // Update the calendar when instance data changes
  instance.autorun(function () {
    const residentActivities = Template.currentData().activities;
    //console.log(residentActivities);

    // Group activities by activity date
    const nestedActivities = d3.nest()
      .key(function (activity) {
        return activity.activityDate;
      });

    // Get a sum of activities
    const summedActivities = nestedActivities.rollup(function (activity) {
        return {
          duration: d3.sum(activity, function (activity) {
            return activity.duration;
          })
        }
      })
      .entries(residentActivities);

      summedActivities.map(function (activity) {
        // Create date and duration attributes with proper data types
        activity.timestamp = new Date(activity.key).getTime();
        activity.duration = parseInt(activity.values.duration);

        // Delete unused key and values
        delete activity.values
        delete activity.key;
      });

    const activityMapTitle = TAPi18n.__("resident-activityCalendar-title") + " ";

    // Set up the activity map graphic
    const activityMap = new ActivityMap(summedActivities, {
      "id": "#activity-calendar",
      "parent": "#activity-calendar-container",
      "fit": true,
      "title": activityMapTitle,
      "timeColumn": "timestamp",
      "valueColumn": "duration",
      "compact": false
    });

    // Trying to figure out how to re-render the data
    activityMap.process();

    // Render the activity calendar
    activityMap.render();
  });
};
<commit_msg>Update calendar when data changes<commit_after>Template.activityCalendar.rendered = function () {
  // Get reference to template instance
  const instance = this;

  // Update the calendar when instance data changes
  instance.autorun(function () {
    // Empty the Activity Calendar container element, in case of re-render
    $("#activity-calendar-container").empty();

    const residentActivities = Template.currentData().activities;

    // Group activities by activity date
    const nestedActivities = d3.nest()
      .key(function (activity) {
        return activity.activityDate;
      });

    // Get a sum of activities
    const summedActivities = nestedActivities.rollup(function (activity) {
        return {
          duration: d3.sum(activity, function (activity) {
            return activity.duration;
          })
        }
      })
      .entries(residentActivities);

      summedActivities.map(function (activity) {
        // Create date and duration attributes with proper data types
        activity.timestamp = new Date(activity.key).getTime();
        activity.duration = parseInt(activity.values.duration);

        // Delete unused key and values
        delete activity.values
        delete activity.key;
      });

    const activityMapTitle = TAPi18n.__("resident-activityCalendar-title") + " ";

    // Set up the activity map graphic
    const activityMap = new ActivityMap(summedActivities, {
      "id": "activity-calendar",
      "parent": "#activity-calendar-container",
      "fit": true,
      "title": activityMapTitle,
      "timeColumn": "timestamp",
      "valueColumn": "duration",
      "compact": false
    });

    // Trying to figure out how to re-render the data
    activityMap.process();

    // Render the activity calendar
    activityMap.render();
  });
};
<|endoftext|>


<commit_before>"use strict";

function orTrue(v) {
	return typeof v === "boolean" ? v : true;
}

function assert(condition, message) {
	if(!condition) {
		throw message || "Assertion failed";
	}
}

const settings = {
	muteNewTabs:           true,
	muteOnOriginChange:    true,
	muteAllTabsOnStartup:  true,
	unmuteOnVolumeControl: true
}

// Populate settings as soon as possible
chrome.storage.local.get(['muteNewTabs', 'muteOnOriginChange', 'muteAllTabsOnStartup', 'unmuteOnVolumeControl'], function(result) {
	settings.muteNewTabs           = orTrue(result.muteNewTabs);
	settings.muteOnOriginChange    = orTrue(result.muteOnOriginChange);
	settings.muteAllTabsOnStartup  = orTrue(result.muteAllTabsOnStartup);
	settings.unmuteOnVolumeControl = orTrue(result.unmuteOnVolumeControl);

	if(settings.muteAllTabsOnStartup) {
		muteAllTabs();
	}
});

function keyChanged(key, newValue) {
	assert(typeof key === "string");
	if(settings.hasOwnProperty(key)) {
		settings[key] = orTrue(newValue);
	}
}

function storageChanged(changes, namespace) {
	for(const key in changes) {
		var storageChange = changes[key];
		console.log(
			"Storage key", key, "in namespace", namespace, "changed.",
			"Old value was", storageChange.oldValue, "; new value is", storageChange.newValue
		);
		keyChanged(key, storageChange.newValue);
	}
}

function muteTab(tabId) {
	assert(Number.isInteger(tabId));
	chrome.tabs.update(tabId, {muted: true});
}

function unmuteTab(tabId) {
	assert(Number.isInteger(tabId));
	chrome.tabs.update(tabId, {muted: false});
}

function muteAllTabs() {
	chrome.tabs.query({}, function(tabs) {
		for(const tab of tabs) {
			muteTab(tab.id);
		}
	});
}

function maybeMuteNewTab(tab) {
	const tabId = tab.id;
	if(settings.muteNewTabs) {
		console.log("Muting new tab:", tab);
		muteTab(tabId);
	} else {
		console.log("Not muting new tab:", tab);
	}
}

function getOrigin(url) {
	return new URL(url).origin;
}

// TODO: remove entries when tabs are closed
const tabIdToUrl = Object.create(null);

function navigationCommitted(details) {
	if(details.frameId !== 0) {
		// Ignore navigation in subframes
		return;
	}
	const tabId = details.tabId;
	assert(Number.isInteger(tabId));
	const newUrl = details.url;
	if(settings.muteOnOriginChange) {
		const oldUrl = tabIdToUrl[tabId];
		console.log("Old URL:", oldUrl);
		const needMute =
			oldUrl !== undefined &&
			getOrigin(oldUrl) !== getOrigin(newUrl);
		if(needMute) {
			console.log("Muting tab because new origin:", details);
			muteTab(tabId);
		} else {
			console.log("Not muting tab because same origin:", details);
		}
	}
	tabIdToUrl[tabId] = newUrl;
}

function messageFromContentScript(request, sender, sendResponse) {
	console.log("Message from content script: sender=", sender, "request=", request);
	if(request !== "unmute") {
		return;
	}
	if(!settings.unmuteOnVolumeControl) {
		return;
	}
	const tabId = sender.tab.id;
	assert(Number.isInteger(tabId));
	unmuteTab(tabId);
}

// New tabs
chrome.tabs.onCreated.addListener(maybeMuteNewTab);

// Navigation events in a tab
chrome.webNavigation.onCommitted.addListener(navigationCommitted);

// Messages from content scripts telling us to unmute
chrome.runtime.onMessage.addListener(messageFromContentScript);

// Storage events that notify us of settings changes
chrome.storage.onChanged.addListener(storageChanged);
<commit_msg>var -> const<commit_after>"use strict";

function orTrue(v) {
	return typeof v === "boolean" ? v : true;
}

function assert(condition, message) {
	if(!condition) {
		throw message || "Assertion failed";
	}
}

const settings = {
	muteNewTabs:           true,
	muteOnOriginChange:    true,
	muteAllTabsOnStartup:  true,
	unmuteOnVolumeControl: true
}

// Populate settings as soon as possible
chrome.storage.local.get(['muteNewTabs', 'muteOnOriginChange', 'muteAllTabsOnStartup', 'unmuteOnVolumeControl'], function(result) {
	settings.muteNewTabs           = orTrue(result.muteNewTabs);
	settings.muteOnOriginChange    = orTrue(result.muteOnOriginChange);
	settings.muteAllTabsOnStartup  = orTrue(result.muteAllTabsOnStartup);
	settings.unmuteOnVolumeControl = orTrue(result.unmuteOnVolumeControl);

	if(settings.muteAllTabsOnStartup) {
		muteAllTabs();
	}
});

function keyChanged(key, newValue) {
	assert(typeof key === "string");
	if(settings.hasOwnProperty(key)) {
		settings[key] = orTrue(newValue);
	}
}

function storageChanged(changes, namespace) {
	for(const key in changes) {
		const storageChange = changes[key];
		console.log(
			"Storage key", key, "in namespace", namespace, "changed.",
			"Old value was", storageChange.oldValue, "; new value is", storageChange.newValue
		);
		keyChanged(key, storageChange.newValue);
	}
}

function muteTab(tabId) {
	assert(Number.isInteger(tabId));
	chrome.tabs.update(tabId, {muted: true});
}

function unmuteTab(tabId) {
	assert(Number.isInteger(tabId));
	chrome.tabs.update(tabId, {muted: false});
}

function muteAllTabs() {
	chrome.tabs.query({}, function(tabs) {
		for(const tab of tabs) {
			muteTab(tab.id);
		}
	});
}

function maybeMuteNewTab(tab) {
	const tabId = tab.id;
	if(settings.muteNewTabs) {
		console.log("Muting new tab:", tab);
		muteTab(tabId);
	} else {
		console.log("Not muting new tab:", tab);
	}
}

function getOrigin(url) {
	return new URL(url).origin;
}

// TODO: remove entries when tabs are closed
const tabIdToUrl = Object.create(null);

function navigationCommitted(details) {
	if(details.frameId !== 0) {
		// Ignore navigation in subframes
		return;
	}
	const tabId = details.tabId;
	assert(Number.isInteger(tabId));
	const newUrl = details.url;
	if(settings.muteOnOriginChange) {
		const oldUrl = tabIdToUrl[tabId];
		console.log("Old URL:", oldUrl);
		const needMute =
			oldUrl !== undefined &&
			getOrigin(oldUrl) !== getOrigin(newUrl);
		if(needMute) {
			console.log("Muting tab because new origin:", details);
			muteTab(tabId);
		} else {
			console.log("Not muting tab because same origin:", details);
		}
	}
	tabIdToUrl[tabId] = newUrl;
}

function messageFromContentScript(request, sender, sendResponse) {
	console.log("Message from content script: sender=", sender, "request=", request);
	if(request !== "unmute") {
		return;
	}
	if(!settings.unmuteOnVolumeControl) {
		return;
	}
	const tabId = sender.tab.id;
	assert(Number.isInteger(tabId));
	unmuteTab(tabId);
}

// New tabs
chrome.tabs.onCreated.addListener(maybeMuteNewTab);

// Navigation events in a tab
chrome.webNavigation.onCommitted.addListener(navigationCommitted);

// Messages from content scripts telling us to unmute
chrome.runtime.onMessage.addListener(messageFromContentScript);

// Storage events that notify us of settings changes
chrome.storage.onChanged.addListener(storageChanged);
<|endoftext|>


<commit_before>$(document).ready(function(){

  function imageSwitch(n){
    return function(){
      for (var i=0; i<11; i++){
        $('#img_'+i).css('opacity', '0');
      }

      $('#img_'+n).css('opacity', '1');
    }
  }

  for (var i=0; i<5; i++){
    $('#button_'+i)
    .mouseenter(imageSwitch(i+1))
    .mouseleave(imageSwitch(0));

    $('#button_'+i).click(imageSwitch(i+6));
  }

  $('.close_button').click(imageSwitch(9));

});
<commit_msg>Update linkedin.js<commit_after>$(document).ready(function(){

  function imageSwitch(n){
    return function(){
      for (var i=0; i<11; i++){
        $('#img_'+i).css('opacity', '0');
      }

      $('#img_'+n).css('opacity', '1');
    }
  }

  for (var i=0; i<5; i++){
    $('#button_'+i)
    .mouseenter(imageSwitch(i+1))
    .mouseleave(imageSwitch(0));

    $('#button_'+i).click(imageSwitch(i+6));
  }

  $('.close_button').click(imageSwitch(9));

  function closeButtonPosition(){
    var width = $(window).width();
    console.log(width);
    $('.close_button').css('left', (width-960)*0.5+920+'px');
  }

  closeButtonPosition();
  $(window).resize(function(){
    closeButtonPosition()
  });

});
<|endoftext|>