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

function SecureDOMEvent(event, key) {
    "use strict";

    var o = Object.create(null, {
        toString: {
            value: function() {
                return "SecureDOMEvent: " + event + "{ key: " + JSON.stringify(key) + " }";
            }
        }
    });

    var DOMEventSecureDescriptors = {
        // Events properties that are DOM Elements were compiled from
        // https://developer.mozilla.org/en-US/docs/Web/Events
        target: SecureObject.createFilteredProperty(o, event, "target"),
        currentTarget: SecureObject.createFilteredProperty(o, event, "currentTarget"),

        initEvent: SecureObject.createFilteredMethod(o, event, "initEvent"),

        // Touch Events are special on their own:
        // https://developer.mozilla.org/en-US/docs/Web/API/Touch
        touches: SecureDOMEvent.filterTouchesDescriptor(o, event, "touch"),
        targetTouches: SecureDOMEvent.filterTouchesDescriptor(o, event, "targetTouches"),
        changedTouches: SecureDOMEvent.filterTouchesDescriptor(o, event, "changedTouches"),

        view: {
            get: function() {
            	var swin = $A.lockerService.getEnvForSecureObject(o);
            	var win = getLockerSecret(swin, "ref");
                return win === event.view ? swin : undefined;
            }
        }
    };

    // non-standard properties and aliases
    ["relatedTarget", "srcElement", "explicitOriginalTarget", "originalTarget"].forEach(function(property) {
    	SecureObject.addPropertyIfSupported(o, event, property);
    });

    // re-exposing externals
    // TODO: we might need to include non-enumerables
    for (var name in event) {
        if (!(name in o)) {
            // every DOM event has a different shape, we apply filters when possible,
            // and bypass when no secure filter is found.
            Object.defineProperty(o, name, DOMEventSecureDescriptors[name] || SecureObject.createFilteredProperty(o, event, name));
        }
    }

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

    return o;
}

SecureDOMEvent.filterTouchesDescriptor = function (se, event, propName) {
    "use strict";

    // descriptor to produce a new collection of touches where the target of each
    // touch is a secure element
    return {
        get: function() {
            // perf hard-wired in case there is not a touches to wrap
            var touches = event[propName];
            if (!touches) {
                return touches;
            }
            return touches.map(function(touch) {
                // touches is normally a big big collection of touch objects,
                // we do not want to pre-process them all, just create a the getters
                // and process the accessor on the spot. e.g.:
                // https://developer.mozilla.org/en-US/docs/Web/Events/touchstart
                return Object.keys(touch).reduce(function(o, p) {
                    Object.defineProperty(o, p, {
                        // all props in a touch object are readonly by spec:
                        // https://developer.mozilla.org/en-US/docs/Web/API/Touch
                        get: function() {
                            return SecureObject.filterEverything(se, touch[p]);
                        }
                    });
                }, {});
            });
        }
    };
};
<commit_msg>Fix ToucheList does not implement "map" @bug W-3212661@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function SecureDOMEvent(event, key) {
    "use strict";

    var o = Object.create(null, {
        toString: {
            value: function() {
                return "SecureDOMEvent: " + event + "{ key: " + JSON.stringify(key) + " }";
            }
        }
    });

    var DOMEventSecureDescriptors = {
        // Events properties that are DOM Elements were compiled from
        // https://developer.mozilla.org/en-US/docs/Web/Events
        target: SecureObject.createFilteredProperty(o, event, "target"),
        currentTarget: SecureObject.createFilteredProperty(o, event, "currentTarget"),

        initEvent: SecureObject.createFilteredMethod(o, event, "initEvent"),

        // Touch Events are special on their own:
        // https://developer.mozilla.org/en-US/docs/Web/API/Touch
        touches: SecureDOMEvent.filterTouchesDescriptor(o, event, "touch"),
        targetTouches: SecureDOMEvent.filterTouchesDescriptor(o, event, "targetTouches"),
        changedTouches: SecureDOMEvent.filterTouchesDescriptor(o, event, "changedTouches"),

        view: {
            get: function() {
            	var swin = $A.lockerService.getEnvForSecureObject(o);
            	var win = getLockerSecret(swin, "ref");
                return win === event.view ? swin : undefined;
            }
        }
    };

    // non-standard properties and aliases
    ["relatedTarget", "srcElement", "explicitOriginalTarget", "originalTarget"].forEach(function(property) {
    	SecureObject.addPropertyIfSupported(o, event, property);
    });

    // re-exposing externals
    // TODO: we might need to include non-enumerables
    for (var name in event) {
        if (!(name in o)) {
            // every DOM event has a different shape, we apply filters when possible,
            // and bypass when no secure filter is found.
            Object.defineProperty(o, name, DOMEventSecureDescriptors[name] || SecureObject.createFilteredProperty(o, event, name));
        }
    }

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

    return o;
}

SecureDOMEvent.filterTouchesDescriptor = function (se, event, propName) {
    "use strict";

    // descriptor to produce a new collection of touches where the target of each
    // touch is a secure element
    return {
        get: function() {
            // perf hard-wired in case there is not a touches to wrap
            var touches = event[propName];
            if (!touches) {
                return touches;
            }
            // touches, of type ToucheList does not implement "map"
            return Array.prototype.map.call(touches, function(touch) {
                // touches is normally a big big collection of touch objects,
                // we do not want to pre-process them all, just create a the getters
                // and process the accessor on the spot. e.g.:
                // https://developer.mozilla.org/en-US/docs/Web/Events/touchstart
                return Object.keys(touch).reduce(function(o, p) {
                    Object.defineProperty(o, p, {
                        // all props in a touch object are readonly by spec:
                        // https://developer.mozilla.org/en-US/docs/Web/API/Touch
                        get: function() {
                            return SecureObject.filterEverything(se, touch[p]);
                        }
                    });
                }, {});
            });
        }
    };
};
<|endoftext|>


<commit_before>const throttle = require('lodash.throttle')
const classNames = require('classnames')
const statusBarStates = require('./StatusBarStates')
const { h } = require('preact')

function calculateProcessingProgress (files) {
  // Collect pre or postprocessing progress states.
  const progresses = []
  Object.keys(files).forEach((fileID) => {
    const { progress } = files[fileID]
    if (progress.preprocess) {
      progresses.push(progress.preprocess)
    }
    if (progress.postprocess) {
      progresses.push(progress.postprocess)
    }
  })

  // In the future we should probably do this differently. For now we'll take the
  // mode and message from the first file…
  const { mode, message } = progresses[0]
  const value = progresses.filter(isDeterminate).reduce((total, progress, index, all) => {
    return total + progress.value / all.length
  }, 0)
  function isDeterminate (progress) {
    return progress.mode === 'determinate'
  }

  return {
    mode,
    message,
    value
  }
}

function togglePauseResume (props) {
  if (props.isAllComplete) return

  if (!props.resumableUploads) {
    return props.cancelAll()
  }

  if (props.isAllPaused) {
    return props.resumeAll()
  }

  return props.pauseAll()
}

module.exports = (props) => {
  props = props || {}

  const uploadState = props.uploadState

  let progressValue = props.totalProgress
  let progressMode
  let progressBarContent

  if (uploadState === statusBarStates.STATE_PREPROCESSING || uploadState === statusBarStates.STATE_POSTPROCESSING) {
    const progress = calculateProcessingProgress(props.files)
    progressMode = progress.mode
    if (progressMode === 'determinate') {
      progressValue = progress.value * 100
    }

    progressBarContent = ProgressBarProcessing(progress)
  } else if (uploadState === statusBarStates.STATE_COMPLETE) {
    progressBarContent = ProgressBarComplete(props)
  } else if (uploadState === statusBarStates.STATE_UPLOADING) {
    progressBarContent = ProgressBarUploading(props)
  } else if (uploadState === statusBarStates.STATE_ERROR) {
    progressValue = undefined
    progressBarContent = ProgressBarError(props)
  }

  const width = typeof progressValue === 'number' ? progressValue : 100
  const isHidden = (uploadState === statusBarStates.STATE_WAITING && props.hideUploadButton) ||
    (uploadState === statusBarStates.STATE_WAITING && !props.newFiles > 0) ||
    (uploadState === statusBarStates.STATE_COMPLETE && props.hideAfterFinish)

  const progressClassNames = `uppy-StatusBar-progress
                           ${progressMode ? 'is-' + progressMode : ''}`

  const statusBarClassNames = classNames(
    { 'uppy-Root': props.isTargetDOMEl },
    'uppy-StatusBar',
    `is-${uploadState}`,
    { 'uppy-StatusBar--detailedProgress': props.showProgressDetails }
  )

  return (

      {progressBarContent}

        { props.newFiles && !props.hideUploadButton ? <UploadBtn {...props} uploadState={uploadState} /> : null }
        { props.error && !props.hideRetryButton ? <RetryBtn {...props} /> : null }
        { !props.hidePauseResumeCancelButtons && uploadState !== statusBarStates.STATE_WAITING && uploadState !== statusBarStates.STATE_COMPLETE
          ? <CancelBtn {...props} />
          : null
        }

  )
}

const UploadBtn = (props) => {
  const uploadBtnClassNames = classNames(
    'uppy-u-reset',
    'uppy-c-btn',
    'uppy-StatusBar-actionBtn',
    'uppy-StatusBar-actionBtn--upload',
    { 'uppy-c-btn-primary': props.uploadState === statusBarStates.STATE_WAITING }
  )

  return <button type="button"
    class={uploadBtnClassNames}
    aria-label={props.i18n('uploadXFiles', { smart_count: props.newFiles })}
    onclick={props.startUpload}>
    {props.newFiles && props.uploadStarted
      ? props.i18n('uploadXNewFiles', { smart_count: props.newFiles })
      : props.i18n('uploadXFiles', { smart_count: props.newFiles })
    }
  </button>
}

const RetryBtn = (props) => {
  return <button type="button"
    class="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--retry"
    aria-label={props.i18n('retryUpload')}
    onclick={props.retryAll}>{props.i18n('retry')}</button>
}

const CancelBtn = (props) => {
  return <button type="button"
    class="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--cancel"
    aria-label={props.i18n('cancel')}
    onclick={props.cancelAll}>{props.i18n('cancel')}</button>
}

const PauseResumeButtons = (props) => {
  const { resumableUploads, isAllPaused, i18n } = props
  const title = resumableUploads
                ? isAllPaused
                  ? i18n('resumeUpload')
                  : i18n('pauseUpload')
                : i18n('cancelUpload')

  return <button title={title} class="uppy-u-reset uppy-StatusBar-statusIndicator" type="button" onclick={() => togglePauseResume(props)}>
    {resumableUploads
      ? isAllPaused
        ? <svg aria-hidden="true" class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
          <path d="M1.26 12.534a.67.67 0 0 1-.674.012.67.67 0 0 1-.336-.583v-11C.25.724.38.5.586.382a.658.658 0 0 1 .673.012l9.165 5.5a.66.66 0 0 1 .325.57.66.66 0 0 1-.325.573l-9.166 5.5z" />
        </svg>
        : <svg aria-hidden="true" class="UppyIcon" width="16" height="17" viewBox="0 0 12 13">
          <path d="M4.888.81v11.38c0 .446-.324.81-.722.81H2.722C2.324 13 2 12.636 2 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81zM9.888.81v11.38c0 .446-.324.81-.722.81H7.722C7.324 13 7 12.636 7 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81z" />
        </svg>
      : <svg aria-hidden="true" class="UppyIcon" width="16px" height="16px" viewBox="0 0 19 19">
        <path d="M17.318 17.232L9.94 9.854 9.586 9.5l-.354.354-7.378 7.378h.707l-.62-.62v.706L9.318 9.94l.354-.354-.354-.354L1.94 1.854v.707l.62-.62h-.706l7.378 7.378.354.354.354-.354 7.378-7.378h-.707l.622.62v-.706L9.854 9.232l-.354.354.354.354 7.378 7.378.708-.707-7.38-7.378v.708l7.38-7.38.353-.353-.353-.353-.622-.622-.353-.353-.354.352-7.378 7.38h.708L2.56 1.23 2.208.88l-.353.353-.622.62-.353.355.352.353 7.38 7.38v-.708l-7.38 7.38-.353.353.352.353.622.622.353.353.354-.353 7.38-7.38h-.708l7.38 7.38z" />
      </svg>
    }
  </button>
}

const ProgressBarProcessing = (props) => {
  const value = Math.round(props.value * 100)

  return

    {props.mode === 'determinate' ? `${value}% \u00B7 ` : ''}
    {props.message}

}

const ProgressDetails = (props) => {
  return

    { props.numUploads > 1 && props.i18n('filesUploadedOfTotal', { complete: props.complete, smart_count: props.numUploads }) + ' \u00B7 ' }
    { props.i18n('dataUploadedOfTotal', { complete: props.totalUploadedSize, total: props.totalSize }) + ' \u00B7 ' }
    { props.i18n('xTimeLeft', { time: props.totalETA }) }

}

const ThrottledProgressDetails = throttle(ProgressDetails, 500, { leading: true, trailing: true })

const ProgressBarUploading = (props) => {
  if (!props.isUploadStarted || props.isAllComplete) {
    return null
  }

  const title = props.isAllPaused ? props.i18n('paused') : props.i18n('uploading')

  return (

      { !props.hidePauseResumeCancelButtons && <PauseResumeButtons {...props} /> }

{title}: {props.totalProgress}%

        { !props.isAllPaused && <ThrottledProgressDetails {...props} /> }

  )
}

const ProgressBarComplete = ({ totalProgress, i18n }) => {
  return (

      <svg aria-hidden="true" class="uppy-StatusBar-statusIndicator UppyIcon" width="18" height="17" viewBox="0 0 23 17">
        <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
      </svg>
      {i18n('complete')}

  )
}

const ProgressBarError = ({ error, retryAll, hideRetryButton, i18n }) => {
  return (

      {i18n('uploadFailed')}.
      { !hideRetryButton && {i18n('pleasePressRetry')} }
      ?

  )
}
<commit_msg>status-bar: Hide only the upload button when no new uploads are allowed<commit_after>const throttle = require('lodash.throttle')
const classNames = require('classnames')
const statusBarStates = require('./StatusBarStates')
const { h } = require('preact')

function calculateProcessingProgress (files) {
  // Collect pre or postprocessing progress states.
  const progresses = []
  Object.keys(files).forEach((fileID) => {
    const { progress } = files[fileID]
    if (progress.preprocess) {
      progresses.push(progress.preprocess)
    }
    if (progress.postprocess) {
      progresses.push(progress.postprocess)
    }
  })

  // In the future we should probably do this differently. For now we'll take the
  // mode and message from the first file…
  const { mode, message } = progresses[0]
  const value = progresses.filter(isDeterminate).reduce((total, progress, index, all) => {
    return total + progress.value / all.length
  }, 0)
  function isDeterminate (progress) {
    return progress.mode === 'determinate'
  }

  return {
    mode,
    message,
    value
  }
}

function togglePauseResume (props) {
  if (props.isAllComplete) return

  if (!props.resumableUploads) {
    return props.cancelAll()
  }

  if (props.isAllPaused) {
    return props.resumeAll()
  }

  return props.pauseAll()
}

module.exports = (props) => {
  props = props || {}

  const uploadState = props.uploadState

  let progressValue = props.totalProgress
  let progressMode
  let progressBarContent

  if (uploadState === statusBarStates.STATE_PREPROCESSING || uploadState === statusBarStates.STATE_POSTPROCESSING) {
    const progress = calculateProcessingProgress(props.files)
    progressMode = progress.mode
    if (progressMode === 'determinate') {
      progressValue = progress.value * 100
    }

    progressBarContent = ProgressBarProcessing(progress)
  } else if (uploadState === statusBarStates.STATE_COMPLETE) {
    progressBarContent = ProgressBarComplete(props)
  } else if (uploadState === statusBarStates.STATE_UPLOADING) {
    progressBarContent = ProgressBarUploading(props)
  } else if (uploadState === statusBarStates.STATE_ERROR) {
    progressValue = undefined
    progressBarContent = ProgressBarError(props)
  }

  const width = typeof progressValue === 'number' ? progressValue : 100
  const isHidden = (uploadState === statusBarStates.STATE_WAITING && props.hideUploadButton) ||
    (uploadState === statusBarStates.STATE_WAITING && !props.newFiles > 0) ||
    (uploadState === statusBarStates.STATE_COMPLETE && props.hideAfterFinish)

  const showUploadButton = props.newFiles && !props.hideUploadButton && props.allowNewUpload
  const showRetryButton = props.error && !props.hideRetryButton
  const showCancelButton = !props.hidePauseResumeCancelButtons &&
    uploadState !== statusBarStates.STATE_WAITING &&
    uploadState !== statusBarStates.STATE_COMPLETE

  const progressClassNames = `uppy-StatusBar-progress
                           ${progressMode ? 'is-' + progressMode : ''}`

  const statusBarClassNames = classNames(
    { 'uppy-Root': props.isTargetDOMEl },
    'uppy-StatusBar',
    `is-${uploadState}`,
    { 'uppy-StatusBar--detailedProgress': props.showProgressDetails }
  )

  return (

      {progressBarContent}

        { showUploadButton ? <UploadBtn {...props} uploadState={uploadState} /> : null }
        { showRetryButton ? <RetryBtn {...props} /> : null }
        { showCancelButton ? <CancelBtn {...props} /> : null }

  )
}

const UploadBtn = (props) => {
  const uploadBtnClassNames = classNames(
    'uppy-u-reset',
    'uppy-c-btn',
    'uppy-StatusBar-actionBtn',
    'uppy-StatusBar-actionBtn--upload',
    { 'uppy-c-btn-primary': props.uploadState === statusBarStates.STATE_WAITING }
  )

  return <button type="button"
    class={uploadBtnClassNames}
    aria-label={props.i18n('uploadXFiles', { smart_count: props.newFiles })}
    onclick={props.startUpload}>
    {props.newFiles && props.uploadStarted
      ? props.i18n('uploadXNewFiles', { smart_count: props.newFiles })
      : props.i18n('uploadXFiles', { smart_count: props.newFiles })
    }
  </button>
}

const RetryBtn = (props) => {
  return <button type="button"
    class="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--retry"
    aria-label={props.i18n('retryUpload')}
    onclick={props.retryAll}>{props.i18n('retry')}</button>
}

const CancelBtn = (props) => {
  return <button type="button"
    class="uppy-u-reset uppy-c-btn uppy-StatusBar-actionBtn uppy-StatusBar-actionBtn--cancel"
    aria-label={props.i18n('cancel')}
    onclick={props.cancelAll}>{props.i18n('cancel')}</button>
}

const PauseResumeButtons = (props) => {
  const { resumableUploads, isAllPaused, i18n } = props
  const title = resumableUploads
                ? isAllPaused
                  ? i18n('resumeUpload')
                  : i18n('pauseUpload')
                : i18n('cancelUpload')

  return <button title={title} class="uppy-u-reset uppy-StatusBar-statusIndicator" type="button" onclick={() => togglePauseResume(props)}>
    {resumableUploads
      ? isAllPaused
        ? <svg aria-hidden="true" class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
          <path d="M1.26 12.534a.67.67 0 0 1-.674.012.67.67 0 0 1-.336-.583v-11C.25.724.38.5.586.382a.658.658 0 0 1 .673.012l9.165 5.5a.66.66 0 0 1 .325.57.66.66 0 0 1-.325.573l-9.166 5.5z" />
        </svg>
        : <svg aria-hidden="true" class="UppyIcon" width="16" height="17" viewBox="0 0 12 13">
          <path d="M4.888.81v11.38c0 .446-.324.81-.722.81H2.722C2.324 13 2 12.636 2 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81zM9.888.81v11.38c0 .446-.324.81-.722.81H7.722C7.324 13 7 12.636 7 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81z" />
        </svg>
      : <svg aria-hidden="true" class="UppyIcon" width="16px" height="16px" viewBox="0 0 19 19">
        <path d="M17.318 17.232L9.94 9.854 9.586 9.5l-.354.354-7.378 7.378h.707l-.62-.62v.706L9.318 9.94l.354-.354-.354-.354L1.94 1.854v.707l.62-.62h-.706l7.378 7.378.354.354.354-.354 7.378-7.378h-.707l.622.62v-.706L9.854 9.232l-.354.354.354.354 7.378 7.378.708-.707-7.38-7.378v.708l7.38-7.38.353-.353-.353-.353-.622-.622-.353-.353-.354.352-7.378 7.38h.708L2.56 1.23 2.208.88l-.353.353-.622.62-.353.355.352.353 7.38 7.38v-.708l-7.38 7.38-.353.353.352.353.622.622.353.353.354-.353 7.38-7.38h-.708l7.38 7.38z" />
      </svg>
    }
  </button>
}

const ProgressBarProcessing = (props) => {
  const value = Math.round(props.value * 100)

  return

    {props.mode === 'determinate' ? `${value}% \u00B7 ` : ''}
    {props.message}

}

const ProgressDetails = (props) => {
  return

    { props.numUploads > 1 && props.i18n('filesUploadedOfTotal', { complete: props.complete, smart_count: props.numUploads }) + ' \u00B7 ' }
    { props.i18n('dataUploadedOfTotal', { complete: props.totalUploadedSize, total: props.totalSize }) + ' \u00B7 ' }
    { props.i18n('xTimeLeft', { time: props.totalETA }) }

}

const ThrottledProgressDetails = throttle(ProgressDetails, 500, { leading: true, trailing: true })

const ProgressBarUploading = (props) => {
  if (!props.isUploadStarted || props.isAllComplete) {
    return null
  }

  const title = props.isAllPaused ? props.i18n('paused') : props.i18n('uploading')

  return (

      { !props.hidePauseResumeCancelButtons && <PauseResumeButtons {...props} /> }

{title}: {props.totalProgress}%

        { !props.isAllPaused && <ThrottledProgressDetails {...props} /> }

  )
}

const ProgressBarComplete = ({ totalProgress, i18n }) => {
  return (

      <svg aria-hidden="true" class="uppy-StatusBar-statusIndicator UppyIcon" width="18" height="17" viewBox="0 0 23 17">
        <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
      </svg>
      {i18n('complete')}

  )
}

const ProgressBarError = ({ error, retryAll, hideRetryButton, i18n }) => {
  return (

      {i18n('uploadFailed')}.
      { !hideRetryButton && {i18n('pleasePressRetry')} }
      ?

  )
}
<|endoftext|>


<commit_before>const Transform = require('readable-stream').Transform;
const TYPE = require('./token').TYPE;

const tokenParsers = {};
tokenParsers[TYPE.COLMETADATA] = require('./colmetadata-token-parser');
tokenParsers[TYPE.DONE] = require('./done-token-parser').doneParser;
tokenParsers[TYPE.DONEINPROC] = require('./done-token-parser').doneInProcParser;
tokenParsers[TYPE.DONEPROC] = require('./done-token-parser').doneProcParser;
tokenParsers[TYPE.ENVCHANGE] = require('./env-change-token-parser');
tokenParsers[TYPE.ERROR] = require('./infoerror-token-parser').errorParser;
tokenParsers[TYPE.FEDAUTHINFO] = require('./fedauth-info-parser');
tokenParsers[TYPE.FEATUREEXTACK] = require('./feature-ext-ack-parser');
tokenParsers[TYPE.INFO] = require('./infoerror-token-parser').infoParser;
tokenParsers[TYPE.LOGINACK] = require('./loginack-token-parser');
tokenParsers[TYPE.ORDER] = require('./order-token-parser');
tokenParsers[TYPE.RETURNSTATUS] = require('./returnstatus-token-parser');
tokenParsers[TYPE.RETURNVALUE] = require('./returnvalue-token-parser');
tokenParsers[TYPE.ROW] = require('./row-token-parser');
tokenParsers[TYPE.NBCROW] = require('./nbcrow-token-parser');
tokenParsers[TYPE.SSPI] = require('./sspi-token-parser');

module.exports = class Parser extends Transform {
  constructor(debug, colMetadata, options) {
    super({ objectMode: true });

    this.debug = debug;
    this.colMetadata = colMetadata;
    this.options = options;
    this.endOfMessageMarker = {};

    this.buffer = Buffer.alloc(0);
    this.position = 0;
    this.suspended = false;
    this.await = undefined;
    this.next = undefined;
  }

  _transform(input, encoding, done) {
    if (input === this.endOfMessageMarker) {
      done(null, { // generate endOfMessage pseudo token
        name: 'EOM',
        event: 'endOfMessage'
      });
      return;
    }
    if (this.position === this.buffer.length) {
      this.buffer = input;
    } else {
      this.buffer = Buffer.concat([this.buffer.slice(this.position), input]);
    }
    this.position = 0;

    // This will be called once we need to wait for more data to
    // become available
    this.await = done;

    if (this.suspended) {
      // Unsuspend and continue from where ever we left off.
      this.suspended = false;
      this.next.call(null);
    }

    // If we're no longer suspended, parse new tokens
    if (!this.suspended) {
      // Start the parser
      this.parseTokens();
    }
  }

  parseTokens() {
    const doneParsing = (token) => {
      if (token) {
        switch (token.name) {
          case 'COLMETADATA':
            this.colMetadata = token.columns;
        }

        this.push(token);
      }
    };

    while (!this.suspended && this.position + 1 <= this.buffer.length) {
      const type = this.buffer.readUInt8(this.position);

      this.position += 1;

      if (tokenParsers[type]) {
        tokenParsers[type](this, this.colMetadata, this.options, doneParsing);
      } else {
        this.emit('error', new Error('Unknown type: ' + type));
      }
    }

    if (!this.suspended && this.position === this.buffer.length) {
      // If we reached the end of the buffer, we can stop parsing now.
      return this.await.call(null);
    }
  }

  suspend(next) {
    this.suspended = true;
    this.next = next;
    this.await.call(null);
  }

  awaitData(length, callback) {
    if (this.position + length <= this.buffer.length) {
      callback();
    } else {
      this.suspend(() => {
        this.awaitData(length, callback);
      });
    }
  }

  readInt8(callback) {
    this.awaitData(1, () => {
      const data = this.buffer.readInt8(this.position);
      this.position += 1;
      callback(data);
    });
  }

  readUInt8(callback) {
    this.awaitData(1, () => {
      const data = this.buffer.readUInt8(this.position);
      this.position += 1;
      callback(data);
    });
  }

  readInt16LE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readInt16LE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readInt16BE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readInt16BE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readUInt16LE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readUInt16LE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readUInt16BE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readUInt16BE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readInt32LE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readInt32LE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readInt32BE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readInt32BE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readUInt32LE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readUInt32LE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readUInt32BE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readUInt32BE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readInt64LE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readInt32LE(this.position + 4) + (this.buffer[this.position + 4] & 0x80 === 0x80 ? 1 : -1) * this.buffer.readUInt32LE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readInt64BE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readInt32BE(this.position) + (this.buffer[this.position] & 0x80 === 0x80 ? 1 : -1) * this.buffer.readUInt32BE(this.position + 4);
      this.position += 8;
      callback(data);
    });
  }

  readUInt64LE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readUInt32LE(this.position + 4) + this.buffer.readUInt32LE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readUInt64BE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readUInt32BE(this.position) + this.buffer.readUInt32BE(this.position + 4);
      this.position += 8;
      callback(data);
    });
  }

  readFloatLE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readFloatLE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readFloatBE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readFloatBE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readDoubleLE(callback) {
    this.awaitData(8, () => {
      const data = this.buffer.readDoubleLE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readDoubleBE(callback) {
    this.awaitData(8, () => {
      const data = this.buffer.readDoubleBE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readUInt24LE(callback) {
    this.awaitData(3, () => {
      const low = this.buffer.readUInt16LE(this.position);
      const high = this.buffer.readUInt8(this.position + 2);

      this.position += 3;

      callback(low | (high << 16));
    });
  }

  readUInt40LE(callback) {
    this.awaitData(5, () => {
      const low = this.buffer.readUInt32LE(this.position);
      const high = this.buffer.readUInt8(this.position + 4);

      this.position += 5;

      callback((0x100000000 * high) + low);
    });
  }

  readUNumeric64LE(callback) {
    this.awaitData(8, () => {
      const low = this.buffer.readUInt32LE(this.position);
      const high = this.buffer.readUInt32LE(this.position + 4);

      this.position += 8;

      callback((0x100000000 * high) + low);
    });
  }

  readUNumeric96LE(callback) {
    this.awaitData(12, () => {
      const dword1 = this.buffer.readUInt32LE(this.position);
      const dword2 = this.buffer.readUInt32LE(this.position + 4);
      const dword3 = this.buffer.readUInt32LE(this.position + 8);

      this.position += 12;

      callback(dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3));
    });
  }

  readUNumeric128LE(callback) {
    this.awaitData(16, () => {
      const dword1 = this.buffer.readUInt32LE(this.position);
      const dword2 = this.buffer.readUInt32LE(this.position + 4);
      const dword3 = this.buffer.readUInt32LE(this.position + 8);
      const dword4 = this.buffer.readUInt32LE(this.position + 12);

      this.position += 16;

      callback(dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3) + (0x100000000 * 0x100000000 * 0x100000000 * dword4));
    });
  }

  // Variable length data

  readBuffer(length, callback) {
    this.awaitData(length, () => {
      const data = this.buffer.slice(this.position, this.position + length);
      this.position += length;
      callback(data);
    });
  }

  // Read a Unicode String (BVARCHAR)
  readBVarChar(callback) {
    this.readUInt8((length) => {
      this.readBuffer(length * 2, (data) => {
        callback(data.toString('ucs2'));
      });
    });
  }

  // Read a Unicode String (USVARCHAR)
  readUsVarChar(callback) {
    this.readUInt16LE((length) => {
      this.readBuffer(length * 2, (data) => {
        callback(data.toString('ucs2'));
      });
    });
  }

  // Read binary data (BVARBYTE)
  readBVarByte(callback) {
    this.readUInt8((length) => {
      this.readBuffer(length, callback);
    });
  }

  // Read binary data (USVARBYTE)
  readUsVarByte(callback) {
    this.readUInt16LE((length) => {
      this.readBuffer(length, callback);
    });
  }
};
<commit_msg>fix: correct callback of token stream parser transform<commit_after>const Transform = require('readable-stream').Transform;
const TYPE = require('./token').TYPE;

const tokenParsers = {};
tokenParsers[TYPE.COLMETADATA] = require('./colmetadata-token-parser');
tokenParsers[TYPE.DONE] = require('./done-token-parser').doneParser;
tokenParsers[TYPE.DONEINPROC] = require('./done-token-parser').doneInProcParser;
tokenParsers[TYPE.DONEPROC] = require('./done-token-parser').doneProcParser;
tokenParsers[TYPE.ENVCHANGE] = require('./env-change-token-parser');
tokenParsers[TYPE.ERROR] = require('./infoerror-token-parser').errorParser;
tokenParsers[TYPE.FEDAUTHINFO] = require('./fedauth-info-parser');
tokenParsers[TYPE.FEATUREEXTACK] = require('./feature-ext-ack-parser');
tokenParsers[TYPE.INFO] = require('./infoerror-token-parser').infoParser;
tokenParsers[TYPE.LOGINACK] = require('./loginack-token-parser');
tokenParsers[TYPE.ORDER] = require('./order-token-parser');
tokenParsers[TYPE.RETURNSTATUS] = require('./returnstatus-token-parser');
tokenParsers[TYPE.RETURNVALUE] = require('./returnvalue-token-parser');
tokenParsers[TYPE.ROW] = require('./row-token-parser');
tokenParsers[TYPE.NBCROW] = require('./nbcrow-token-parser');
tokenParsers[TYPE.SSPI] = require('./sspi-token-parser');

module.exports = class Parser extends Transform {
  constructor(debug, colMetadata, options) {
    super({ objectMode: true });

    this.debug = debug;
    this.colMetadata = colMetadata;
    this.options = options;
    this.endOfMessageMarker = {};

    this.buffer = Buffer.alloc(0);
    this.position = 0;
    this.suspended = false;
    this.next = undefined;
  }

  _transform(input, encoding, done) {
    if (input === this.endOfMessageMarker) {
      done(null, { // generate endOfMessage pseudo token
        name: 'EOM',
        event: 'endOfMessage'
      });
      return;
    }
    if (this.position === this.buffer.length) {
      this.buffer = input;
    } else {
      this.buffer = Buffer.concat([this.buffer.slice(this.position), input]);
    }
    this.position = 0;

    if (this.suspended) {
      // Unsuspend and continue from where ever we left off.
      this.suspended = false;
      this.next.call(null);
    }

    // If we're no longer suspended, parse new tokens
    if (!this.suspended) {
      // Start the parser
      this.parseTokens();
    }

    done();
  }

  parseTokens() {
    const doneParsing = (token) => {
      if (token) {
        switch (token.name) {
          case 'COLMETADATA':
            this.colMetadata = token.columns;
        }

        this.push(token);
      }
    };

    while (!this.suspended && this.position + 1 <= this.buffer.length) {
      const type = this.buffer.readUInt8(this.position);

      this.position += 1;

      if (tokenParsers[type]) {
        tokenParsers[type](this, this.colMetadata, this.options, doneParsing);
      } else {
        this.emit('error', new Error('Unknown type: ' + type));
      }
    }
  }

  suspend(next) {
    this.suspended = true;
    this.next = next;
  }

  awaitData(length, callback) {
    if (this.position + length <= this.buffer.length) {
      callback();
    } else {
      this.suspend(() => {
        this.awaitData(length, callback);
      });
    }
  }

  readInt8(callback) {
    this.awaitData(1, () => {
      const data = this.buffer.readInt8(this.position);
      this.position += 1;
      callback(data);
    });
  }

  readUInt8(callback) {
    this.awaitData(1, () => {
      const data = this.buffer.readUInt8(this.position);
      this.position += 1;
      callback(data);
    });
  }

  readInt16LE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readInt16LE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readInt16BE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readInt16BE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readUInt16LE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readUInt16LE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readUInt16BE(callback) {
    this.awaitData(2, () => {
      const data = this.buffer.readUInt16BE(this.position);
      this.position += 2;
      callback(data);
    });
  }

  readInt32LE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readInt32LE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readInt32BE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readInt32BE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readUInt32LE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readUInt32LE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readUInt32BE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readUInt32BE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readInt64LE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readInt32LE(this.position + 4) + (this.buffer[this.position + 4] & 0x80 === 0x80 ? 1 : -1) * this.buffer.readUInt32LE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readInt64BE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readInt32BE(this.position) + (this.buffer[this.position] & 0x80 === 0x80 ? 1 : -1) * this.buffer.readUInt32BE(this.position + 4);
      this.position += 8;
      callback(data);
    });
  }

  readUInt64LE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readUInt32LE(this.position + 4) + this.buffer.readUInt32LE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readUInt64BE(callback) {
    this.awaitData(8, () => {
      const data = Math.pow(2, 32) * this.buffer.readUInt32BE(this.position) + this.buffer.readUInt32BE(this.position + 4);
      this.position += 8;
      callback(data);
    });
  }

  readFloatLE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readFloatLE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readFloatBE(callback) {
    this.awaitData(4, () => {
      const data = this.buffer.readFloatBE(this.position);
      this.position += 4;
      callback(data);
    });
  }

  readDoubleLE(callback) {
    this.awaitData(8, () => {
      const data = this.buffer.readDoubleLE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readDoubleBE(callback) {
    this.awaitData(8, () => {
      const data = this.buffer.readDoubleBE(this.position);
      this.position += 8;
      callback(data);
    });
  }

  readUInt24LE(callback) {
    this.awaitData(3, () => {
      const low = this.buffer.readUInt16LE(this.position);
      const high = this.buffer.readUInt8(this.position + 2);

      this.position += 3;

      callback(low | (high << 16));
    });
  }

  readUInt40LE(callback) {
    this.awaitData(5, () => {
      const low = this.buffer.readUInt32LE(this.position);
      const high = this.buffer.readUInt8(this.position + 4);

      this.position += 5;

      callback((0x100000000 * high) + low);
    });
  }

  readUNumeric64LE(callback) {
    this.awaitData(8, () => {
      const low = this.buffer.readUInt32LE(this.position);
      const high = this.buffer.readUInt32LE(this.position + 4);

      this.position += 8;

      callback((0x100000000 * high) + low);
    });
  }

  readUNumeric96LE(callback) {
    this.awaitData(12, () => {
      const dword1 = this.buffer.readUInt32LE(this.position);
      const dword2 = this.buffer.readUInt32LE(this.position + 4);
      const dword3 = this.buffer.readUInt32LE(this.position + 8);

      this.position += 12;

      callback(dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3));
    });
  }

  readUNumeric128LE(callback) {
    this.awaitData(16, () => {
      const dword1 = this.buffer.readUInt32LE(this.position);
      const dword2 = this.buffer.readUInt32LE(this.position + 4);
      const dword3 = this.buffer.readUInt32LE(this.position + 8);
      const dword4 = this.buffer.readUInt32LE(this.position + 12);

      this.position += 16;

      callback(dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3) + (0x100000000 * 0x100000000 * 0x100000000 * dword4));
    });
  }

  // Variable length data

  readBuffer(length, callback) {
    this.awaitData(length, () => {
      const data = this.buffer.slice(this.position, this.position + length);
      this.position += length;
      callback(data);
    });
  }

  // Read a Unicode String (BVARCHAR)
  readBVarChar(callback) {
    this.readUInt8((length) => {
      this.readBuffer(length * 2, (data) => {
        callback(data.toString('ucs2'));
      });
    });
  }

  // Read a Unicode String (USVARCHAR)
  readUsVarChar(callback) {
    this.readUInt16LE((length) => {
      this.readBuffer(length * 2, (data) => {
        callback(data.toString('ucs2'));
      });
    });
  }

  // Read binary data (BVARBYTE)
  readBVarByte(callback) {
    this.readUInt8((length) => {
      this.readBuffer(length, callback);
    });
  }

  // Read binary data (USVARBYTE)
  readUsVarByte(callback) {
    this.readUInt16LE((length) => {
      this.readBuffer(length, callback);
    });
  }
};
<|endoftext|>


<commit_before>/*!
    Copyright (C) 2015 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: ivan@reciprocitylabs.com
    Maintained By: ivan@reciprocitylabs.com
*/
(function($) {
  var MAX_RESULTS = 20;
  $.widget(
    "ggrc.autocomplete",
    $.ui.autocomplete,
    {
      options: {
        // Ensure that the input.change event still occurs
        change: function(event, ui) {
          if (!$(event.target).parents(document.body).length)
            console.warn("autocomplete menu change event is coming from detached nodes");
          $(event.target).trigger("change");
        },

        minLength: 0,

        source: function(request, response) {
          // Search based on the term
          var query = request.term || '',
            queue = new RefreshQueue(),
            that = this,
            is_next_page = request.start != null,
            dfd;

          if (query.indexOf('@') > -1)
            query = '"' + query + '"';

          this.last_request = request;
          if (is_next_page) {
            dfd = $.when(this.last_stubs);
          } else {
            request.start = 0;
            dfd = this.options.source_for_refreshable_objects.call(this, request);
          }

          this.options.controller.bindXHRToButton(
            // Retrieve full people data

            dfd.then(function(objects) {
              that.last_stubs = objects;
              can.each(objects.slice(request.start, request.start + MAX_RESULTS), function(object) {
                queue.enqueue(object);
              });
              queue.trigger().then(function(objs) {
                objs = that.options.apply_filter.call(that, objs, request);
                if (objs.length || is_next_page) {
                  // Envelope the object to not break model instance due to
                  // shallow copy done by jQuery in `response()`
                  objs = can.map(objs, function(obj) {
                    return {
                      item: obj
                    };
                  });
                  response(objs);
                } else {
                  // show the no-results option iff no results come through here,
                  //  and not merely showing paging.
                  that._suggest([]);
                  that._trigger("open");
                }
              });
            }), $(this.element), null, false);
        },

        apply_filter: function(objects) {
          return objects;
        },

        source_for_refreshable_objects: function(request) {
          var that = this;

          if (this.options.searchlist) {
            return this.options.searchlist.then(function() {
              var filtered_list = [];
              return $.map(arguments, function(item) {
                if (!item) {
                  return;
                }
                var search_attr = item.title || "",
                  term = request.term.toLowerCase();

                // Filter out duplicates:
                if (filtered_list.indexOf(item._cid) > -1) {
                  return;
                }
                filtered_list.push(item._cid);

                // Perform search based on term:
                if (search_attr.toLowerCase().indexOf(term) === -1) {
                  return;
                }
                return item;
              });
            });
          }

          return GGRC.Models.Search
            .search_for_types(
              request.term || '',
              this.options.searchtypes,
              this.options.search_params
            )
            .then(function(search_result) {
              var objects = [];

              can.each(that.options.searchtypes, function(searchtype) {
                objects.push.apply(
                  objects, search_result.getResultsForType(searchtype));
              });
              return objects;
            });
        },

        select: function(ev, ui) {
          var original_event,
              $this = $(this),
              ctl = $this.data($this.data("autocomplete-widget-name")).options.controller;

          if (ui.item) {
            $this.trigger("autocomplete:select", [ui]);
            if (ctl.scope && ctl.scope.autocomplete_select) {
              return ctl.scope.autocomplete_select($this, ev, ui);
            } else if (ctl.autocomplete_select) {
              return ctl.autocomplete_select($this, ev, ui);
            }

          } else {
            original_event = ev;
            $(document.body).off(".autocomplete").one("modal:success.autocomplete", function(_ev, new_obj) {
              var autocomplete_select = ctl.autocomplete_select || ctl.scope.autocomplete_select;
              if (autocomplete_select) {
                autocomplete_select($this, original_event, {
                  item: new_obj
                });
              }
              $this.trigger("autocomplete:select", [{
                item: new_obj
              }]);
              $this.trigger("modal:success", new_obj);
            }).one("hidden", function() {
              setTimeout(function() {
                $(this).off(".autocomplete");
              }, 100);
            });
            while (original_event = original_event.originalEvent) {
              if (original_event.type === "keydown") {
                //This selection event was generated from a keydown, so click the add new link.
                var widget_name = el.data("autocompleteWidgetName");
                el.data(widget_name).menu.active.find("a").click();
                break;
              }
            }
            return false;
          }
        },

        close: function() {
          delete this.scroll_op_in_progress;
          //$that.val($that.attr("value"));
        }
      },

      _create: function() {
        var that = this,
          $that = $(this.element),
          base_search = $that.data("lookup"),
          from_list = $that.data("from-list"),
          search_params = $that.data("params"),
          permission = $that.data("permission-type"),
          searchtypes;

        this._super.apply(this, arguments);
        this.options.search_params = {
          extra_params: search_params
        };
        if (permission) {
          this.options.search_params.__permission_type = permission;
        }

        $that.data("autocomplete-widget-name", this.widgetFullName);

        $that.focus(function() {
          $(this).data(that.widgetFullName).search($(this).val());
        });

        if (from_list) {
          this.options.searchlist = $.when.apply(this, $.map(from_list.list, function(item) {
            var props = base_search.trim().split('.');
            return item.instance.refresh_all.apply(item.instance, props);
          }));
        } else if (base_search) {
          base_search = base_search.trim();
          if (base_search.indexOf("__mappable") === 0 || base_search.indexOf("__all") === 0) {
            searchtypes = GGRC.Mappings.get_canonical_mappings_for(
              this.options.parent_instance.constructor.shortName
            );
            if (base_search.indexOf("__mappable") === 0) {
              searchtypes = can.map(searchtypes, function(mapping) {
                return mapping instanceof GGRC.ListLoaders.ProxyListLoader ? mapping : undefined;
              });
            }
            if (base_search.indexOf("_except:")) {
              can.each(base_search.substr(base_search.indexOf("_except:") + 8).split(","), function(remove) {
                delete searchtypes[remove];
              });
            }
            searchtypes = Object.keys(searchtypes);
          } else {
            searchtypes = base_search.split(",");
          }

          this.options.searchtypes = can.map(searchtypes, function(t) {
            return CMS.Models[t].model_singular;
          });
        }
      },

      _setup_menu_context: function(items) {
        var model_class = this.element.data("lookup"),

          model = CMS.Models[model_class || this.element.data("model")]
            || GGRC.Models[model_class || this.element.data("model")]
        ;

        return {
          model_class: model_class,
          model: model,
          // Reverse the enveloping we did 25 lines up
          items: can.map(items, function(item) {
            return item.item;
          }),
        };
      },

      _renderMenu: function(ul, items) {
        var template = this.element.data("template"),
          context = new can.Observe(this._setup_menu_context(items)),
          model = context.model,
          that = this,
          $ul = $(ul)
        ;

        if (!template) {
          if (model && GGRC.Templates[model.table_plural + "/autocomplete_result"]) {
            template = '/' + model.table_plural + '/autocomplete_result.mustache';
          } else {
            template = '/base_objects/autocomplete_result.mustache';
          }
        }

        $ul.unbind("scrollNext")
          .bind("scrollNext", function(ev, data) {
            if (that.scroll_op_in_progress) {
              return;
            }
            that.scroll_op_in_progress = true;
            that.last_request = that.last_request || {};
            that.last_request.start = that.last_request.start || 0;
            that.last_request.start += MAX_RESULTS;
            context.attr("items_loading", true);
            that.source(that.last_request, function(items) {
              context.items.push.apply(context.items, can.map(items, function(item) {
                return item.item;
              }));
              context.removeAttr("items_loading");
              setTimeout(function() {
                delete that.scroll_op_in_progress;
              }, 10);
            });
          });

        can.view.render(
          GGRC.mustache_path + template,
          context,
          function(frag) {
            $ul.html(frag);
            $ul.cms_controllers_lhn_tooltips().cms_controllers_infinite_scroll();
            can.view.hookup(ul);
          });
      }
    });
  $.widget.bridge("ggrc_autocomplete", $.ggrc.autocomplete);

  $.widget("ggrc.mapping_autocomplete", $.ggrc.autocomplete, {
    options: {
      source_for_refreshable_objects: function(request) {
        var $el = $(this.element),
          mapping = this.options.controller.options;

        if (mapping.scope) {
          mapping = mapping.scope.source_mapping;
        } else {
          mapping = inst.source_mapping;
        }

        return $.when(can.map(mapping, function(binding) {
          return binding.instance;
        }));
      },
      apply_filter: function(objects, request) {
        return can.map(objects, function(object) {
          if (!request.term || object.title && ~object.title.indexOf(request.term))
            return object;
          else
            return undefined;
        });
      }
    },
    _setup_menu_context: function(items) {
      return $.extend(this._super(items), {
        mapping: this.options.mapping == null ? this.element.data("mapping") : this.options.mapping
      });
    }
  });
  $.widget.bridge("ggrc_mapping_autocomplete", $.ggrc.mapping_autocomplete);

  $.cms_autocomplete = function(el) {
    var ctl = this;
    // Add autocomplete to the owner field
    ($(el) || this.element.find('input[data-lookup]'))
      .filter("[name][name!='']")
      .ggrc_autocomplete({
        controller: ctl
      });
  };
})(jQuery);
<commit_msg>Fix uncaught script error while creating program<commit_after>/*!
    Copyright (C) 2015 Google Inc., authors, and contributors <see AUTHORS file>
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
    Created By: ivan@reciprocitylabs.com
    Maintained By: ivan@reciprocitylabs.com
*/
(function($) {
  var MAX_RESULTS = 20;
  $.widget(
    "ggrc.autocomplete",
    $.ui.autocomplete,
    {
      options: {
        // Ensure that the input.change event still occurs
        change: function(event, ui) {
          if (!$(event.target).parents(document.body).length)
            console.warn("autocomplete menu change event is coming from detached nodes");
          $(event.target).trigger("change");
        },

        minLength: 0,

        source: function(request, response) {
          // Search based on the term
          var query = request.term || '',
            queue = new RefreshQueue(),
            that = this,
            is_next_page = request.start != null,
            dfd;

          if (query.indexOf('@') > -1)
            query = '"' + query + '"';

          this.last_request = request;
          if (is_next_page) {
            dfd = $.when(this.last_stubs);
          } else {
            request.start = 0;
            dfd = this.options.source_for_refreshable_objects.call(this, request);
          }

          this.options.controller.bindXHRToButton(
            // Retrieve full people data

            dfd.then(function(objects) {
              that.last_stubs = objects;
              can.each(objects.slice(request.start, request.start + MAX_RESULTS), function(object) {
                queue.enqueue(object);
              });
              queue.trigger().then(function(objs) {
                objs = that.options.apply_filter.call(that, objs, request);
                if (objs.length || is_next_page) {
                  // Envelope the object to not break model instance due to
                  // shallow copy done by jQuery in `response()`
                  objs = can.map(objs, function(obj) {
                    return {
                      item: obj
                    };
                  });
                  response(objs);
                } else {
                  // show the no-results option iff no results come through here,
                  //  and not merely showing paging.
                  that._suggest([]);
                  that._trigger("open");
                }
              });
            }), $(this.element), null, false);
        },

        apply_filter: function(objects) {
          return objects;
        },

        source_for_refreshable_objects: function(request) {
          var that = this;

          if (this.options.searchlist) {
            return this.options.searchlist.then(function() {
              var filtered_list = [];
              return $.map(arguments, function(item) {
                if (!item) {
                  return;
                }
                var search_attr = item.title || "",
                  term = request.term.toLowerCase();

                // Filter out duplicates:
                if (filtered_list.indexOf(item._cid) > -1) {
                  return;
                }
                filtered_list.push(item._cid);

                // Perform search based on term:
                if (search_attr.toLowerCase().indexOf(term) === -1) {
                  return;
                }
                return item;
              });
            });
          }

          return GGRC.Models.Search
            .search_for_types(
              request.term || '',
              this.options.searchtypes,
              this.options.search_params
            )
            .then(function(search_result) {
              var objects = [];

              can.each(that.options.searchtypes, function(searchtype) {
                objects.push.apply(
                  objects, search_result.getResultsForType(searchtype));
              });
              return objects;
            });
        },

        select: function(ev, ui) {
          var original_event,
              $this = $(this),
              ctl = $this.data($this.data("autocomplete-widget-name")).options.controller;

          if (ui.item) {
            $this.trigger("autocomplete:select", [ui]);
            if (ctl.scope && ctl.scope.autocomplete_select) {
              return ctl.scope.autocomplete_select($this, ev, ui);
            } else if (ctl.autocomplete_select) {
              return ctl.autocomplete_select($this, ev, ui);
            }

          } else {
            original_event = ev;
            $(document.body).off(".autocomplete").one("modal:success.autocomplete", function(_ev, new_obj) {
              if (ctl.scope && ctl.scope.autocomplete_select) {
                return ctl.scope.autocomplete_select(
                  $this, original_event, {item: new_obj});
              } else if (ctl.autocomplete_select) {
                return ctl.autocomplete_select(
                  $this, original_event, {item: new_obj});
              }
              $this.trigger("autocomplete:select", [{
                item: new_obj
              }]);
              $this.trigger("modal:success", new_obj);
            }).one("hidden", function() {
              setTimeout(function() {
                $(this).off(".autocomplete");
              }, 100);
            });
            while (original_event = original_event.originalEvent) {
              if (original_event.type === "keydown") {
                //This selection event was generated from a keydown, so click the add new link.
                var widget_name = el.data("autocompleteWidgetName");
                el.data(widget_name).menu.active.find("a").click();
                break;
              }
            }
            return false;
          }
        },

        close: function() {
          delete this.scroll_op_in_progress;
          //$that.val($that.attr("value"));
        }
      },

      _create: function() {
        var that = this,
          $that = $(this.element),
          base_search = $that.data("lookup"),
          from_list = $that.data("from-list"),
          search_params = $that.data("params"),
          permission = $that.data("permission-type"),
          searchtypes;

        this._super.apply(this, arguments);
        this.options.search_params = {
          extra_params: search_params
        };
        if (permission) {
          this.options.search_params.__permission_type = permission;
        }

        $that.data("autocomplete-widget-name", this.widgetFullName);

        $that.focus(function() {
          $(this).data(that.widgetFullName).search($(this).val());
        });

        if (from_list) {
          this.options.searchlist = $.when.apply(this, $.map(from_list.list, function(item) {
            var props = base_search.trim().split('.');
            return item.instance.refresh_all.apply(item.instance, props);
          }));
        } else if (base_search) {
          base_search = base_search.trim();
          if (base_search.indexOf("__mappable") === 0 || base_search.indexOf("__all") === 0) {
            searchtypes = GGRC.Mappings.get_canonical_mappings_for(
              this.options.parent_instance.constructor.shortName
            );
            if (base_search.indexOf("__mappable") === 0) {
              searchtypes = can.map(searchtypes, function(mapping) {
                return mapping instanceof GGRC.ListLoaders.ProxyListLoader ? mapping : undefined;
              });
            }
            if (base_search.indexOf("_except:")) {
              can.each(base_search.substr(base_search.indexOf("_except:") + 8).split(","), function(remove) {
                delete searchtypes[remove];
              });
            }
            searchtypes = Object.keys(searchtypes);
          } else {
            searchtypes = base_search.split(",");
          }

          this.options.searchtypes = can.map(searchtypes, function(t) {
            return CMS.Models[t].model_singular;
          });
        }
      },

      _setup_menu_context: function(items) {
        var model_class = this.element.data("lookup"),

          model = CMS.Models[model_class || this.element.data("model")]
            || GGRC.Models[model_class || this.element.data("model")]
        ;

        return {
          model_class: model_class,
          model: model,
          // Reverse the enveloping we did 25 lines up
          items: can.map(items, function(item) {
            return item.item;
          }),
        };
      },

      _renderMenu: function(ul, items) {
        var template = this.element.data("template"),
          context = new can.Observe(this._setup_menu_context(items)),
          model = context.model,
          that = this,
          $ul = $(ul)
        ;

        if (!template) {
          if (model && GGRC.Templates[model.table_plural + "/autocomplete_result"]) {
            template = '/' + model.table_plural + '/autocomplete_result.mustache';
          } else {
            template = '/base_objects/autocomplete_result.mustache';
          }
        }

        $ul.unbind("scrollNext")
          .bind("scrollNext", function(ev, data) {
            if (that.scroll_op_in_progress) {
              return;
            }
            that.scroll_op_in_progress = true;
            that.last_request = that.last_request || {};
            that.last_request.start = that.last_request.start || 0;
            that.last_request.start += MAX_RESULTS;
            context.attr("items_loading", true);
            that.source(that.last_request, function(items) {
              context.items.push.apply(context.items, can.map(items, function(item) {
                return item.item;
              }));
              context.removeAttr("items_loading");
              setTimeout(function() {
                delete that.scroll_op_in_progress;
              }, 10);
            });
          });

        can.view.render(
          GGRC.mustache_path + template,
          context,
          function(frag) {
            $ul.html(frag);
            $ul.cms_controllers_lhn_tooltips().cms_controllers_infinite_scroll();
            can.view.hookup(ul);
          });
      }
    });
  $.widget.bridge("ggrc_autocomplete", $.ggrc.autocomplete);

  $.widget("ggrc.mapping_autocomplete", $.ggrc.autocomplete, {
    options: {
      source_for_refreshable_objects: function(request) {
        var $el = $(this.element),
          mapping = this.options.controller.options;

        if (mapping.scope) {
          mapping = mapping.scope.source_mapping;
        } else {
          mapping = inst.source_mapping;
        }

        return $.when(can.map(mapping, function(binding) {
          return binding.instance;
        }));
      },
      apply_filter: function(objects, request) {
        return can.map(objects, function(object) {
          if (!request.term || object.title && ~object.title.indexOf(request.term))
            return object;
          else
            return undefined;
        });
      }
    },
    _setup_menu_context: function(items) {
      return $.extend(this._super(items), {
        mapping: this.options.mapping == null ? this.element.data("mapping") : this.options.mapping
      });
    }
  });
  $.widget.bridge("ggrc_mapping_autocomplete", $.ggrc.mapping_autocomplete);

  $.cms_autocomplete = function(el) {
    var ctl = this;
    // Add autocomplete to the owner field
    ($(el) || this.element.find('input[data-lookup]'))
      .filter("[name][name!='']")
      .ggrc_autocomplete({
        controller: ctl
      });
  };
})(jQuery);
<|endoftext|>