<commit_before>const resolveUrl = require('resolve-url')
const { Plugin } = require('@uppy/core')
const Translator = require('@uppy/utils/lib/Translator')
const limitPromises = require('@uppy/utils/lib/limitPromises')
const { RequestClient } = require('@uppy/companion-client')
const XHRUpload = require('@uppy/xhr-upload')

function isXml (xhr) {
  const contentType = xhr.headers ? xhr.headers['content-type'] : xhr.getResponseHeader('Content-Type')
  return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
}

function assertServerError (res) {
  if (res && res.error) {
    const error = new Error(res.message)
    Object.assign(error, res.error)
    throw error
  }
  return res
}

module.exports = class AwsS3 extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultLocale = {
      strings: {
        preparingUpload: 'Preparing upload...'
      }
    }

    const defaultOptions = {
      timeout: 30 * 1000,
      limit: 0,
      getUploadParameters: this.getUploadParameters.bind(this),
      locale: defaultLocale
    }

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

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

    this.client = new RequestClient(uppy, opts)

    this.prepareUpload = this.prepareUpload.bind(this)

    if (typeof this.opts.limit === 'number' && this.opts.limit !== 0) {
      this.limitRequests = limitPromises(this.opts.limit)
    } else {
      this.limitRequests = (fn) => fn
    }
  }

  getUploadParameters (file) {
    if (!this.opts.serverUrl) {
      throw new Error('Expected a `serverUrl` option containing a Companion address.')
    }

    const filename = encodeURIComponent(file.name)
    const type = encodeURIComponent(file.type)
    return this.client.get(`s3/params?filename=${filename}&type=${type}`)
      .then(assertServerError)
  }

  validateParameters (file, params) {
    const valid = typeof params === 'object' && params &&
      typeof params.url === 'string' &&
      (typeof params.fields === 'object' || params.fields == null) &&
      (params.method == null || /^(put|post)$/i.test(params.method))

    if (!valid) {
      const err = new TypeError(`AwsS3: got incorrect result from 'getUploadParameters()' for file '${file.name}', expected an object '{ url, method, fields, headers }'.\nSee https://uppy.io/docs/aws-s3/#getUploadParameters-file for more on the expected format.`)
      console.error(err)
      throw err
    }

    return params
  }

  prepareUpload (fileIDs) {
    fileIDs.forEach((id) => {
      const file = this.uppy.getFile(id)
      this.uppy.emit('preprocess-progress', file, {
        mode: 'determinate',
        message: this.i18n('preparingUpload'),
        value: 0
      })
    })

    const getUploadParameters = this.limitRequests(this.opts.getUploadParameters)

    return Promise.all(
      fileIDs.map((id) => {
        const file = this.uppy.getFile(id)
        const paramsPromise = Promise.resolve()
          .then(() => getUploadParameters(file))
        return paramsPromise.then((params) => {
          return this.validateParameters(file, params)
        }).then((params) => {
          this.uppy.emit('preprocess-progress', file, {
            mode: 'determinate',
            message: this.i18n('preparingUpload'),
            value: 1
          })
          return params
        }).catch((error) => {
          this.uppy.emit('upload-error', file, error)
        })
      })
    ).then((responses) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.uppy.getFile(id)
        if (file.error) {
          return
        }

        const {
          method = 'post',
          url,
          fields,
          headers
        } = responses[index]
        const xhrOpts = {
          method,
          formData: method.toLowerCase() === 'post',
          endpoint: url,
          metaFields: Object.keys(fields)
        }

        if (headers) {
          xhrOpts.headers = headers
        }

        const updatedFile = Object.assign({}, file, {
          meta: Object.assign({}, file.meta, fields),
          xhrUpload: xhrOpts
        })

        updatedFiles[id] = updatedFile
      })

      this.uppy.setState({
        files: Object.assign({}, this.uppy.getState().files, updatedFiles)
      })

      fileIDs.forEach((id) => {
        const file = this.uppy.getFile(id)
        this.uppy.emit('preprocess-complete', file)
      })
    })
  }

  install () {
    const { log } = this.uppy
    this.uppy.addPreProcessor(this.prepareUpload)

    let warnedSuccessActionStatus = false
    this.uppy.use(XHRUpload, {
      fieldName: 'file',
      responseUrlFieldName: 'location',
      timeout: this.opts.timeout,
      limit: this.opts.limit,
      // Get the response data from a successful XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseData (content, xhr) {
        const opts = this

        // If no response, we've hopefully done a PUT request to the file
        // in the bucket on its full URL.
        if (!isXml(xhr)) {
          if (opts.method.toUpperCase() === 'POST') {
            if (!warnedSuccessActionStatus) {
              log('[AwsS3] No response data found, make sure to set the success_action_status AWS SDK option to 201. See https://uppy.io/docs/aws-s3/#POST-Uploads', 'warning')
              warnedSuccessActionStatus = true
            }
            // The responseURL won't contain the object key. Give up.
            return { location: null }
          }

          // responseURL is not available in older browsers.
          if (!xhr.responseURL) {
            return { location: null }
          }

          // Trim the query string because it's going to be a bunch of presign
          // parameters for a PUT request—doing a GET request with those will
          // always result in an error
          return { location: xhr.responseURL.replace(/\?.*$/, '') }
        }

        let getValue = () => ''
        if (xhr.responseXML) {
          getValue = (key) => {
            const el = xhr.responseXML.querySelector(key)
            return el ? el.textContent : ''
          }
        }

        if (xhr.responseText) {
          getValue = (key) => {
            const start = xhr.responseText.indexOf(`<${key}>`)
            const end = xhr.responseText.indexOf(`</${key}>`)
            return start !== -1 && end !== -1
              ? xhr.responseText.slice(start + key.length + 2, end)
              : ''
          }
        }

        return {
          // Some S3 alternatives do not reply with an absolute URL.
          // Eg DigitalOcean Spaces uses /$bucketName/xyz
          location: resolveUrl(xhr.responseURL, getValue('Location')),
          bucket: getValue('Bucket'),
          key: getValue('Key'),
          etag: getValue('ETag')
        }
      },

      // Get the error data from a failed XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseError (content, xhr) {
        // If no response, we don't have a specific error message, use the default.
        if (!isXml(xhr)) {
          return
        }
        const error = xhr.responseXML.querySelector('Error > Message')
        return new Error(error.textContent)
      }
    })
  }

  uninstall () {
    const uploader = this.uppy.getPlugin('XHRUpload')
    this.uppy.removePlugin(uploader)

    this.uppy.removePreProcessor(this.prepareUpload)
  }
}
<commit_msg>Object rest spread<commit_after>const resolveUrl = require('resolve-url')
const { Plugin } = require('@uppy/core')
const Translator = require('@uppy/utils/lib/Translator')
const limitPromises = require('@uppy/utils/lib/limitPromises')
const { RequestClient } = require('@uppy/companion-client')
const XHRUpload = require('@uppy/xhr-upload')

function isXml (xhr) {
  const contentType = xhr.headers ? xhr.headers['content-type'] : xhr.getResponseHeader('Content-Type')
  return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
}

function assertServerError (res) {
  if (res && res.error) {
    const error = new Error(res.message)
    Object.assign(error, res.error)
    throw error
  }
  return res
}

module.exports = class AwsS3 extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultLocale = {
      strings: {
        preparingUpload: 'Preparing upload...'
      }
    }

    const defaultOptions = {
      timeout: 30 * 1000,
      limit: 0,
      getUploadParameters: this.getUploadParameters.bind(this),
      locale: defaultLocale
    }

    this.opts = { ...defaultOptions, ...opts }
    this.locale = {
      ...defaultLocale,
      ...this.opts.locale,
      strings: { ...defaultLocale.strings, ...this.opts.locale.strings }
    }

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

    this.client = new RequestClient(uppy, opts)

    this.prepareUpload = this.prepareUpload.bind(this)

    if (typeof this.opts.limit === 'number' && this.opts.limit !== 0) {
      this.limitRequests = limitPromises(this.opts.limit)
    } else {
      this.limitRequests = (fn) => fn
    }
  }

  getUploadParameters (file) {
    if (!this.opts.serverUrl) {
      throw new Error('Expected a `serverUrl` option containing a Companion address.')
    }

    const filename = encodeURIComponent(file.name)
    const type = encodeURIComponent(file.type)
    return this.client.get(`s3/params?filename=${filename}&type=${type}`)
      .then(assertServerError)
  }

  validateParameters (file, params) {
    const valid = typeof params === 'object' && params &&
      typeof params.url === 'string' &&
      (typeof params.fields === 'object' || params.fields == null) &&
      (params.method == null || /^(put|post)$/i.test(params.method))

    if (!valid) {
      const err = new TypeError(`AwsS3: got incorrect result from 'getUploadParameters()' for file '${file.name}', expected an object '{ url, method, fields, headers }'.\nSee https://uppy.io/docs/aws-s3/#getUploadParameters-file for more on the expected format.`)
      console.error(err)
      throw err
    }

    return params
  }

  prepareUpload (fileIDs) {
    fileIDs.forEach((id) => {
      const file = this.uppy.getFile(id)
      this.uppy.emit('preprocess-progress', file, {
        mode: 'determinate',
        message: this.i18n('preparingUpload'),
        value: 0
      })
    })

    const getUploadParameters = this.limitRequests(this.opts.getUploadParameters)

    return Promise.all(
      fileIDs.map((id) => {
        const file = this.uppy.getFile(id)
        const paramsPromise = Promise.resolve()
          .then(() => getUploadParameters(file))
        return paramsPromise.then((params) => {
          return this.validateParameters(file, params)
        }).then((params) => {
          this.uppy.emit('preprocess-progress', file, {
            mode: 'determinate',
            message: this.i18n('preparingUpload'),
            value: 1
          })
          return params
        }).catch((error) => {
          this.uppy.emit('upload-error', file, error)
        })
      })
    ).then((responses) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.uppy.getFile(id)
        if (file.error) {
          return
        }

        const {
          method = 'post',
          url,
          fields,
          headers
        } = responses[index]
        const xhrOpts = {
          method,
          formData: method.toLowerCase() === 'post',
          endpoint: url,
          metaFields: Object.keys(fields)
        }

        if (headers) {
          xhrOpts.headers = headers
        }

        const updatedFile = Object.assign({}, file, {
          meta: Object.assign({}, file.meta, fields),
          xhrUpload: xhrOpts
        })

        updatedFiles[id] = updatedFile
      })

      this.uppy.setState({
        files: Object.assign({}, this.uppy.getState().files, updatedFiles)
      })

      fileIDs.forEach((id) => {
        const file = this.uppy.getFile(id)
        this.uppy.emit('preprocess-complete', file)
      })
    })
  }

  install () {
    const { log } = this.uppy
    this.uppy.addPreProcessor(this.prepareUpload)

    let warnedSuccessActionStatus = false
    this.uppy.use(XHRUpload, {
      fieldName: 'file',
      responseUrlFieldName: 'location',
      timeout: this.opts.timeout,
      limit: this.opts.limit,
      // Get the response data from a successful XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseData (content, xhr) {
        const opts = this

        // If no response, we've hopefully done a PUT request to the file
        // in the bucket on its full URL.
        if (!isXml(xhr)) {
          if (opts.method.toUpperCase() === 'POST') {
            if (!warnedSuccessActionStatus) {
              log('[AwsS3] No response data found, make sure to set the success_action_status AWS SDK option to 201. See https://uppy.io/docs/aws-s3/#POST-Uploads', 'warning')
              warnedSuccessActionStatus = true
            }
            // The responseURL won't contain the object key. Give up.
            return { location: null }
          }

          // responseURL is not available in older browsers.
          if (!xhr.responseURL) {
            return { location: null }
          }

          // Trim the query string because it's going to be a bunch of presign
          // parameters for a PUT request—doing a GET request with those will
          // always result in an error
          return { location: xhr.responseURL.replace(/\?.*$/, '') }
        }

        let getValue = () => ''
        if (xhr.responseXML) {
          getValue = (key) => {
            const el = xhr.responseXML.querySelector(key)
            return el ? el.textContent : ''
          }
        }

        if (xhr.responseText) {
          getValue = (key) => {
            const start = xhr.responseText.indexOf(`<${key}>`)
            const end = xhr.responseText.indexOf(`</${key}>`)
            return start !== -1 && end !== -1
              ? xhr.responseText.slice(start + key.length + 2, end)
              : ''
          }
        }

        return {
          // Some S3 alternatives do not reply with an absolute URL.
          // Eg DigitalOcean Spaces uses /$bucketName/xyz
          location: resolveUrl(xhr.responseURL, getValue('Location')),
          bucket: getValue('Bucket'),
          key: getValue('Key'),
          etag: getValue('ETag')
        }
      },

      // Get the error data from a failed XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseError (content, xhr) {
        // If no response, we don't have a specific error message, use the default.
        if (!isXml(xhr)) {
          return
        }
        const error = xhr.responseXML.querySelector('Error > Message')
        return new Error(error.textContent)
      }
    })
  }

  uninstall () {
    const uploader = this.uppy.getPlugin('XHRUpload')
    this.uppy.removePlugin(uploader)

    this.uppy.removePreProcessor(this.prepareUpload)
  }
}
<|endoftext|>


<commit_before>import log from '../lib/logger-service';
import Builder from '../chatbot/builder';
import Messenger from '../facebook-messenger/messenger-service';

import strings from './strings.json';
import PersonalInformationFormatter
 from '../lib/personal-information-formatter-service';
import CommunicationMethodsFormatter
 from '../lib/communication-methods-formatter';
import PairFormatter from '../lib/pair-formatter';
import Sessions from '../util/sessions-service';
// import AcceptedPairFormatter from '../lib/accepted-pair-formatter';
import Pairs from '../util/pairs-service';

export function setName({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      name: input,
    },
  });
}

export function setJob({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      job: input,
    },
  });
}

export function setAge({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      age: input,
    },
  });
}

export function setPlace({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      place: input,
    },
  });
}

export function updateProfile({ context, userData }) {
  let profile = PersonalInformationFormatter.createProfile(context);

  return Promise.resolve({
    userData: {
      ...userData,
      profile,
    },
  });
}

export function addCommunicationMethod({ context, input }) {
  let undefinedCommunicationInfo = 'UNDEFINED_COMMUNICATION_INFO';
  let method = CommunicationMethodsFormatter
    .getCommunicationMethodByInput(input);
  return Promise.resolve({
    context: {
      ...context,
      communicationMethods: {
        ...context.communicationMethods,
        [method.identifier]: undefinedCommunicationInfo,
      },
    },
    result: method.infoRequestText,
  });
}

export function addCommunicationInfo({ context, input }) {
  return new Promise((resolve, reject) => {
    let communicationMethods = context.communicationMethods;

    let undefinedCommunicationInfo = 'UNDEFINED_COMMUNICATION_INFO';

    for (let method in communicationMethods) {
      if (communicationMethods[method] !== undefinedCommunicationInfo) {
        continue;
      }

      return resolve({
        context: {
          ...context,
          communicationMethods: {
            ...communicationMethods,
            [method]: input,
          },
        },
      });
    }

    return resolve({
      context: {
        ...context,
        communicationMethods: {
          input,
        },
      },
    });
  });
}

export function reset() {
  return Promise.resolve({
    context: {},
  });
}
export function addMeetingFrequency( { context, input } ) {
  return Promise.resolve({
    context: {
      ...context,
      meetingFrequency: PersonalInformationFormatter
        .getMeetingFrequencyIdentifierByInput(input),
    },
  });
}

export function markUserAsSearching({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      searching: true,
    },
  });
}

export function markUserAsNotSearching({ context }) {
    return Promise.resolve({
        context: {
            ...context,
            rejectedPeers: [],
            availablePeers: [],
            pairRequests: [],
            searching: false,
        },
    });
}

export function updateAvailablePeers({ sessionId, context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    const rejectedPeers = context.rejectedPeers || [];

    return sessions.getAvailablePairs(sessionId, context.meetingFrequency)
      .then((pairs) => {
        resolve({
          context: {
            ...context,
            availablePeers: pairs
                .map((entry) => entry.id)
                .filter((entry) => rejectedPeers.indexOf(entry) < 0),
          },
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function displayAvailablePeer({ context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    return sessions.read(context.availablePeers[0])
      .then((profile) => {
        resolve({
          result: PairFormatter.createPairString(profile),
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function nextAvailablePeer({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      availablePeers: context.availablePeers.slice(1),
    },
  });
}

export function rejectAvailablePeer({ context }) {
  const rejectedPeers = context.rejectedPeers || [];
  rejectedPeers.push(context.availablePeers[0]);

  return Promise.resolve({
    context: {
      ...context,
      rejectedPeers,
    },
  });
}

export function nextRequest({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      pairRequests: context.pairRequests.slice(1).concat(
          context.pairRequests.slice(0, 1)),
    },
  });
}

export function rejectRequest({ context }) {
  const rejectedPeers = context.rejectedPeers || [];
  rejectedPeers.push(context.pairRequests[0]);

  return Promise.resolve({
    context: {
      ...context,
      rejectedPeers,
      pairRequests: context.pairRequests.slice(1),
    },
  });
}

export function acceptRequest({ sessionId, context }) {
  let pairs = new Pairs();

  return pairs.createPair(sessionId, context.pairRequests[0])
      .then(() => {
        return { result: '@PAIR_CREATED' };
      });
}

export function displayRequest({ context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    return sessions.read(context.pairRequests[0])
      .then((profile) => {
        resolve({
          result: PairFormatter.createPairString(profile),
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function addPairRequest({ sessionId, context }) {
  let peerId = context.availablePeers[0];
  let session = new Sessions();

  return session.read(peerId).then((chosenPeer) => {
    if (chosenPeer.searching) {
      if (chosenPeer.pairRequests === undefined) {
        chosenPeer.pairRequests = [];
      }
      chosenPeer.pairRequests.push(sessionId);

      return session.write(peerId, chosenPeer)
          .then(() => {
            // skip notification on local client
            if (process.env.RUN_ENV === 'dev') return;

            return Messenger.send(
              peerId,
              strings['@TELL_USER_HAS_NEW_REQUEST'],
              Builder.QuickReplies.createArray([
                strings['@SHOW_REQUESTS'],
                strings['@STOP_SEARCHING'],
              ])
            );
          })
          .then(() => {
            return {
              result: '@CONFIRM_NEW_PEER_ASK',
            };
          });
    } else {
      return Promise.resolve({
        result: '@PEER_NO_LONGER_AVAILABLE',
      });
    }
  });
}
<commit_msg>Update actions.js<commit_after>import log from '../lib/logger-service';
import Builder from '../chatbot/builder';
import Messenger from '../facebook-messenger/messenger-service';

import strings from './strings.json';
import PersonalInformationFormatter
 from '../lib/personal-information-formatter-service';
import CommunicationMethodsFormatter
 from '../lib/communication-methods-formatter';
import PairFormatter from '../lib/pair-formatter';
import Sessions from '../util/sessions-service';
import Pairs from '../util/pairs-service';

export function setName({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      name: input,
    },
  });
}

export function setJob({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      job: input,
    },
  });
}

export function setAge({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      age: input,
    },
  });
}

export function setPlace({ context, input }) {
  return Promise.resolve({
    context: {
      ...context,
      place: input,
    },
  });
}

export function updateProfile({ context, userData }) {
  let profile = PersonalInformationFormatter.createProfile(context);

  return Promise.resolve({
    userData: {
      ...userData,
      profile,
    },
  });
}

export function addCommunicationMethod({ context, input }) {
  let undefinedCommunicationInfo = 'UNDEFINED_COMMUNICATION_INFO';
  let method = CommunicationMethodsFormatter
    .getCommunicationMethodByInput(input);
  return Promise.resolve({
    context: {
      ...context,
      communicationMethods: {
        ...context.communicationMethods,
        [method.identifier]: undefinedCommunicationInfo,
      },
    },
    result: method.infoRequestText,
  });
}

export function addCommunicationInfo({ context, input }) {
  return new Promise((resolve, reject) => {
    let communicationMethods = context.communicationMethods;

    let undefinedCommunicationInfo = 'UNDEFINED_COMMUNICATION_INFO';

    for (let method in communicationMethods) {
      if (communicationMethods[method] !== undefinedCommunicationInfo) {
        continue;
      }

      return resolve({
        context: {
          ...context,
          communicationMethods: {
            ...communicationMethods,
            [method]: input,
          },
        },
      });
    }

    return resolve({
      context: {
        ...context,
        communicationMethods: {
          input,
        },
      },
    });
  });
}

export function reset() {
  return Promise.resolve({
    context: {},
  });
}
export function addMeetingFrequency( { context, input } ) {
  return Promise.resolve({
    context: {
      ...context,
      meetingFrequency: PersonalInformationFormatter
        .getMeetingFrequencyIdentifierByInput(input),
    },
  });
}

export function markUserAsSearching({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      searching: true,
    },
  });
}

export function markUserAsNotSearching({ context }) {
    return Promise.resolve({
        context: {
            ...context,
            rejectedPeers: [],
            availablePeers: [],
            pairRequests: [],
            searching: false,
        },
    });
}

export function updateAvailablePeers({ sessionId, context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    const rejectedPeers = context.rejectedPeers || [];

    return sessions.getAvailablePairs(sessionId, context.meetingFrequency)
      .then((pairs) => {
        resolve({
          context: {
            ...context,
            availablePeers: pairs
                .map((entry) => entry.id)
                .filter((entry) => rejectedPeers.indexOf(entry) < 0),
          },
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function displayAvailablePeer({ context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    return sessions.read(context.availablePeers[0])
      .then((profile) => {
        resolve({
          result: PairFormatter.createPairString(profile),
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function nextAvailablePeer({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      availablePeers: context.availablePeers.slice(1),
    },
  });
}

export function rejectAvailablePeer({ context }) {
  const rejectedPeers = context.rejectedPeers || [];
  rejectedPeers.push(context.availablePeers[0]);

  return Promise.resolve({
    context: {
      ...context,
      rejectedPeers,
    },
  });
}

export function nextRequest({ context }) {
  return Promise.resolve({
    context: {
      ...context,
      pairRequests: context.pairRequests.slice(1).concat(
          context.pairRequests.slice(0, 1)),
    },
  });
}

export function rejectRequest({ context }) {
  const rejectedPeers = context.rejectedPeers || [];
  rejectedPeers.push(context.pairRequests[0]);

  return Promise.resolve({
    context: {
      ...context,
      rejectedPeers,
      pairRequests: context.pairRequests.slice(1),
    },
  });
}

export function acceptRequest({ sessionId, context }) {
  let pairs = new Pairs();

  return pairs.createPair(sessionId, context.pairRequests[0])
      .then(() => {
        return { result: '@PAIR_CREATED' };
      });
}

export function displayRequest({ context }) {
  return new Promise((resolve, reject) => {
    let sessions = new Sessions();

    return sessions.read(context.pairRequests[0])
      .then((profile) => {
        resolve({
          result: PairFormatter.createPairString(profile),
        });
      })
      .catch((err) => {
        log.error('err: {0}', err);
        reject(err);
      });
  });
}

export function addPairRequest({ sessionId, context }) {
  let peerId = context.availablePeers[0];
  let session = new Sessions();

  return session.read(peerId).then((chosenPeer) => {
    if (chosenPeer.searching) {
      if (chosenPeer.pairRequests === undefined) {
        chosenPeer.pairRequests = [];
      }
      chosenPeer.pairRequests.push(sessionId);

      return session.write(peerId, chosenPeer)
          .then(() => {
            // skip notification on local client
            if (process.env.RUN_ENV === 'dev') return;

            return Messenger.send(
              peerId,
              strings['@TELL_USER_HAS_NEW_REQUEST'],
              Builder.QuickReplies.createArray([
                strings['@SHOW_REQUESTS'],
                strings['@STOP_SEARCHING'],
              ])
            );
          })
          .then(() => {
            return {
              result: '@CONFIRM_NEW_PEER_ASK',
            };
          });
    } else {
      return Promise.resolve({
        result: '@PEER_NO_LONGER_AVAILABLE',
      });
    }
  });
}
<|endoftext|>


<commit_before>/*
---
name: Behavior
description: Auto-instantiates widgets/classes based on parsed, declarative HTML.
requires: [Core/Class.Extras, Core/Element, Core/Selectors, /Element.Data, More/Table]
provides: [DashSelectors, Behavior]
...
*/

(function(){

	this.Behavior = new Class({

		Implements: [Options, Events],

		options: {
			//by default, errors thrown by filters are caught; the onError event is fired.
			//set this to *true* to NOT catch these errors to allow them to be handled by the browser.
			// breakOnErrors: false,

			//default error behavior when a filter cannot be applied
			onError: function(){
				if (window.console && console.warn){
					if(console.warn.apply) console.warn.apply(console, arguments);
					else console.warn($A(arguments).join(' '));
				}
			}
			//Components that have a Behavior instance (like an ART.Window)
			//call these events to tell filters that need to know that the state
			//has changed:
			// onResize: $empty, //the element's dimensions have changed
			// onShow: $empty, //the element is displayed
			// onHide: $empty //the element is hidden
		},

		initialize: function(options){
			this.setOptions(options);
			this.passMethods({
				addEvent: this.addEvent.bind(this),
				removeEvent: this.removeEvent.bind(this),
				addEvents: this.addEvents.bind(this),
				removeEvents: this.removeEvents.bind(this),
				//this doesn't really stand up; the container is variable - one behavior instance
				//can handle numerous containers... TODO: revisit
				getContainerSize: function() { return this.currentSize; }.bind(this),
				error: function(){ this.fireEvent('error', arguments); }.bind(this)
			});
		},

		//pass a method pointer through to a filter
		//by default the methods for add/remove events are passed to the filter
		//pointed to this instance of behavior. you could use this to pass along
		//other methods to your filters. For example, a method to close a popup
		//for filters presented inside popups.
		_passedMethods: {},
		passMethod: function(method, fn){
			var self = this;
			this._passedMethods[method] = function(){
				return fn.apply(this, arguments);
			};
			return this;
		},

		passMethods: function(methods){
			for (method in methods) {
				this.passMethod(method, methods[method]);
			}
			return this;
		},

		//These methods don't change the element's state but rather are used
		//to tell filters that need to adapt to the new element state that
		//it has changed.
		show: function(){
			return this.fireEvent('show');
		},

		//the element is hidden
		hide: function(){
			return this.fireEvent('hide');
		},

		//the element's dimensions are now the specified width and height
		resize: function(x, y){
			this.currentSize = {x: x, y: y};
			return this.fireEvent('resize', [x, y]);
		},

		//Applies all the behavior filters for an element.
		//container - (element) an element to apply the filters registered with this Behavior instance to.
		//force - (boolean; optional) passed through to applyFilter (see it for docs)
		apply: function(container, force){
			document.id(container).getElements('[data-filters]').each(function(element){
				element.getData('filters').split(',').each(function(name){
					var behavior = this.getFilter(name.trim());
					if (!behavior) this.fireEvent('error', ['There is no behavior registered with this name: ', name, element]);
					else this.applyFilter(element, behavior, force);
				}, this);
			}, this);
			return this;
		},

		//Applies a specific behavior to a specific element.
		//element - the element to which to apply the behavior
		//filter - (object) a specific behavior filter, typically one registered with this instance or registered globally.
		//force - (boolean; optional) apply the behavior to each element it matches, even if it was previously applied. Defaults to *false*.
		applyFilter: function(element, filter, force){
			var run = function(){
				element = document.id(element);
				//get the filters already applied to this element
				var applied = getApplied(element);
				//if this filter is not yet applied to the element, or we are forcing the filter
				if (!applied[filter.name] || force) {
					//if it was previously applied, garbage collect it
					if (applied[filter.name]) applied[filter.name].cleanup(element);
					//apply the filter
					filter.attach(element, this._passedMethods);
					//and mark it as having been previously applied
					applied[filter.name] = filter;
					//apply all the plugins for this filter
					var plugins = this.getPlugins(filter.name);
					if (plugins) {
						for (name in plugins) {
							this.applyFilter(element, plugins[name], force);
						}
					}
				}
			}.bind(this);
			if (this.options.breakOnErrors) {
				run();
			} else {
				try {
					run();
				} catch (e) {
					this.fireEvent('error', ['Could not apply the behavior ' + filter.name, e]);
				}
			}
			return this;
		},

		//given a name, returns a registered behavior
		getFilter: function(name){
			return this._registered[name] || Behavior._registered[name];
		},

		getPlugins: function(name){
			return this._plugins[name] || Behavior._plugins[name];
		},

		//Garbage collects all applied filters for an element and its children.
		//element - (*element*) container to cleanup
		//ignoreChildren - (*boolean*; optional) if *true* only the element will be cleaned, otherwise the element and all the
		//	  children with filters applied will be cleaned. Defaults to *false*.
		cleanup: function(element, ignoreChildren){
			element = document.id(element);
			var applied = getApplied(element);
			for (behavior in applied) {
				applied[behavior].cleanup(element);
				delete applied[behavior];
			}
			if (!ignoreChildren) element.getElements(':hasBehaviors').each(this.cleanup, this);
			return this;
		}

	});

	//Returns the applied behaviors for an element.
	var getApplied = function(el){
		return el.retrieve('_appliedBehaviors', {});
	};

	//Registers a behavior filter.
	//name - the name of the filter
	//fn - a function that applies the filter to the given element
	//overwrite - (boolean) if true, will overwrite existing filter if one exists; defaults to false.
	var addFilter = function(name, fn, overwrite){
		if (!this._registered[name] || overwrite) this._registered[name] = new Behavior.Filter(name, fn);
	};

	var addFilters = function(obj, overwrite) {
		for (var name in obj) {
			addFilter.apply(this, [name, obj[name], overwrite]);
		}
	};

	//Registers a behavior plugin
	//filterName - (*string*) the filter (or plugin) this is a plugin for
	//name - (*string*) the name of this plugin
	//attacher - a function that applies the filter to the given element
	var addPlugin = function(filterName, name, attacher, overwrite) {
		if (!this._plugins[filterName]) this._plugins[filterName] = {};
		if (!this._plugins[filterName][name] || overwrite) this._plugins[filterName][name] = new Behavior.Filter(name, attacher);
	};

	var addPlugins = function(obj, overwrite) {
		for (name in obj) {
			addPlugin.apply(this, [obj[name].fitlerName, obj[name].name, obj[name].attacher], overwrite);
		}
	};

	//Add methods to the Behavior namespace for global registration.
	$extend(Behavior, {
		_registered: {},
		_plugins: {},
		addGlobalFilter: addFilter,
		addGlobalFilters: addFilters,
		addGlobalPlugin: addPlugin,
		addGlobalPlugins: addPlugins
	});
	//Add methods to the Behavior class for instance registration.
	Behavior.implement({
		_registered: {},
		_plugins: {},
		addFilter: addFilter,
		addFilters: addFilters,
		addPlugin: addPlugin,
		addPlugins: addPlugins
	});

	//This class is an actual filter that, given an element, alters it with specific behaviors.
	Behavior.Filter = new Class({

		//Pass in an object with the following properties:
		//name - the name of this filter
		//attacher - a function that applies the filter to the given element
		initialize: function(name, attacher){
			this.name = name;
			this.attach = attacher;
			this._marks = new Table();
		},

		//Stores a garbage collection pointer for a specific element.
		//Example: if your filter enhances all the inputs in the container
		//you might have a function that removes that enhancement for garbage collection.
		//You would mark each input matched with its own cleanup function.
		//NOTE: this MUST be the element passed to the filter - the element with this filters
		//      name in its data-filter property. I.E.:
		//<form data-filter="FormValidator">
		//  <input type="text" name="email"/>
		//</form>
		//If this filter is FormValidator, you can mark the form for cleanup, but not, for example
		//the input. Only elements that match this filter can be marked.
		markForCleanup: function(element, fn){
			var marks = this._marks.get(element);
			if (!marks) marks = [];
			marks.include(fn);
			this._marks.set(element, marks);
			return this;
		},

		//Garbage collect a specific element.
		//NOTE: this should be an element that has a data-filter property that matches this filter.
		cleanup: function(element){
			var marks = this._marks.get(element);
			if (marks) {
				marks.each(function(fn){ fn(); });
				this._marks.erase(element);
			}
			return this;
		}

	});

})();

//a selector to find all elements that have behaviors applied to them.
Selectors.Pseudo.hasBehaviors = function(){
	return !!Element.retrieve(this, '_appliedBehaviors');
};

Element.implement({

	addDataFilter: function(name){
		return this.set('data', 'filters', this.getDataFilters().include(name).join(','));
	},

	removeDataFilter: function(name){
		return this.set('data', 'filters', this.getDataFilters().erase(name).join(','));
	},

	getDataFilters: function(){
		var filters = this.getData('filters');
		if (!filters) return [];
		return filters.split(',').map(String.trim);
	},

	hasDataFilter: function(name){
		return this.getDataFilters().contains(name);
	}

});

//allows for selectors like $$('[data-foo-bar]'); TODO: Note that it'll be in Moo 1.3; remove then.
if (window.Selectors && Selectors.RegExps) {
	Selectors.RegExps.combined = (/\.([\w-]+)|\[([\w-]+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g);
}<commit_msg>adding applyBehavior/s to the behaviorAPI<commit_after>/*
---
name: Behavior
description: Auto-instantiates widgets/classes based on parsed, declarative HTML.
requires: [Core/Class.Extras, Core/Element, Core/Selectors, /Element.Data, More/Table]
provides: [DashSelectors, Behavior]
...
*/

(function(){

	this.Behavior = new Class({

		Implements: [Options, Events],

		options: {
			//by default, errors thrown by filters are caught; the onError event is fired.
			//set this to *true* to NOT catch these errors to allow them to be handled by the browser.
			// breakOnErrors: false,

			//default error behavior when a filter cannot be applied
			onError: function(){
				if (window.console && console.warn){
					if(console.warn.apply) console.warn.apply(console, arguments);
					else console.warn($A(arguments).join(' '));
				}
			}
			//Components that have a Behavior instance (like an ART.Window)
			//call these events to tell filters that need to know that the state
			//has changed:
			// onResize: $empty, //the element's dimensions have changed
			// onShow: $empty, //the element is displayed
			// onHide: $empty //the element is hidden
		},

		initialize: function(options){
			this.setOptions(options);
			this.passMethods({
				addEvent: this.addEvent.bind(this),
				removeEvent: this.removeEvent.bind(this),
				addEvents: this.addEvents.bind(this),
				removeEvents: this.removeEvents.bind(this),
				applyBehaviors: this.apply.bind(this),
				applyBehavior: this.applyBehavior.bind(this),
				//this doesn't really stand up; the container is variable - one behavior instance
				//can handle numerous containers... TODO: revisit
				getContainerSize: function() { return this.currentSize; }.bind(this),
				error: function(){ this.fireEvent('error', arguments); }.bind(this)
			});
		},

		//pass a method pointer through to a filter
		//by default the methods for add/remove events are passed to the filter
		//pointed to this instance of behavior. you could use this to pass along
		//other methods to your filters. For example, a method to close a popup
		//for filters presented inside popups.
		_passedMethods: {},
		passMethod: function(method, fn){
			var self = this;
			this._passedMethods[method] = function(){
				return fn.apply(this, arguments);
			};
			return this;
		},

		passMethods: function(methods){
			for (method in methods) {
				this.passMethod(method, methods[method]);
			}
			return this;
		},

		//These methods don't change the element's state but rather are used
		//to tell filters that need to adapt to the new element state that
		//it has changed.
		show: function(){
			return this.fireEvent('show');
		},

		//the element is hidden
		hide: function(){
			return this.fireEvent('hide');
		},

		//the element's dimensions are now the specified width and height
		resize: function(x, y){
			this.currentSize = {x: x, y: y};
			return this.fireEvent('resize', [x, y]);
		},

		//Applies all the behavior filters for an element.
		//container - (element) an element to apply the filters registered with this Behavior instance to.
		//force - (boolean; optional) passed through to applyFilter (see it for docs)
		apply: function(container, force){
			document.id(container).getElements('[data-filters]').each(function(element){
				element.getData('filters').split(',').each(function(name){
					var behavior = this.getFilter(name.trim());
					if (!behavior) this.fireEvent('error', ['There is no behavior registered with this name: ', name, element]);
					else this.applyFilter(element, behavior, force);
				}, this);
			}, this);
			return this;
		},

		//Applies a specific behavior to a specific element.
		//element - the element to which to apply the behavior
		//filter - (object) a specific behavior filter, typically one registered with this instance or registered globally.
		//force - (boolean; optional) apply the behavior to each element it matches, even if it was previously applied. Defaults to *false*.
		applyFilter: function(element, filter, force){
			var run = function(){
				element = document.id(element);
				//get the filters already applied to this element
				var applied = getApplied(element);
				//if this filter is not yet applied to the element, or we are forcing the filter
				if (!applied[filter.name] || force) {
					//if it was previously applied, garbage collect it
					if (applied[filter.name]) applied[filter.name].cleanup(element);
					//apply the filter
					filter.attach(element, this._passedMethods);
					//and mark it as having been previously applied
					applied[filter.name] = filter;
					//apply all the plugins for this filter
					var plugins = this.getPlugins(filter.name);
					if (plugins) {
						for (name in plugins) {
							this.applyFilter(element, plugins[name], force);
						}
					}
				}
			}.bind(this);
			if (this.options.breakOnErrors) {
				run();
			} else {
				try {
					run();
				} catch (e) {
					this.fireEvent('error', ['Could not apply the behavior ' + filter.name, e]);
				}
			}
			return this;
		},

		//given a name, returns a registered behavior
		getFilter: function(name){
			return this._registered[name] || Behavior._registered[name];
		},

		getPlugins: function(name){
			return this._plugins[name] || Behavior._plugins[name];
		},

		//Garbage collects all applied filters for an element and its children.
		//element - (*element*) container to cleanup
		//ignoreChildren - (*boolean*; optional) if *true* only the element will be cleaned, otherwise the element and all the
		//	  children with filters applied will be cleaned. Defaults to *false*.
		cleanup: function(element, ignoreChildren){
			element = document.id(element);
			var applied = getApplied(element);
			for (behavior in applied) {
				applied[behavior].cleanup(element);
				delete applied[behavior];
			}
			if (!ignoreChildren) element.getElements(':hasBehaviors').each(this.cleanup, this);
			return this;
		}

	});

	//Returns the applied behaviors for an element.
	var getApplied = function(el){
		return el.retrieve('_appliedBehaviors', {});
	};

	//Registers a behavior filter.
	//name - the name of the filter
	//fn - a function that applies the filter to the given element
	//overwrite - (boolean) if true, will overwrite existing filter if one exists; defaults to false.
	var addFilter = function(name, fn, overwrite){
		if (!this._registered[name] || overwrite) this._registered[name] = new Behavior.Filter(name, fn);
	};

	var addFilters = function(obj, overwrite) {
		for (var name in obj) {
			addFilter.apply(this, [name, obj[name], overwrite]);
		}
	};

	//Registers a behavior plugin
	//filterName - (*string*) the filter (or plugin) this is a plugin for
	//name - (*string*) the name of this plugin
	//attacher - a function that applies the filter to the given element
	var addPlugin = function(filterName, name, attacher, overwrite) {
		if (!this._plugins[filterName]) this._plugins[filterName] = {};
		if (!this._plugins[filterName][name] || overwrite) this._plugins[filterName][name] = new Behavior.Filter(name, attacher);
	};

	var addPlugins = function(obj, overwrite) {
		for (name in obj) {
			addPlugin.apply(this, [obj[name].fitlerName, obj[name].name, obj[name].attacher], overwrite);
		}
	};

	//Add methods to the Behavior namespace for global registration.
	$extend(Behavior, {
		_registered: {},
		_plugins: {},
		addGlobalFilter: addFilter,
		addGlobalFilters: addFilters,
		addGlobalPlugin: addPlugin,
		addGlobalPlugins: addPlugins
	});
	//Add methods to the Behavior class for instance registration.
	Behavior.implement({
		_registered: {},
		_plugins: {},
		addFilter: addFilter,
		addFilters: addFilters,
		addPlugin: addPlugin,
		addPlugins: addPlugins
	});

	//This class is an actual filter that, given an element, alters it with specific behaviors.
	Behavior.Filter = new Class({

		//Pass in an object with the following properties:
		//name - the name of this filter
		//attacher - a function that applies the filter to the given element
		initialize: function(name, attacher){
			this.name = name;
			this.attach = attacher;
			this._marks = new Table();
		},

		//Stores a garbage collection pointer for a specific element.
		//Example: if your filter enhances all the inputs in the container
		//you might have a function that removes that enhancement for garbage collection.
		//You would mark each input matched with its own cleanup function.
		//NOTE: this MUST be the element passed to the filter - the element with this filters
		//      name in its data-filter property. I.E.:
		//<form data-filter="FormValidator">
		//  <input type="text" name="email"/>
		//</form>
		//If this filter is FormValidator, you can mark the form for cleanup, but not, for example
		//the input. Only elements that match this filter can be marked.
		markForCleanup: function(element, fn){
			var marks = this._marks.get(element);
			if (!marks) marks = [];
			marks.include(fn);
			this._marks.set(element, marks);
			return this;
		},

		//Garbage collect a specific element.
		//NOTE: this should be an element that has a data-filter property that matches this filter.
		cleanup: function(element){
			var marks = this._marks.get(element);
			if (marks) {
				marks.each(function(fn){ fn(); });
				this._marks.erase(element);
			}
			return this;
		}

	});

})();

//a selector to find all elements that have behaviors applied to them.
Selectors.Pseudo.hasBehaviors = function(){
	return !!Element.retrieve(this, '_appliedBehaviors');
};

Element.implement({

	addDataFilter: function(name){
		return this.set('data', 'filters', this.getDataFilters().include(name).join(','));
	},

	removeDataFilter: function(name){
		return this.set('data', 'filters', this.getDataFilters().erase(name).join(','));
	},

	getDataFilters: function(){
		var filters = this.getData('filters');
		if (!filters) return [];
		return filters.split(',').map(String.trim);
	},

	hasDataFilter: function(name){
		return this.getDataFilters().contains(name);
	}

});

//allows for selectors like $$('[data-foo-bar]'); TODO: Note that it'll be in Moo 1.3; remove then.
if (window.Selectors && Selectors.RegExps) {
	Selectors.RegExps.combined = (/\.([\w-]+)|\[([\w-]+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g);
}<|endoftext|>


<commit_before>import Vue from 'vue'

import { stopAndPrevent } from '../../utils/event.js'
import slot from '../../utils/slot.js'
import { getAllChildren } from '../../utils/vm.js'

export default Vue.extend({
  name: 'QForm',

  props: {
    autofocus: Boolean
  },

  mounted () {
    this.validateIndex = 0
    this.autofocus === true && this.focus()
  },

  methods: {
    validate () {
      const promises = []

      this.validateIndex++

      const components = getAllChildren(this)
      const emit = res => {
        this.$emit('validation-' + (res === true ? 'success' : 'error'))
      }

      for (let i = 0; i < components.length; i++) {
        const comp = components[i]

        if (typeof comp.validate === 'function') {
          const valid = comp.validate()

          if (typeof valid.then === 'function') {
            promises.push(valid.then(v => ({ valid: v, comp }), error => ({ valid: false, comp, error })))
          }
          else if (valid !== true) {
            emit(false)
            typeof comp.focus === 'function' && comp.focus()
            return Promise.resolve(false)
          }
        }
      }

      if (promises.length === 0) {
        emit(true)
        return Promise.resolve(true)
      }

      const index = this.validateIndex

      return Promise.all(promises).then(
        res => {
          if (index === this.validateIndex) {
            const { valid, comp } = res[0]
            emit(valid)
            valid !== true && typeof comp.focus === 'function' && comp.focus()
            return valid
          }
        }
      )
    },

    resetValidation () {
      this.validateIndex++

      getAllChildren(this).forEach(comp => {
        if (typeof comp.resetValidation === 'function') {
          comp.resetValidation()
        }
      })
    },

    submit (evt) {
      evt !== void 0 && stopAndPrevent(evt)

      this.validate().then(val => {
        val === true && this.$emit('submit')
      })
    },

    reset (evt) {
      evt !== void 0 && stopAndPrevent(evt)

      this.$emit('reset')

      this.$nextTick(() => { // allow userland to reset values before
        this.resetValidation()
        this.autofocus === true && this.focus()
      })
    },

    focus () {
      const target = this.$el.querySelector('[autofocus]') || this.$el.querySelector('[tabindex]')
      target !== null && target.focus()
    }
  },

  render (h) {
    return h('form', {
      staticClass: 'q-form',
      on: {
        ...this.$listeners,
        submit: this.submit,
        reset: this.reset
      }
    }, slot(this, 'default'))
  }
})
<commit_msg>Update QForm.js<commit_after>import Vue from 'vue'

import { stopAndPrevent } from '../../utils/event.js'
import slot from '../../utils/slot.js'
import { getAllChildren } from '../../utils/vm.js'

export default Vue.extend({
  name: 'QForm',

  props: {
    autofocus: Boolean
  },

  mounted () {
    this.validateIndex = 0
    this.autofocus === true && this.focus()
  },

  methods: {
    validate () {
      const promises = []

      this.validateIndex++

      const components = getAllChildren(this)
      const emit = res => {
        this.$emit('validation-' + (res === true ? 'success' : 'error'))
      }

      for (let i = 0; i < components.length; i++) {
        const comp = components[i]

        if (typeof comp.validate === 'function') {
          const valid = comp.validate()

          if (typeof valid.then === 'function') {
            promises.push(
              valid.then(
                v => ({ valid: v, comp }),
                error => ({ valid: false, comp, error })
              )
            )
          }
          else if (valid !== true) {
            emit(false)
            typeof comp.focus === 'function' && comp.focus()
            return Promise.resolve(false)
          }
        }
      }

      if (promises.length === 0) {
        emit(true)
        return Promise.resolve(true)
      }

      const index = this.validateIndex

      return Promise.all(promises).then(
        res => {
          if (index === this.validateIndex) {
            const { valid, comp } = res[0]
            emit(valid)
            valid !== true && typeof comp.focus === 'function' && comp.focus()
            return valid
          }
        }
      )
    },

    resetValidation () {
      this.validateIndex++

      getAllChildren(this).forEach(comp => {
        if (typeof comp.resetValidation === 'function') {
          comp.resetValidation()
        }
      })
    },

    submit (evt) {
      evt !== void 0 && stopAndPrevent(evt)

      this.validate().then(val => {
        val === true && this.$emit('submit')
      })
    },

    reset (evt) {
      evt !== void 0 && stopAndPrevent(evt)

      this.$emit('reset')

      this.$nextTick(() => { // allow userland to reset values before
        this.resetValidation()
        this.autofocus === true && this.focus()
      })
    },

    focus () {
      const target = this.$el.querySelector('[autofocus]') || this.$el.querySelector('[tabindex]')
      target !== null && target.focus()
    }
  },

  render (h) {
    return h('form', {
      staticClass: 'q-form',
      on: {
        ...this.$listeners,
        submit: this.submit,
        reset: this.reset
      }
    }, slot(this, 'default'))
  }
})
<|endoftext|>


<commit_before>'use strict'
/**
 * Created by acastillo on 7/1/16.
 */
define([
    'file-saver',
    'src/util/api',
    'src/util/ui',
    'https://www.lactame.com/lib/openchemlib-extended/1.11.0/openchemlib-extended.js',
    'https://www.lactame.com/lib/chemcalc/3.0.6/chemcalc.js',
    'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js',
    'https://www.lactame.com/github/cheminfo-js/visualizer-helper/7f9c4d2c296389ed263a43826bafeba1164d13de/rest-on-couch/Roc.js'
], function (fileSaver, API, UI, OCLE, CC, elnPlugin, Roc) {

    var defaultOptions = {
        varName: 'sample',
        track: true
    };

    class Sample {
        constructor(couchDB, uuid, options) {
            this.options = Object.assign({}, defaultOptions, options);

            var roc = API.cache('roc');
            if (!roc) {
                roc = new Roc({
                    url: couchDB.url,
                    database: couchDB.database,
                    processor: elnPlugin,
                    kind: couchDB.kind
                });
                API.cache('roc', roc);
            }
            this.roc = roc;

            this.uuid = uuid;
            if (!this.uuid) {
                UI.showNotification("Cannot create an editable sample without an uuid", 'error');
                return;
            }
            this._loadInstanceInVisualizer();
        }

        _loadInstanceInVisualizer() {
            this.roc.document(this.uuid, {
                varName: this.options.varName
            }).then(sample => {
                this.sample = sample;
                var sampleVar = API.getVar(this.options.varName);
                API.setVariable('sampleCode', sampleVar, ['$id', 0]);
                API.setVariable('batchCode', sampleVar, ['$id', 1]);
                API.setVariable('creationDate', sampleVar, ['$creationDate']);
                API.setVariable('modificationDate', sampleVar, ['$modificationDate']);
                API.setVariable('content', sampleVar, ['$content']);
                API.setVariable('molfile', sampleVar, ['$content', 'general', 'molfile']);
                API.setVariable('mf', sampleVar, ['$content', 'general', 'mf']);
                API.setVariable('mw', sampleVar, ['$content', 'general', 'mw']);
                API.setVariable('description', sampleVar, ['$content', 'general', 'description']);
                API.setVariable('iupac', sampleVar, ['$content', 'general', 'iupac']);
                API.setVariable('bp', sampleVar, ['$content', 'physical', 'bp']);
                API.setVariable('nd', sampleVar, ['$content', 'physical', 'nd']);
                API.setVariable('mp', sampleVar, ['$content', 'physical', 'mp']);
                API.setVariable('density', sampleVar, ['$content', 'physical', 'density']);
                API.setVariable('nmr', sampleVar, ['$content', 'spectra', 'nmr']);
                API.setVariable('ir', sampleVar, ['$content', 'spectra', 'ir']);
                API.setVariable('mass', sampleVar, ['$content', 'spectra', 'mass']);
                this.updateAttachments(sample);

                this.updateChemcalc();
                initializeNMRAssignment();

                sample.onChange((event) => {
                    if (typeof IframeBridge !== 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: false
                        });
                    }

                    console.log("change event received", event.jpath.join('.'), event);

                    switch (event.jpath.join('.')) {
                        case 'general.molfile':

                            break;
                        case 'general.mf':
                            this.updateChemcalc();
                            break;
                    }
                });

                if (typeof OCLE != 'undefined' && this.options.track) {
                    var expandableMolecule = new ExpandableMolecule(sample);
                    API.cache('expandableMolecule', expandableMolecule);
                }
            });
        }

        updateChemcalc() {
            this.chemcalc=undefined;
            if (this.sample.general && this.sample.general.mf) {
                try {
                    this.chemcalc=CC.analyzeMF(this.sample.general.mf);
                } catch (e) {
                    UI.showNotification('Could not calculate molecular formula: '+e);
                    console.log(e);
                }
            }
        }

        updateAttachments(entry) {
            return this.roc.getAttachmentList(this.uuid).then(function (list) {
                API.createData('sampleAttachments', list);
            })
        }

        handleActionSD(action) {
            switch (action.name) {
                case 'reset1d':
                case 'reset2d':
                    if (this.event !== 'action') return;

                    var type;
                    if (action.name === 'reset1d') type = '1'
                    else if (action.name === 'reset2d') type = '2'
                    else return;

                    var legend = API.cache('legend');
                    if (!legend) {
                        legend = {
                            1: {},
                            2: {}
                        }
                        API.cache('legend', legend);
                    }

                    legend[type] = {};

                    type = type + 'd';
                    API.createData('black', null);
                    API.createData('annot' + type, null);
                    API.createData('legend' + type, {});
                    API.createData('acs', null);

                    break;
                case 'executePeakPicking':
                    //API.doAction("reset1d");
                    // the action may be generated by clicking on a line or clicking on the button to
                    // recalculate the peak picking.
                    var editedNmr;
                    if (action.value.dimension) { // Fired from click on row. We can not take variable because it may not exist yet
                        editedNmr = action.value;
                        if (editedNmr.dimension > 1) {
                            API.createData('black2d', editedNmr.jcamp.data);
                            API.switchToLayer('2D');
                            return;
                        } else {
                            API.switchToLayer('Default layer');
                            API.createData('black1d', editedNmr.jcamp.data);
                        }
                    } else { // we click on the button, show an alert if we want to redo peak picking
                        editedNmr = API.getData('editedNmr');
                        if (editedNmr.dimension > 1) {
                            if (typeof UI != "undefined")
                                UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                            return;
                        }
                    }
                    if (action.value.integral) {//Fired from button
                        doAssignment();
                    } else {
                        if (!editedNmr.range || !editedNmr.range.length) {
                            doAssignment();
                        } else {
                            API.setVariable("editedRange", API.getVariable('editedNmr'), ["range"]);
                        }
                    }
                    API.createData("nmrParams", {
                        "nucleus": editedNmr.nucleus[0],
                        "observe": Math.floor(editedNmr.frequency / 10) * 10
                    });
                    break;
                default:
                    return false;
            }
            return true;
        }

         doAssignment() {
            var jcamp = editedNmr.getChild(['jcamp', 'data']);

            jcamp.then(function(jcamp) {
                jcamp = String(jcamp.get());
                var ppOptions = JSON.parse(JSON.stringify(API.getData("options1H")));
                var integral = ppOptions.integral;
                //console.log(ppOptions);
                if(!ppOptions.noiseFactor){
                    ppOptions = {"noiseFactor":0.8,"clean":true,"compile":true,"optimize":false,"integralFn":"sum", "type":"1H"};
                }

                var spectrum = SD.NMR.fromJcamp(jcamp);
                //spectrum.fillWith(4.7,4.9,0);
                //spectrum.fillWith(-0.1,0.1,0);
                var intFN = 0;
                if(ppOptions.integralFn=="peaks"){
                    intFN=1;
                }
                var peakPicking = spectrum.nmrPeakDetection({"nH":integral,
                    realTop:true,
                    thresholdFactor:ppOptions.noiseFactor,
                    clean:ppOptions.clean,
                    compile:ppOptions.compile,
                    optimize:ppOptions.optimize,
                    integralFn:intFN,
                    idPrefix:spectrum.getNucleus()+"",
                    gsdOptions:{minMaxRatio:0.001, smoothY:false, broadWidth:0},
                    format:"new"
                });
                editedNmr.setChildSync(['range'], peakPicking);
                API.setVariable("editedRange",API.getVariable('editedNmr'),["range"]);
            });

        }

        handleAction(action) {
            if (!action) return;

            if (handleActionSD(action)) return;

            switch (action.name) {
                case 'refresh':
                    this.roc.get(this.uuid);
                    break;
                case 'save':
                    this.roc.update(this.sample).then(function () {
                        if (typeof IframeBridge != 'undefined') {
                            IframeBridge.postMessage('tab.status', {
                                saved: true
                            });
                        }
                    });
                    break;

                case 'toggleJSMEEdition':
                    API.cache("expandableMolecule").toggleJSMEEdition();
                    break;
                case 'clearMolfile':
                    var molfile=API.getData('editableMolfile');
                    molfile.setValue('');
                    break;
                case 'swapHydrogens':
                    API.cache("expandableMolecule").setExpandedHydrogens();
                    break;
                case 'toggleNMR1hAdvancedOptions':
                    API.cache('nmr1hAdvancedOptions', ! API.cache('nmr1hAdvancedOptions'));
                case 'createOptions':
                    var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                    if (advancedOptions1H) {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                    } else {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                    }
                    break;
                case 'downloadSVG':
                    var blob = new Blob([this.action.value+""], {type: "application/jcamp-dx;charset=utf-8"});
                    fileSaver(blob, 'spectra.svg');
                    break;

                case 'deleteAttachment':
                    var attachment = action.value.name;
                    this.roc.deleteAttachment(sample, attachment).then(this.updateAttachments);
                    break;
                case 'deleteSpectra':
                    this.roc.unattach(sample, action.value).then(this.updateAttachments);
                    break;
                case 'attachNMR':
                case 'attachIR':
                case 'attachMass':
                    var type = action.name.replace("attach", "").toLowerCase();
                    var droppedDatas = data;
                    droppedDatas = droppedDatas.file || droppedDatas.str;
                    var prom = Promise.resolve();
                    for (let i = 0; i < droppedDatas.length; i++) {
                        prom = prom.then(() => {
                            var data = DataObject.resurrect(droppedDatas[i]);
                            return this.roc.attach(type, sample, data);
                        });
                    }

                    prom.then(() => {
                        this.updateAttachments(sample);
                    }).catch(() => {
                        this.updateAttachments(sample);
                    });
                    break;
                default:
                    break
            }
        }

        initializeNMRAssignment() {
            console.log(this.chemcalc);

            API.createData('nmr1hOptions', {
                "noiseFactor": 0.8,
                "clean": true,
                "compile": true,
                "optimize": false,
                "integralFn": "sum",
                "integral": 30,
                "type": "1H"
            });

            API.createData('nmr1hOndeTemplates', {
                "full": {
                    "type": "object",
                    "properties": {
                        "integral": {
                            "type": "number",
                            "title": "value to fit the spectrum integral",
                            "label": "Integral"
                        },
                        "noiseFactor": {
                            "type": "number",
                            "title": "Mutiplier of the auto-detected noise level",
                            "label": "noiseFactor"
                        },
                        "clean": {
                            "type": "boolean",
                            "title": "Delete signals with integration less than 0.5",
                            "label": "clean"
                        },
                        "compile": {
                            "type": "boolean",
                            "title": "Compile the multiplets",
                            "label": "compile"
                        },
                        "optimize": {
                            "type": "boolean",
                            "title": "Optimize the peaks to fit the spectrum",
                            "label": "optimize"
                        },
                        "integralFn": {
                            "type": "string",
                            "title": "Type of integration",
                            "label": "Integral type",
                            "enum": [
                                "sum",
                                "peaks"
                            ]
                        },
                        "type": {
                            "type": "string",
                            "title": "Nucleus",
                            "label": "Nucleus",
                            "editable": false
                        }
                    }
                },
                "short": {
                    "type": "object",
                    "properties": {
                        "integral": {
                            "type": "number",
                            "title": "value to fit the spectrum integral",
                            "label": "Integral"
                        }
                    }
                }
            }).then(function(nmr1hOndeTemplates) {
                API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
            });
        }
    }

    class ExpandableMolecule {
        constructor(sampleIn) {
            this.sample = sampleIn;
            this.molfile = this.sample.$content.general.molfile + '';
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.idCode = molecule.getIDCode();
            this.expandedHydrogens = false;
            this.jsmeEditionMode = false;
            API.createData('editableMolfile', this.molfile).then(
                (editableMolfile) => {
                    editableMolfile.onChange( (event) => {
                        // us this really a modification ? or a loop event ...
                        // need to compare former oclID with new oclID
                        var idCode = OCLE.Molecule.fromMolfile(event.target + '').getIDCode();
                        if (idCode != this.idCode) {
                            this.idCode = idCode;
                            this.molfile = event.target + '';
                            this.sample.setChildSync('$content.general.molfile', this.molfile);
                        } else {
                            console.log('no update');
                        }

                        // by default we would like the depict mode
                        this.updateMolfiles();
                        this.updateMF();
                    });
                    this.updateMolfiles();
                    this.toggleJSMEEdition(false);
                }
            );
        }

        toggleJSMEEdition(force, noDepictUpdate) {
            if (force !== undefined && force === this.jsmeEditionMode) return;
            if (force === undefined) {
                this.jsmeEditionMode = !this.jsmeEditionMode;
            } else {
                this.jsmeEditionMode = force;
            }
            var prefs = {
                "prefs": [
                    "oldlook",
                    "nozoom"
                ],
                "labelsize": "14",
                "bondwidth": "1",
                "defaultaction": "105",
                "highlightColor": "3",
                "outputResult": [
                    "yes"
                ]
            };

            if (this.jsmeEditionMode) {
                API.getData("editableMolfile").triggerChange();
                this.expandedHydrogens = false;
            } else {
                prefs.prefs.push('depict');
                if (!noDepictUpdate) {
                    this.expandedHydrogens = false;
                    API.createData("viewMolfile", this.viewMolfile);
                }

            }
            API.doAction('setJSMEPreferences', prefs)
        }

        setExpandedHydrogens(force) {
            if (force === undefined) {
                this.expandedHydrogens = !this.expandedHydrogens;
            } else {
                this.expandedHydrogens = force;
            }
            if (this.expandedHydrogens) {
                API.createData("viewMolfileExpandedH", this.viewMolfileExpandedH);
                this.toggleJSMEEdition(false, true);
            } else {
                API.createData("viewMolfile", this.viewMolfile);
            }
        }

        updateMolfiles() {
            // prevent the loop by checking actelionID
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.viewMolfile = molecule.toVisualizerMolfile();

            molecule.addImplicitHydrogens();
            this.viewMolfileExpandedH = molecule.toVisualizerMolfile();
            this.mf = molecule.getMolecularFormula().formula;
            this.mw = molecule.getMolecularFormula().relativeWeight;
            this.nH = molecule.getNumberOfAtoms('H');
        }

        updateMF() {
            if (typeof UI != 'undefined')
                UI.showNotification('Updated mf and mw', 'info');
            this.sample.$content.general.molfile = this.molfile;
            this.sample.$content.general.mf = this.mf;
            this.sample.$content.general.mw = this.mw;
        }
    }

    return Sample;
});

<commit_msg>Fix bugs<commit_after>'use strict'
/**
 * Created by acastillo on 7/1/16.
 */
define([
    'file-saver',
    'src/util/api',
    'src/util/ui',
    'https://www.lactame.com/lib/openchemlib-extended/1.11.0/openchemlib-extended.js',
    'https://www.lactame.com/lib/chemcalc/3.0.6/chemcalc.js',
    'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js',
    'https://www.lactame.com/github/cheminfo-js/visualizer-helper/7f9c4d2c296389ed263a43826bafeba1164d13de/rest-on-couch/Roc.js'
], function (fileSaver, API, UI, OCLE, CC, elnPlugin, Roc) {

    var defaultOptions = {
        varName: 'sample',
        track: true
    };

    class Sample {
        constructor(couchDB, uuid, options) {
            this.options = Object.assign({}, defaultOptions, options);

            var roc = API.cache('roc');
            if (!roc) {
                roc = new Roc({
                    url: couchDB.url,
                    database: couchDB.database,
                    processor: elnPlugin,
                    kind: couchDB.kind
                });
                API.cache('roc', roc);
            }
            this.roc = roc;

            this.uuid = uuid;
            if (!this.uuid) {
                UI.showNotification("Cannot create an editable sample without an uuid", 'error');
                return;
            }
            this._loadInstanceInVisualizer();
        }

        _loadInstanceInVisualizer() {
            this.roc.document(this.uuid, {
                varName: this.options.varName
            }).then(sample => {
                this.sample = sample;
                var sampleVar = API.getVar(this.options.varName);
                API.setVariable('sampleCode', sampleVar, ['$id', 0]);
                API.setVariable('batchCode', sampleVar, ['$id', 1]);
                API.setVariable('creationDate', sampleVar, ['$creationDate']);
                API.setVariable('modificationDate', sampleVar, ['$modificationDate']);
                API.setVariable('content', sampleVar, ['$content']);
                API.setVariable('molfile', sampleVar, ['$content', 'general', 'molfile']);
                API.setVariable('mf', sampleVar, ['$content', 'general', 'mf']);
                API.setVariable('mw', sampleVar, ['$content', 'general', 'mw']);
                API.setVariable('description', sampleVar, ['$content', 'general', 'description']);
                API.setVariable('iupac', sampleVar, ['$content', 'general', 'iupac']);
                API.setVariable('bp', sampleVar, ['$content', 'physical', 'bp']);
                API.setVariable('nd', sampleVar, ['$content', 'physical', 'nd']);
                API.setVariable('mp', sampleVar, ['$content', 'physical', 'mp']);
                API.setVariable('density', sampleVar, ['$content', 'physical', 'density']);
                API.setVariable('nmr', sampleVar, ['$content', 'spectra', 'nmr']);
                API.setVariable('ir', sampleVar, ['$content', 'spectra', 'ir']);
                API.setVariable('mass', sampleVar, ['$content', 'spectra', 'mass']);
                this.updateAttachments(sample);

                this.updateChemcalc();
                this.initializeNMRAssignment();

                sample.onChange((event) => {
                    if (typeof IframeBridge !== 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: false
                        });
                    }

                    console.log("change event received", event.jpath.join('.'), event);

                    switch (event.jpath.join('.')) {
                        case 'general.molfile':

                            break;
                        case 'general.mf':
                            this.updateChemcalc();
                            break;
                    }
                });

                if (typeof OCLE != 'undefined' && this.options.track) {
                    var expandableMolecule = new ExpandableMolecule(sample);
                    API.cache('expandableMolecule', expandableMolecule);
                }
            });
        }

        updateChemcalc() {
            this.chemcalc=undefined;
            if (this.sample.general && this.sample.general.mf) {
                try {
                    this.chemcalc=CC.analyzeMF(this.sample.general.mf);
                } catch (e) {
                    UI.showNotification('Could not calculate molecular formula: '+e);
                    console.log(e);
                }
            }
        }

        updateAttachments(entry) {
            return this.roc.getAttachmentList(this.uuid).then(function (list) {
                API.createData('sampleAttachments', list);
            })
        }

        handleActionSD(action) {
            switch (action.name) {
                case 'reset1d':
                case 'reset2d':
                    if (this.event !== 'action') return;

                    var type;
                    if (action.name === 'reset1d') type = '1'
                    else if (action.name === 'reset2d') type = '2'
                    else return;

                    var legend = API.cache('legend');
                    if (!legend) {
                        legend = {
                            1: {},
                            2: {}
                        }
                        API.cache('legend', legend);
                    }

                    legend[type] = {};

                    type = type + 'd';
                    API.createData('black', null);
                    API.createData('annot' + type, null);
                    API.createData('legend' + type, {});
                    API.createData('acs', null);

                    break;
                case 'executePeakPicking':
                    //API.doAction("reset1d");
                    // the action may be generated by clicking on a line or clicking on the button to
                    // recalculate the peak picking.
                    var editedNmr;
                    if (action.value.dimension) { // Fired from click on row. We can not take variable because it may not exist yet
                        editedNmr = action.value;
                        if (editedNmr.dimension > 1) {
                            API.createData('black2d', editedNmr.jcamp.data);
                            API.switchToLayer('2D');
                            return;
                        } else {
                            API.switchToLayer('Default layer');
                            API.createData('black1d', editedNmr.jcamp.data);
                        }
                    } else { // we click on the button, show an alert if we want to redo peak picking
                        editedNmr = API.getData('editedNmr');
                        if (editedNmr.dimension > 1) {
                            if (typeof UI != "undefined")
                                UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                            return;
                        }
                    }
                    if (action.value.integral) {//Fired from button
                        doAssignment();
                    } else {
                        if (!editedNmr.range || !editedNmr.range.length) {
                            doAssignment();
                        } else {
                            API.setVariable("editedRange", API.getVariable('editedNmr'), ["range"]);
                        }
                    }
                    API.createData("nmrParams", {
                        "nucleus": editedNmr.nucleus[0],
                        "observe": Math.floor(editedNmr.frequency / 10) * 10
                    });
                    break;
                default:
                    return false;
            }
            return true;
        }

         doAssignment() {
            var jcamp = editedNmr.getChild(['jcamp', 'data']);

            jcamp.then(function(jcamp) {
                jcamp = String(jcamp.get());
                var ppOptions = JSON.parse(JSON.stringify(API.getData("options1H")));
                var integral = ppOptions.integral;
                //console.log(ppOptions);
                if(!ppOptions.noiseFactor){
                    ppOptions = {"noiseFactor":0.8,"clean":true,"compile":true,"optimize":false,"integralFn":"sum", "type":"1H"};
                }

                var spectrum = SD.NMR.fromJcamp(jcamp);
                //spectrum.fillWith(4.7,4.9,0);
                //spectrum.fillWith(-0.1,0.1,0);
                var intFN = 0;
                if(ppOptions.integralFn=="peaks"){
                    intFN=1;
                }
                var peakPicking = spectrum.nmrPeakDetection({"nH":integral,
                    realTop:true,
                    thresholdFactor:ppOptions.noiseFactor,
                    clean:ppOptions.clean,
                    compile:ppOptions.compile,
                    optimize:ppOptions.optimize,
                    integralFn:intFN,
                    idPrefix:spectrum.getNucleus()+"",
                    gsdOptions:{minMaxRatio:0.001, smoothY:false, broadWidth:0},
                    format:"new"
                });
                editedNmr.setChildSync(['range'], peakPicking);
                API.setVariable("editedRange",API.getVariable('editedNmr'),["range"]);
            });

        }

        handleAction(action) {
            if (!action) return;

            if (handleActionSD(action)) return;

            switch (action.name) {
                case 'refresh':
                    this.roc.get(this.uuid);
                    break;
                case 'save':
                    this.roc.update(this.sample).then(function () {
                        if (typeof IframeBridge != 'undefined') {
                            IframeBridge.postMessage('tab.status', {
                                saved: true
                            });
                        }
                    });
                    break;

                case 'toggleJSMEEdition':
                    API.cache("expandableMolecule").toggleJSMEEdition();
                    break;
                case 'clearMolfile':
                    var molfile=API.getData('editableMolfile');
                    molfile.setValue('');
                    break;
                case 'swapHydrogens':
                    API.cache("expandableMolecule").setExpandedHydrogens();
                    break;
                case 'toggleNMR1hAdvancedOptions':
                    API.cache('nmr1hAdvancedOptions', ! API.cache('nmr1hAdvancedOptions'));
                case 'createOptions':
                    var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                    if (advancedOptions1H) {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                    } else {
                        API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                    }
                    break;
                case 'downloadSVG':
                    var blob = new Blob([this.action.value+""], {type: "application/jcamp-dx;charset=utf-8"});
                    fileSaver(blob, 'spectra.svg');
                    break;

                case 'deleteAttachment':
                    var attachment = action.value.name;
                    this.roc.deleteAttachment(sample, attachment).then(this.updateAttachments);
                    break;
                case 'deleteSpectra':
                    this.roc.unattach(sample, action.value).then(this.updateAttachments);
                    break;
                case 'attachNMR':
                case 'attachIR':
                case 'attachMass':
                    var type = action.name.replace("attach", "").toLowerCase();
                    var droppedDatas = data;
                    droppedDatas = droppedDatas.file || droppedDatas.str;
                    var prom = Promise.resolve();
                    for (let i = 0; i < droppedDatas.length; i++) {
                        prom = prom.then(() => {
                            var data = DataObject.resurrect(droppedDatas[i]);
                            return this.roc.attach(type, sample, data);
                        });
                    }

                    prom.then(() => {
                        this.updateAttachments(sample);
                    }).catch(() => {
                        this.updateAttachments(sample);
                    });
                    break;
                default:
                    break
            }
        }

        initializeNMRAssignment() {
            console.log(this.chemcalc);

            API.createData('nmr1hOptions', {
                "noiseFactor": 0.8,
                "clean": true,
                "compile": true,
                "optimize": false,
                "integralFn": "sum",
                "integral": 30,
                "type": "1H"
            });

            API.createData('nmr1hOndeTemplates', {
                "full": {
                    "type": "object",
                    "properties": {
                        "integral": {
                            "type": "number",
                            "title": "value to fit the spectrum integral",
                            "label": "Integral"
                        },
                        "noiseFactor": {
                            "type": "number",
                            "title": "Mutiplier of the auto-detected noise level",
                            "label": "noiseFactor"
                        },
                        "clean": {
                            "type": "boolean",
                            "title": "Delete signals with integration less than 0.5",
                            "label": "clean"
                        },
                        "compile": {
                            "type": "boolean",
                            "title": "Compile the multiplets",
                            "label": "compile"
                        },
                        "optimize": {
                            "type": "boolean",
                            "title": "Optimize the peaks to fit the spectrum",
                            "label": "optimize"
                        },
                        "integralFn": {
                            "type": "string",
                            "title": "Type of integration",
                            "label": "Integral type",
                            "enum": [
                                "sum",
                                "peaks"
                            ]
                        },
                        "type": {
                            "type": "string",
                            "title": "Nucleus",
                            "label": "Nucleus",
                            "editable": false
                        }
                    }
                },
                "short": {
                    "type": "object",
                    "properties": {
                        "integral": {
                            "type": "number",
                            "title": "value to fit the spectrum integral",
                            "label": "Integral"
                        }
                    }
                }
            }).then(function(nmr1hOndeTemplates) {
                API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
            });
        }
    }

    class ExpandableMolecule {
        constructor(sampleIn) {
            this.sample = sampleIn;
            this.molfile = this.sample.$content.general.molfile + '';
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.idCode = molecule.getIDCode();
            this.expandedHydrogens = false;
            this.jsmeEditionMode = false;
            API.createData('editableMolfile', this.molfile).then(
                (editableMolfile) => {
                    editableMolfile.onChange( (event) => {
                        // us this really a modification ? or a loop event ...
                        // need to compare former oclID with new oclID
                        var idCode = OCLE.Molecule.fromMolfile(event.target + '').getIDCode();
                        if (idCode != this.idCode) {
                            this.idCode = idCode;
                            this.molfile = event.target + '';
                            this.sample.setChildSync('$content.general.molfile', this.molfile);
                        } else {
                            console.log('no update');
                        }

                        // by default we would like the depict mode
                        this.updateMolfiles();
                        this.updateMF();
                    });
                    this.updateMolfiles();
                    this.toggleJSMEEdition(false);
                }
            );
        }

        toggleJSMEEdition(force, noDepictUpdate) {
            if (force !== undefined && force === this.jsmeEditionMode) return;
            if (force === undefined) {
                this.jsmeEditionMode = !this.jsmeEditionMode;
            } else {
                this.jsmeEditionMode = force;
            }
            var prefs = {
                "prefs": [
                    "oldlook",
                    "nozoom"
                ],
                "labelsize": "14",
                "bondwidth": "1",
                "defaultaction": "105",
                "highlightColor": "3",
                "outputResult": [
                    "yes"
                ]
            };

            if (this.jsmeEditionMode) {
                API.getData("editableMolfile").triggerChange();
                this.expandedHydrogens = false;
            } else {
                prefs.prefs.push('depict');
                if (!noDepictUpdate) {
                    this.expandedHydrogens = false;
                    API.createData("viewMolfile", this.viewMolfile);
                }

            }
            API.doAction('setJSMEPreferences', prefs)
        }

        setExpandedHydrogens(force) {
            if (force === undefined) {
                this.expandedHydrogens = !this.expandedHydrogens;
            } else {
                this.expandedHydrogens = force;
            }
            if (this.expandedHydrogens) {
                API.createData("viewMolfileExpandedH", this.viewMolfileExpandedH);
                this.toggleJSMEEdition(false, true);
            } else {
                API.createData("viewMolfile", this.viewMolfile);
            }
        }

        updateMolfiles() {
            // prevent the loop by checking actelionID
            var molecule = OCLE.Molecule.fromMolfile(this.molfile);
            this.viewMolfile = molecule.toVisualizerMolfile();

            molecule.addImplicitHydrogens();
            this.viewMolfileExpandedH = molecule.toVisualizerMolfile();
            this.mf = molecule.getMolecularFormula().formula;
            this.mw = molecule.getMolecularFormula().relativeWeight;
            this.nH = molecule.getNumberOfAtoms('H');
        }

        updateMF() {
            if (typeof UI != 'undefined')
                UI.showNotification('Updated mf and mw', 'info');
            this.sample.$content.general.molfile = this.molfile;
            this.sample.$content.general.mf = this.mf;
            this.sample.$content.general.mw = this.mw;
        }
    }

    return Sample;
});

<|endoftext|>


<commit_before>import * as ActionTypes from '../constants/ActionTypes';
import remove from 'lodash.remove';

const initialState = [];

const updateImageInState = (state, id, changes) => {
  const target = remove(state, { id })[0];
  return [...state, { ...target, ...changes }];
};

const actionsMap = {
  [ActionTypes.ADD_IMAGE](state, { image }) {
    return [...state, image];
  },
  [ActionTypes.SELECT_IMAGE](state, { id }) {
    return updateImageInState(state, id, { isSelected: true })
  },
  [ActionTypes.DESELECT_IMAGE](state, { id }) {
    return updateImageInState(state, id, { isSelected: false })
  }
};

export default function images(state = initialState, action) {
  const reduceFn = actionsMap[action.type];
  if (!reduceFn) return state;
  return reduceFn(state, action);
}
<commit_msg>Rename merge method<commit_after>import * as ActionTypes from '../constants/ActionTypes';
import remove from 'lodash.remove';

const initialState = [];

// Modify an image in the state, merging in changes
const merge = (state, id, changes) => {
  const target = remove(state, { id })[0];
  return [...state, { ...target, ...changes }];
};

const actionsMap = {
  [ActionTypes.ADD_IMAGE](state, { image }) {
    return [...state, image];
  },
  [ActionTypes.SELECT_IMAGE](state, { id }) {
    return merge(state, id, { isSelected: true })
  },
  [ActionTypes.DESELECT_IMAGE](state, { id }) {
    return merge(state, id, { isSelected: false })
  }
};

export default function images(state = initialState, action) {
  const reduceFn = actionsMap[action.type];
  if (!reduceFn) return state;
  return reduceFn(state, action);
}
<|endoftext|>


<commit_before>'use strict';

const Command = require('../../models/Command.js');
const NewsEmbed = require('../../embeds/NewsEmbed.js');

/**
 * Displays the currently active warframe news
 */
class News extends Command {
  /**
   * Constructs a callable command
   * @param {Genesis} bot  The bot object
   */
  constructor(bot) {
    super(bot, 'warframe.worldstate.news', 'news', 'Display the currently active news');
    this.regex = new RegExp(`^${this.call}(?:\\s+on\\s+([pcsxb14]{2,3}))?$`, 'i');
  }

  async run(message) {
    const platformParam = message.strippedContent.match(this.regex)[1];
    const platform = platformParam || await this.settings.getChannelSetting(message.channel, 'platform');
    const language = await this.settings.getChannelSetting(message.channel, 'language');
    const ws = await this.bot.worldStates[platform.toLowerCase()].getData();
    const news = ws.news.filter(n => !n.update && !n.primeAccess && n.translations[language]);
    await this.messageManager.embed(
      message,
      new NewsEmbed(this.bot, news, undefined, platform), true, false,
    );
    return this.messageManager.statuses.SUCCESS;
  }
}

module.exports = News;
<commit_msg>use context<commit_after>'use strict';

const Command = require('../../models/Command.js');
const NewsEmbed = require('../../embeds/NewsEmbed.js');

/**
 * Displays the currently active warframe news
 */
class News extends Command {
  /**
   * Constructs a callable command
   * @param {Genesis} bot  The bot object
   */
  constructor(bot) {
    super(bot, 'warframe.worldstate.news', 'news', 'Display the currently active news');
    this.regex = new RegExp(`^${this.call}(?:\\s+on\\s+([pcsxb14]{2,3}))?$`, 'i');
  }

  async run(message, ctx) {
    const platformParam = message.strippedContent.match(this.regex)[1];
    const platform = platformParam ||ctx.platform;
    const language = await this.settings.getChannelSetting(message.channel, 'language');
    const ws = await this.bot.worldStates[platform.toLowerCase()].getData();
    const news = ws.news.filter(n => !n.update && !n.primeAccess && n.translations[language]);
    await this.messageManager.embed(
      message,
      new NewsEmbed(this.bot, news, undefined, platform), true, false,
    );
    return this.messageManager.statuses.SUCCESS;
  }
}

module.exports = News;
<|endoftext|>